From 0fe44a04fbe263ffb64102c60f17cf8342744548 Mon Sep 17 00:00:00 2001 From: J Logan Date: Wed, 24 Sep 2025 13:57:34 -0700 Subject: [PATCH] Adds a plain stderr log handler. (#680) - Initial work for #642. CLI commands will configure this log handler so that they write warnings and errors to stderr, and only proper output will go to stdout. - Facilitates #507. The `--debug` option can set the logging level appropriately, and CLI commands can just use `log.debug()`. ## Type of Change - [ ] Bug fix - [x] New feature - [ ] Breaking change - [ ] Documentation update --- Sources/ContainerLog/StderrLogHandler.swift | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Sources/ContainerLog/StderrLogHandler.swift diff --git a/Sources/ContainerLog/StderrLogHandler.swift b/Sources/ContainerLog/StderrLogHandler.swift new file mode 100644 index 00000000..28d5fcab --- /dev/null +++ b/Sources/ContainerLog/StderrLogHandler.swift @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// Copyright © 2025 Apple Inc. and the container project authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//===----------------------------------------------------------------------===// + +// + +import Foundation +import Logging + +/// Basic log handler for where simple message output is needed, +/// such as CLI commands. +public struct StderrLogHandler: LogHandler { + public var logLevel: Logger.Level = .info + public var metadata: Logger.Metadata = [:] + + public subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? { + get { + self.metadata[metadataKey] + } + set { + self.metadata[metadataKey] = newValue + } + } + + public init() {} + + public func log( + level: Logger.Level, + message: Logger.Message, + metadata: Logger.Metadata?, + source: String, + file: String, + function: String, + line: UInt + ) { + let messageText = message.description + let data = messageText.data(using: .utf8) ?? Data() + + // Use a single write call for atomicity + var output = data + output.append("\n".data(using: .utf8)!) + FileHandle.standardError.write(output) + } +}