From e98a4aa88a87717f9063bd14642a7faf6d475446 Mon Sep 17 00:00:00 2001 From: Gabbi Fisher Date: Fri, 13 Sep 2024 10:50:44 -0700 Subject: [PATCH] Add withMetadata() convenience function for adding multiple metadata k/v pairs to a Logger --- Sources/Logging/Logging.swift | 11 +++++++++++ Tests/LoggingTests/LoggingTest.swift | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Sources/Logging/Logging.swift b/Sources/Logging/Logging.swift index 04ef0b1a..9bd6e082 100644 --- a/Sources/Logging/Logging.swift +++ b/Sources/Logging/Logging.swift @@ -166,6 +166,17 @@ extension Logger { } } + /// Convenience function for adding multiple metadata items to a logger. + /// + /// - note: Logging metadata behaves as a value that means a change to the logging metadata will only affect the + /// very `Logger` it was changed on. + @inlinable + public mutating func withMetadata(metadata: Logger.Metadata) { + metadata.forEach { (key, value) in + self.handler[metadataKey: key] = value + } + } + /// Get or set the log level configured for this `Logger`. /// /// - note: `Logger`s treat `logLevel` as a value. This means that a change in `logLevel` will only affect this diff --git a/Tests/LoggingTests/LoggingTest.swift b/Tests/LoggingTests/LoggingTest.swift index f77b9dfe..d54d5c48 100644 --- a/Tests/LoggingTests/LoggingTest.swift +++ b/Tests/LoggingTests/LoggingTest.swift @@ -357,6 +357,25 @@ class LoggingTest: XCTestCase { "nested-list": ["l1str", ["l2str1", "l2str2"]]]) } + func testWithMetadata() { + let testLogging = TestLogging() + LoggingSystem.bootstrapInternal { testLogging.make(label: $0) } + + var logger = Logger(label: "\(#function)") + let metadata: Logger.Metadata = [ + "foo": ["bar", "buz"], + "empty-list": [], + "nested-list": ["l1str", ["l2str1", "l2str2"]], + ] + logger.withMetadata(metadata: metadata) + logger.info("hello world!") + testLogging.history.assertExist(level: .info, + message: "hello world!", + metadata: ["foo": ["bar", "buz"], + "empty-list": [], + "nested-list": ["l1str", ["l2str1", "l2str2"]]]) + } + // Example of custom "box" which may be used to implement "render at most once" semantics // Not thread-safe, thus should not be shared across threads. internal final class LazyMetadataBox: CustomStringConvertible {