Claude Skill

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

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download wei18-apple-dev-skills-apple-dev-skills_skills_oslog-logger-defaults-7ea7e61.zip · 2 KB
Part of wei18/apple-dev-skills — 37 skills

Install

skills CLI npx skills add https://github.com/wei18/apple-dev-skills/tree/main/apple-dev-skills/skills/oslog-logger-defaults
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wei18-apple-dev-skills@llmmart
Git 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 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.
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.
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.

No comments yet.

Reviews (0)

No reviews yet.

Related