Output metadata as JSON
Metadata shall be machine readable (see SwiftLog/Structured Logging) and the previous metadata serialization erased the nesting structure. The JSON output ensures that the metadata can be quickly analyzed by either a copy and paste into a JSON editor or a small CLI pipeline. See https://swiftpackageindex.com/apple/swift-log/1.10.1/documentation/logging/002-structuredlogging for more information on metadata.
This commit is contained in:
41
Sources/Logging OSLog/Logger Metadata Extension.swift
Normal file
41
Sources/Logging OSLog/Logger Metadata Extension.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
import Logging
|
||||
|
||||
extension Logging.Logger.Metadata {
|
||||
public func asJSON() -> String {
|
||||
return Self.asJSON(self)
|
||||
}
|
||||
|
||||
private static func asJSON(_ metadata: Logging.Logger.Metadata) -> String {
|
||||
var outputParts: [String: String] = [:]
|
||||
for (key, value) in metadata {
|
||||
let jsonKey = Self.escapeForJSON(key)
|
||||
outputParts[jsonKey] = Self.asJSON(value)
|
||||
}
|
||||
return "{" + outputParts.map { "\"\($0)\": \($1)" }.joined(separator: ", ") + "}"
|
||||
}
|
||||
|
||||
private static func asJSON(_ metadata: [Logging.Logger.MetadataValue]) -> String {
|
||||
var outputParts: [String] = []
|
||||
for item in metadata {
|
||||
outputParts.append(Self.asJSON(item))
|
||||
}
|
||||
return "[" + outputParts.joined(separator: ", ") + "]"
|
||||
}
|
||||
|
||||
private static func asJSON(_ metadata: Logging.Logger.MetadataValue) -> String {
|
||||
switch metadata {
|
||||
case .dictionary(let subvalues):
|
||||
return Self.asJSON(subvalues)
|
||||
case .array(let subvalues):
|
||||
return Self.asJSON(subvalues)
|
||||
case .string(let subvalue):
|
||||
return "\"" + Self.escapeForJSON(subvalue) + "\""
|
||||
case .stringConvertible(let subvalue):
|
||||
return "\"" + Self.escapeForJSON("\(subvalue)") + "\""
|
||||
}
|
||||
}
|
||||
|
||||
private static func escapeForJSON(_ data: String) -> String {
|
||||
return data.replacingOccurrences(of: "\"", with: "\\\"")
|
||||
}
|
||||
}
|
||||
@@ -103,11 +103,6 @@ public struct LoggingOSLog: LogHandler {
|
||||
guard let metadata = metadata else { continue }
|
||||
metadataAggregator.merge(metadata) { return $1 }
|
||||
}
|
||||
return Self.joinedMetadata(metadataAggregator)
|
||||
}
|
||||
|
||||
private static func joinedMetadata(_ metadata: Logging.Logger.Metadata, with separator: String = ", ") -> String? {
|
||||
guard !metadata.isEmpty else { return nil }
|
||||
return metadata.map { "\"\($0)\": \"\($1)\"" }.joined(separator: separator)
|
||||
return metadataAggregator.asJSON()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,16 @@ import LoggingOSLog
|
||||
@Test func canLogMessage() {
|
||||
let logger = Logging.Logger(label: "de.astzweig.loggingoslog.Test")
|
||||
logger.info("Test message")
|
||||
}
|
||||
}
|
||||
|
||||
@Test func canLogMessageWithMetadata() {
|
||||
let logger = Logging.Logger(label: "de.astzweig.loggingoslog.Test")
|
||||
logger.info("Test message", metadata: [
|
||||
"request.id": "20140801",
|
||||
"request.dirname": "\"Impossible\"",
|
||||
"request.authorization": [
|
||||
"bearer": "empty"
|
||||
],
|
||||
"request.values": ["1", "rootID", ["key": "value"]]
|
||||
])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user