-
Notifications
You must be signed in to change notification settings - Fork 24
feat: create new logger API - WPB-14297 #3849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: chore/rename-wirelogging-to-wirelegacylogging-WPB-14876
Are you sure you want to change the base?
feat: create new logger API - WPB-14297 #3849
Conversation
Test Results1 902 tests 1 875 ✅ 2m 16s ⏱️ Results for commit a52d55e. ♻️ This comment has been updated with latest results. |
…' into feat/create-new-logger-WPB-14297
…' into feat/create-new-logger-WPB-14297
…' into feat/create-new-logger-WPB-14297
…' into feat/create-new-logger-WPB-14297
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new type-safe logging API (WireLogging) that prevents accidental logging of sensitive data by restricting automatic string interpolation to StaticString values only. The design forces developers to explicitly define how custom types are converted to log messages through WireLogInterpolation extensions.
Key changes:
- New logging infrastructure with
WireLogMessage,WireLogInterpolation, andWireLogAttributefor structured, secure logging WireTaggedLoggerand protocol-based API with log level methods (debug, info, notice, warn, error, critical)OSLogHandlerimplementation with logger caching and tag-based categorization
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| WireLogInterpolationTests.swift | Basic tests for static string interpolation |
| sourcery.yml | Configuration update to import WireLogging in generated mocks |
| AutoMockable.manual.swift | Manual mock for WireTaggedLoggerProtocol |
| WireTaggedLoggerProtocol.swift | Protocol defining tagged logger interface |
| WireTaggedLogger.swift | Tagged logger implementation with log level methods |
| WireLogger+Singletons.swift | Static logger instances initialized with shared handler |
| WireLogType.swift | Enum defining log levels (renamed from WireLogLevel) |
| WireLogTag.swift | String-based tag type for categorizing logs |
| WireLogMessage.swift | Log message type supporting custom interpolation |
| WireLogInterpolation.swift | Custom string interpolation restricting to StaticString by default |
| WireLogAttribute.swift | Key-value pair for structured log metadata |
| WireLogAttribute+predefined.swift | Predefined attribute helpers |
| WireLogHandlerProtocol.swift | Protocol for log handlers |
| OSLogHandler.swift | os.Logger-based handler with caching |
| Documentation.md | Comprehensive documentation for the logging API |
| WireLogger+Instances.swift | Minor formatting change in legacy logger |
| Package.swift | Added WireLogging dependency to WireLegacyLogging |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| func logger(for tag: WireLogTag) -> Logger { | ||
| // Synchronously get or create logger and update access time | ||
| let logger = queue.sync { |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every log call triggers an async eviction task (line 107-109), which creates many unnecessary async dispatches. Consider adding a throttling mechanism (e.g., only evict every N calls or after a time interval) or moving eviction to a background timer to reduce overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I can replace it with locking.
| queue.async { | ||
| self.evictStaleEntries() | ||
| } |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every log call triggers an async eviction task (line 107-109), which creates many unnecessary async dispatches. Consider adding a throttling mechanism (e.g., only evict every N calls or after a time interval) or moving eviction to a background timer to reduce overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A valid point, I'll think about it.
| var attributesString = "" | ||
| for attributesKey in attributes.keys.sorted() { | ||
| attributesString += "[\(attributesKey)=\(attributes[attributesKey]!)]" | ||
| } | ||
|
|
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String concatenation in a loop (line 46) creates multiple intermediate String objects. Use a String builder pattern or join the array for better performance, especially when many attributes are present.
| var attributesString = "" | |
| for attributesKey in attributes.keys.sorted() { | |
| attributesString += "[\(attributesKey)=\(attributes[attributesKey]!)]" | |
| } | |
| let attributesString = attributes.keys.sorted() | |
| .map { "[\($0)=\(attributes[$0]!)]" } | |
| .joined() |
| @Test | ||
| func staticStringIsNotObfuscated() async throws { |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new logging infrastructure lacks comprehensive test coverage. Missing tests include: WireLogAttribute handling, OSLogHandler behavior, logger caching in OSLogHandler, WireTaggedLogger methods, and the setup/singleton pattern in WireLogger. Consider adding tests for these critical components.
| @Test | ||
| func staticStringInterpolationIsNotObfuscated() async throws { |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new logging infrastructure lacks comprehensive test coverage. Missing tests include: WireLogAttribute handling, OSLogHandler behavior, logger caching in OSLogHandler, WireTaggedLogger methods, and the setup/singleton pattern in WireLogger. Consider adding tests for these critical components.
|
|
||
| public static let analytics = WireTaggedLogger(tag: "analytics", handler: logHandler) | ||
| public static let apiMigration = WireTaggedLogger(tag: "api-migration", handler: logHandler) | ||
| public static let appVersionMigration = WireTaggedLogger(tag: "api-version-migration", handler: logHandler) |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tag "api-version-migration" does not match the logger name appVersionMigration. This inconsistency could cause confusion. Consider renaming the tag to "app-version-migration" for consistency.
| public static let appVersionMigration = WireTaggedLogger(tag: "api-version-migration", handler: logHandler) | |
| public static let appVersionMigration = WireTaggedLogger(tag: "app-version-migration", handler: logHandler) |
| /// ``` | ||
|
|
||
| public mutating func writeAttribute(_ attribute: WireLogAttribute) { | ||
| attributes += [attribute] |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using += with a single-element array creates unnecessary array allocations. Use attributes.append(attribute) for better performance.
| attributes += [attribute] | |
| attributes.append(attribute) |
netbe
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left a couple of questions before approving
| @@ -0,0 +1,86 @@ | |||
| # ``WireLogging`` | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: really clear documentation 🙏
| /// This method must be called very early on app start, before any other interaction with ``WireLogger``. | ||
|
|
||
| public static func setup(_ logHandler: any WireLogHandlerProtocol) { | ||
| precondition(Thread.isMainThread) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: why is this check necessary?
| public static func setup(_ logHandler: any WireLogHandlerProtocol) { | ||
| precondition(Thread.isMainThread) | ||
| guard self.logHandler == nil else { | ||
| fatalError("WireLogger is already set up") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: should we just return ? or be assertionFailure?
| // | ||
|
|
||
| import Foundation | ||
| import os |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: So this is only the osLog implementation given by Apple right? What about Cocoalumberjack (to write to filesystem)?
Issue
This is the second PR in a series,
This PR creates a new interface for logging, which forces calling code to explicitly specify how types are converted to a string.
Checklist
[WPB-XXX].UI accessibility checklist
If your PR includes UI changes, please utilize this checklist: