Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e18692fd4d | ||
|
|
b48562c2b0 | ||
|
|
d22556d04e | ||
|
|
e3f2ba03ef | ||
|
|
e957caf031 | ||
|
|
48fdc144c1 |
2
.spi.yml
2
.spi.yml
@@ -1,4 +1,4 @@
|
|||||||
version: 1
|
version: 1
|
||||||
builder:
|
builder:
|
||||||
configs:
|
configs:
|
||||||
- documentation_targets: [LoggingOSLog]
|
- documentation_targets: [LoggingOSLog]
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ func init() {
|
|||||||
"main": Logger(label: "com.example.yourapp.Main"),
|
"main": Logger(label: "com.example.yourapp.Main"),
|
||||||
"mail": Logger(label: "com.example.yourapp.Mail System"),
|
"mail": Logger(label: "com.example.yourapp.Mail System"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// And using loggers
|
||||||
|
logger["main"]!.debug("Starting build",
|
||||||
|
metadata: [
|
||||||
|
"input.output_directory": "\(output)",
|
||||||
|
"input.data": "\(data ?? "-")"
|
||||||
|
])
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -78,6 +85,14 @@ library maps a reverse domain style label to the subsystem and category
|
|||||||
parameters of the unified logging system. See
|
parameters of the unified logging system. See
|
||||||
``/LoggingOSLog/LoggingOSLog/init(label:)`` for more information.
|
``/LoggingOSLog/LoggingOSLog/init(label:)`` for more information.
|
||||||
|
|
||||||
|
Metadata is appended as JSON to the logged message after a simple unicode right
|
||||||
|
arrow ("→").
|
||||||
|
|
||||||
|
### What this library does not supply
|
||||||
|
This library does not implement any of the interpolation privacy features of
|
||||||
|
the unified logging system, i.e. there is no way to redact or align a meta
|
||||||
|
information, like the `Logging` API would allow.
|
||||||
|
|
||||||
[subsystem]: https://developer.apple.com/documentation/os/generating-log-messages-from-your-code#:~:text=The%20subsystem%20string,for%20each%20subsystem%20string.
|
[subsystem]: https://developer.apple.com/documentation/os/generating-log-messages-from-your-code#:~:text=The%20subsystem%20string,for%20each%20subsystem%20string.
|
||||||
[category]: https://developer.apple.com/documentation/os/generating-log-messages-from-your-code#:~:text=The%20category%20string,for%20these%20strings.
|
[category]: https://developer.apple.com/documentation/os/generating-log-messages-from-your-code#:~:text=The%20category%20string,for%20these%20strings.
|
||||||
|
|
||||||
|
|||||||
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: "\\\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,11 +78,11 @@ public struct LoggingOSLog: LogHandler {
|
|||||||
function: String,
|
function: String,
|
||||||
line: UInt
|
line: UInt
|
||||||
) {
|
) {
|
||||||
let metadataCSV = Self.joinMetadata(self.metadata, self.metadataProvider?.get(), metadata)
|
let metadataCSV = Self.joinedMetadata(self.metadata, self.metadataProvider?.get(), metadata)
|
||||||
let messageParts = [message.description, metadataCSV]
|
let messageParts = [message.description, metadataCSV]
|
||||||
|
|
||||||
let message = messageParts.compactMap { $0 }.joined(separator: " -> ")
|
let message = messageParts.compactMap { $0 }.joined(separator: " → ")
|
||||||
self.oslogger.log(level: OSLogType.from(loggerLevel: level), "\(message)")
|
self.oslogger.log(level: OSLogType.from(loggerLevel: level), "\(message, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,17 +97,12 @@ public struct LoggingOSLog: LogHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func joinMetadata(_ metadataList: Logging.Logger.Metadata?...) -> String? {
|
private static func joinedMetadata(_ metadataList: Logging.Logger.Metadata?...) -> String? {
|
||||||
var metadataAggregator: Logging.Logger.Metadata = [:]
|
var metadataAggregator: Logging.Logger.Metadata = [:]
|
||||||
for metadata in metadataList {
|
for metadata in metadataList {
|
||||||
guard let metadata = metadata else { continue }
|
guard let metadata = metadata else { continue }
|
||||||
metadataAggregator.merge(metadata) { return $1 }
|
metadataAggregator.merge(metadata) { return $1 }
|
||||||
}
|
}
|
||||||
return Self.joinMetadata(metadataAggregator)
|
return metadataAggregator.asJSON()
|
||||||
}
|
|
||||||
|
|
||||||
private static func joinMetadata(_ metadata: Logging.Logger.Metadata, with separator: String = ", ") -> String? {
|
|
||||||
guard !metadata.isEmpty else { return nil }
|
|
||||||
return metadata.map { "\($0) = \($1)" }.joined(separator: separator)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,16 @@ import LoggingOSLog
|
|||||||
@Test func canLogMessage() {
|
@Test func canLogMessage() {
|
||||||
let logger = Logging.Logger(label: "de.astzweig.loggingoslog.Test")
|
let logger = Logging.Logger(label: "de.astzweig.loggingoslog.Test")
|
||||||
logger.info("Test message")
|
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