Add SwiftLog LogHandler conformance to DiagnosticsLogger (#150) - #212
Add SwiftLog LogHandler conformance to DiagnosticsLogger (#150)#212elio-Wang wants to merge 5 commits into
Conversation
Allow DiagnosticsLogger to be used as a backing store for SwiftLog's LoggingSystem by providing a DiagnosticsLogger.SwiftLogHandler type. Projects already using SwiftLog can now seamlessly forward all log messages into the Diagnostics report. - Add swift-log as a package dependency - Make DiagnosticsLogger.init() and .standard public - Add setup(_:) overload accepting a custom logger instance - Add DiagnosticsLogger.SwiftLogHandler nested LogHandler type - Map SwiftLog levels to Diagnostics debug/error CSS classes - Add unit tests for the SwiftLog integration Resolves AvdLee#150
|
The latest version of SwiftLog added task local logger and some other improvements, not to mention all the chances in between. 1.6.0 is quite old. Any reason to not push the dependency to a more recent version? |
| /// | debug | debug | | ||
| /// | info | debug | | ||
| /// | notice | debug | | ||
| /// | warning | debug | |
There was a problem hiding this comment.
Warning might be more suitable as error. Though my next request if the library will be more diagnostic logger levels.
My rule of thumb, use warning for errors that are known, mitigated, and recoverable. They're still something to have observability into.
There was a problem hiding this comment.
Agreed — I've updated the mapping so warning now routes to .error. The default is strict; developers can override via logLevel if they need a more lenient routing.
Regarding more granular diagnostic logger levels, I've put together a proposal in the comment below. Let me know if the direction works and I'll implement it.
| public init( | ||
| label: String, | ||
| logger: DiagnosticsLogger = .standard, | ||
| logLevel: Logger.Level = .debug, |
There was a problem hiding this comment.
Default should be the more strict level. If there were intermediate options I would have it be info. Debug logs typically don't belong in production.
Allow a developer to override but default on hardening the output.
There was a problem hiding this comment.
Done. Changes:
Default logLevel bumped from .debug to .info — debug/trace won't show in production by default
Added a levelMapping closure parameter so developers can override the default mapping if needed
The default mapping keeps trace/debug → Diagnostics debug, and everything else → error.
| logger.log( | ||
| LogItem(.debug(message: fullMessage), file: file, function: function, line: line) | ||
| ) | ||
| case .error, .critical: |
There was a problem hiding this comment.
Thoughts on enhancing the diagnostic logger api with more levels to facilitate more granularity?
There was a problem hiding this comment.
I'm happy to receive that, yeah! The better we can support it, the better!
There was a problem hiding this comment.
Do you want to support all levels of SwiftLog, OpenTelemetry, or a subset of both? It would be expanding the usage of the diagnostic logger quite a bit.
My preference would be to match SwiftLog, or a subset of it since that is what support is being added for.
https://github.com/apple/swift-log/blob/main/Sources/Logging/Logger.swift#L1187
Or
https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord
https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber
https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext
There was a problem hiding this comment.
I'd go with matching SwiftLog's levels. It's the most natural fit since that's what we're bridging, and SwiftLog is already widely adopted in the Swift ecosystem. OpenTelemetry's 24-level SeverityNumber feels like overkill for a diagnostics log file.
For the mapping, I'd suggest:
| SwiftLog Level | Diagnostics Level |
|---|---|
| trace | trace |
| debug | debug |
| info | info |
| notice | info |
| warning | warning |
| error | error |
| critical | error |
This gives us 5 levels in DiagnosticsLogger (trace, debug, info, warning, error) — enough granularity for production diagnostics without being excessive. notice collapsing into info and critical into error keeps it pragmatic.
Happy to implement this if the direction looks right.
@edorphy @AvdLee
|
|
||
| public init() { } | ||
|
|
||
| private static let logFileLocation: URL = FileManager.default.applicationSupportDirectory.appendingPathComponent("diagnostics_log.txt") |
There was a problem hiding this comment.
When I was looking at contributing to this issue, I wanted to also control the destination of the log file.
Maybe out of scope of this merge, but a tradeoff to giving a static default logger without being able to control the destination.
I would find it useful to inject the destination.
There was a problem hiding this comment.
@edorphy Regarding #195 and the ability to inject a custom log file destination — I looked at the code and logFileLocation is currently a hardcoded static let. My approach would be:
Convert it to an instance property, injectable via init(logFileLocation:)
Fall back to the default path when not provided, keeping backward compatibility
This is a different scope from the SwiftLog bridge in this PR, so I can open a separate PR for it. Would you prefer to have it bundled here or kept as a standalone PR?
No specific reason — I conservatively picked 1.6.0 as the minimum since that's the version I had locally when developing the handler. Happy to bump it. Would you prefer pinning to the latest (≥ 1.14.0), or something in between like ≥ 1.6.0 with a note? Let me know and I'll push the update. |
Address review feedback: 1.6.0 was outdated. No API changes needed — the SwiftLogHandler implementation only uses stable LogHandler APIs available since 1.6.0, so this is a minimum version bump only.
Per maintainer feedback, warning represents errors that are known, mitigated, and recoverable — they warrant error-level observability rather than being grouped with debug output. The default mapping now favors strictness; developers can override via the logLevel parameter if they prefer a more lenient routing.
- Default logLevel changed from .debug to .info so debug/trace logs are excluded from production output by default - Add LevelMapping closure parameter to SwiftLogHandler.init, allowing developers to override how SwiftLog levels map to Diagnostics output (debug vs error)
swift-log 1.15.0 makes StreamLogHandler initializers public and includes minor fixes. Keep the dependency current with the latest release.
What
Adds
DiagnosticsLogger.SwiftLogHandler, aLogHandlerconformance for apple/swift-log, so projects already using SwiftLog can bridge their logs into the Diagnostics report with a single bootstrap call:Resolves #150.
Changes
Notes
@unchecked Sendablematches swift-log's ownStreamLogHandlerpattern —metadata/logLevelare set at bootstrap, not mutated across threads.debuglevels, so the mapping groups the lower SwiftLog levels intodebug. Can be revisited if more levels are added later.