oslog-logger-defaults
Set up logging for an Apple-platform Swift app with `os.Logger` and decide its `subsystem` / `category` naming and `privacy:` interpolation. Use when choosing a logging library (`os.Logger` vs swift-log `import Logging` vs CocoaLumberjack); when writing the first `Logger(subsyste
Install
npx skills add https://github.com/wei18/apple-dev-skills/tree/main/apple-dev-skills/skills/oslog-logger-defaults
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wei18-apple-dev-skills@llmmart
git clone https://github.com/wei18/apple-dev-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wei18/apple-dev-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
OSLog / os.Logger Defaults
When to invoke
- Starting a new Apple-platform project and picking a logging library.
- Writing the first
Loggerdeclaration. - Deciding the default for privacy interpolation.
- User asks "OSLog vs SwiftLog vs CocoaLumberjack", "
.privatevs.publichow to pick".
Default decisions
- Use Apple's built-in
os.Logger(import os); do not pull in any third-party logging library. - Naming conventions:
subsystem= bundle ID (e.g.com.example.myapp)category= module name (aligned with the SwiftPM target name)
- Privacy interpolation is type-dependent, not "all private": dynamic strings and complex objects default to
.private; integer, floating-point, and Boolean values default to.public. Any identifying numeric value (player ID, user ID, serial number) must be marked.privateexplicitly.
import os
extension Logger {
static let engine = Logger(subsystem: "com.example.myapp", category: "Engine")
}
Logger.engine.info("user \(userId, privacy: .public) loaded puzzle \(puzzleId, privacy: .private)")
// ^^^^^^^ explicit public ^^^^^^^ explicit private —
// identifying values need this
// even when the type (Int, Bool)
// would otherwise default public
Rationale
- Native integration with Console.app / Instruments / the unified logging system; zero dependencies.
- Friendly to Swift 6 actor / Sendable.
- Native privacy interpolation;
.privatevalues are redacted whenever no debugger is attached (see "What.privateactually means" below). - No third-party SDK pulled in → no extra entries in
PrivacyInfo.xcprivacy, consistent with the "no third-party tracking" stance.
What .private actually means (easily misunderstood)
Practice observed — none of the four official pages in references/official-docs.md state the debugger-attached or OSLogStore behavior below; this is derived from testing, not documented.
.privatecontent is redacted wherever no debugger is attached — this includes a TestFlight user viewing their own Console.app, not only "in someone else's sysdiagnose after release."- When the local Xcode debugger is attached to a running process, private values are still visible.
OSLogStoredoes not bypass redaction: in a TestFlight or production build,OSLogStorereading its own process still sees<private>in place of redacted values — only a process that Xcode itself launched gets unredacted output..privateis redaction, not encryption; never log raw PII even under.private.
Deviation considerations
- Cross-platform shared logger interface (Linux / Android target): use
swift-log(apple/swift-log) as a facade; on Apple platforms, back it with a third-party OSLog handler package (apple/swift-log's own distribution ships no OSLog backend) so the interface stays platform-neutral. - Need remote log aggregation: pair with
telemetry-facade-pattern's fan-out sink rather than replacing OSLog directly. - A third-party crash reporter requires its own logger: usually avoidable; if not, keep its use scoped to that SDK.
Verification checklist
- No
import Logging/import CocoaLumberjack/import Sentryor other third-party logging. - Each module has its own
Loggerextension with a category aligned to the module name. - Every
.publicannotation can be explained as non-privacy-violating (e.g. non-PII, build hash). - PII / player IDs / tokens are always
.private(or not logged at all).
Related skills
telemetry-facade-pattern: whereOSLogSinksits within the facade.apple-three-piece-analytics: OSLog is an Apple-only path, in the same "no third-party" stance as ASC / MetricKit / GC.apple-public-repo-security:.privatecorresponds to sysdiagnose redaction, but is still visible under a debugger — the safety reasoning for the public repo relies on this semantics.ios-performance-engineering:OSSignposter/os_signpostintervals and Instruments profiling; this skill stops atLogger.- Official sources: when verifying or updating a factual or version-sensitive claim, read
references/official-docs.md.
Files (apple-dev-skills)
-
references
-
official-docs.md 1.2 KB
Official pages backing this skill's claims; read when verifying or updating a factual or version-sensitive claim. | Page | URL | Backs | |---|---|---| | Logger | https://developer.apple.com/documentation/os/logger | `Logger(subsystem:category:)` | | Generating Log Messages from Your Code | https://developer.apple.com/documentation/os/generating-log-messages-from-your-code | Integer/float/Bool values aren't redacted; dynamic strings and complex dynamic objects are; use reverse-DNS notation for the subsystem string | | OSLogPrivacy | https://developer.apple.com/documentation/os/oslogprivacy | `.private` / `.public` / `.sensitive` / `private(mask:)` | | Viewing Log Messages | https://developer.apple.com/documentation/os/viewing-log-messages | Xcode's debugger shows log output automatically when attached (doesn't state that `.private` gets unmasked) | | OSLogStore | https://developer.apple.com/documentation/oslog/oslogstore | Only confirms the API exists -- the "doesn't bypass redaction" / "debugger shows `.private`" claims are not written on any official page; treat as a practice observation | | apple/swift-log | https://github.com/apple/swift-log | "SwiftLog is an API package" with community-maintained backends |
-
-
SKILL.md 4.9 KB
--- name: oslog-logger-defaults description: Set up logging for an Apple-platform Swift app with `os.Logger` and decide its `subsystem` / `category` naming and `privacy:` interpolation. Use when choosing a logging library (`os.Logger` vs swift-log `import Logging` vs CocoaLumberjack); when writing the first `Logger(subsystem:category:)`; when deciding `.private` vs `.public` for a value; when asked what `.private` hides in Console.app, sysdiagnose, or `OSLogStore`. Does NOT cover `os_signpost` / Instruments profiling (ios-performance-engineering) or fanning logs out to trackers (telemetry-facade-pattern). --- # OSLog / `os.Logger` Defaults ## When to invoke - Starting a new Apple-platform project and picking a logging library. - Writing the first `Logger` declaration. - Deciding the default for privacy interpolation. - User asks "OSLog vs SwiftLog vs CocoaLumberjack", "`.private` vs `.public` how to pick". ## Default decisions - **Use Apple's built-in `os.Logger`** (`import os`); **do not pull in any third-party logging library**. - Naming conventions: - `subsystem` = bundle ID (e.g. `com.example.myapp`) - `category` = module name (aligned with the SwiftPM target name) - **Privacy interpolation is type-dependent, not "all private"**: dynamic strings and complex objects default to `.private`; integer, floating-point, and Boolean values default to `.public`. Any identifying numeric value (player ID, user ID, serial number) must be marked `.private` explicitly. ```swift import os extension Logger { static let engine = Logger(subsystem: "com.example.myapp", category: "Engine") } Logger.engine.info("user \(userId, privacy: .public) loaded puzzle \(puzzleId, privacy: .private)") // ^^^^^^^ explicit public ^^^^^^^ explicit private — // identifying values need this // even when the type (Int, Bool) // would otherwise default public ``` ## Rationale - Native integration with Console.app / Instruments / the unified logging system; zero dependencies. - Friendly to Swift 6 actor / Sendable. - Native privacy interpolation; `.private` values are redacted whenever no debugger is attached (see "What `.private` actually means" below). - No third-party SDK pulled in → no extra entries in `PrivacyInfo.xcprivacy`, consistent with the "no third-party tracking" stance. ### What `.private` actually means (easily misunderstood) *Practice observed — none of the four official pages in `references/official-docs.md` state the debugger-attached or `OSLogStore` behavior below; this is derived from testing, not documented.* - `.private` content is **redacted wherever no debugger is attached** — this includes a TestFlight user viewing their own Console.app, not only "in someone else's sysdiagnose after release." - **When the local Xcode debugger is attached to a running process, private values are still visible.** - **`OSLogStore` does not bypass redaction**: in a TestFlight or production build, `OSLogStore` reading its own process still sees `<private>` in place of redacted values — only a process that Xcode itself launched gets unredacted output. `.private` is redaction, not encryption; never log raw PII even under `.private`. ## Deviation considerations - **Cross-platform shared logger interface** (Linux / Android target): use `swift-log` (`apple/swift-log`) as a facade; on Apple platforms, back it with a third-party OSLog handler package (apple/swift-log's own distribution ships no OSLog backend) so the interface stays platform-neutral. - **Need remote log aggregation**: pair with `telemetry-facade-pattern`'s fan-out sink rather than replacing OSLog directly. - **A third-party crash reporter requires its own logger**: usually avoidable; if not, keep its use scoped to that SDK. ## Verification checklist - No `import Logging` / `import CocoaLumberjack` / `import Sentry` or other third-party logging. - Each module has its own `Logger` extension with a category aligned to the module name. - Every `.public` annotation can be explained as non-privacy-violating (e.g. non-PII, build hash). - PII / player IDs / tokens are always `.private` (or not logged at all). ## Related skills - `telemetry-facade-pattern`: where `OSLogSink` sits within the facade. - `apple-three-piece-analytics`: OSLog is an Apple-only path, in the same "no third-party" stance as ASC / MetricKit / GC. - `apple-public-repo-security`: `.private` corresponds to sysdiagnose redaction, but is still visible under a debugger — the safety reasoning for the public repo relies on this semantics. - `ios-performance-engineering`: `OSSignposter` / `os_signpost` intervals and Instruments profiling; this skill stops at `Logger`. - Official sources: when verifying or updating a factual or version-sensitive claim, read `references/official-docs.md`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.