agentsclimarketplace

Log levels and hygiene

Skill almasumdev/awesome-mobile-observability-agent-skills/.github/skills/logs/log-levels-and-hygiene

Agent skills for logging, metrics, tracing, crash reporting, and analytics in mobile apps.

Install
npx -y skills add almasumdev/awesome-mobile-observability-agent-skills --skill log-levels-and-hygiene

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Rules for choosing log levels, keeping signal/noise healthy, managing on-device log retention, and avoiding logger abuse on mobile. Use whenever adding or reviewing log statements.

SKILL.md

6.0 KB, as published. Nobody here has run it

Log Levels and Hygiene

Instructions

Mobile loggers double as crash breadcrumbs, support artifacts, and product telemetry. Without discipline they also become the loudest, most expensive channel in the stack. This skill defines the levels, the on-device retention policy, and the review rules.

1. Level Definitions

Use exactly five levels. No custom levels, no verbose vs trace variants.

LevelMeaningShips remote?Kept after crash?
traceOnly during local debugging. Very chatty, per-frame or per-iteration.NeverNo
debugDeveloper-oriented. Off in release builds unless a debug flag is set.Sampled lowYes (last 64)
infoBusiness events and state transitions worth surfacing in production.Sampled medYes
warnRecoverable anomaly; user experience may be degraded.AlwaysYes
errorFailed operation; requires investigation. Often paired with a non-fatal.AlwaysYes

fatal is not a log level; it is a crash. Use recordError(fatal=true) / SentrySDK.capture instead.

2. When to Log What

  • Every screen transition: info nav_screen_shown { from, to }.
  • Every network request outcome: info on success, warn on retry, error on final failure. Include status, duration_ms, request_id.
  • Every auth boundary: info on sign-in / sign-out, warn on token refresh retries, error on auth failure.
  • Every feature-flag evaluation that changes user experience: debug level with flag name and assignment.
  • Never log inside build, render, onDraw, layoutSubviews, scrollViewDidScroll, or any per-frame callback.

3. Anti-Patterns

  • Log.d("TAG", "user=$user") where user is a full object -- leaks PII and blows up allocation. Log specific fields, after redaction.
  • catch (e: Exception) { Log.e("err", e) } with no context. Always include what was being attempted and what is being recovered.
  • Logging success of every operation at info. If 99% of calls succeed, one success log per release build is enough; log only failures at info or above.
  • Reusing one logger name for the whole app. Use feature.subfeature so filtering works.

4. On-Device Retention

  • Crashlytics keeps the last 64 log lines per crash. Do not rely on longer history on the client.
  • Write-ahead log for the remote shipper is not a persistent diagnostic log -- it is a transient queue.
  • For support-driven diagnostics (opt-in "share logs" button), write a separate rotated file log:
    • Rolling file size 2 MB, 3 files max (6 MB ceiling).
    • Stored in the app sandbox, never in shared storage.
    • Cleared on sign-out and on app uninstall (automatic on both platforms).
    • Encrypted at rest if any PII can land in it, which it usually will.

5. Kotlin Example

inline fun <T> traced(logger: String, op: String, block: () -> T): T {
    Log.event(logger, "${op}_start")
    val start = System.nanoTime()
    return try {
        val result = block()
        Log.event(logger, "${op}_success",
            attrs = mapOf("duration_ms" to (System.nanoTime() - start) / 1_000_000))
        result
    } catch (t: Throwable) {
        Log.event(logger, "${op}_error", level = Level.ERROR,
            attrs = mapOf("error_class" to (t::class.simpleName ?: "Unknown"),
                          "duration_ms" to (System.nanoTime() - start) / 1_000_000))
        throw t
    }
}

6. Swift Example

func traced<T>(_ logger: String, op: String, _ block: () throws -> T) rethrows -> T {
    AppLog.event(logger: logger, msg: "\(op)_start")
    let start = DispatchTime.now().uptimeNanoseconds
    do {
        let r = try block()
        AppLog.event(logger: logger, msg: "\(op)_success",
            attrs: ["duration_ms": (DispatchTime.now().uptimeNanoseconds - start) / 1_000_000])
        return r
    } catch {
        AppLog.event(logger: logger, msg: "\(op)_error", level: .error,
            attrs: ["error_class": String(describing: type(of: error)),
                    "duration_ms": (DispatchTime.now().uptimeNanoseconds - start) / 1_000_000])
        throw error
    }
}

7. Debug Flags

Do not ship an in-app "verbose logging" toggle that a user can flip without consent implications. Instead:

  • Gate verbose logging behind a remote config flag assigned only to internal QA cohorts.
  • Require re-consent to ship logs if verbose mode is enabled mid-session.
  • Auto-expire verbose mode after 1 hour or at app restart.

8. Review Rules

In code review, reject any new log statement that:

  • Does not have a stable msg event name.
  • Logs an object reference or a full stack trace at info or below.
  • Runs inside a hot path (render, scroll, animation tick).
  • Leaks PII per the redactor deny-list.
  • Adds a new logger name without being listed in the logger registry.

9. Metrics on Your Own Logs

Track log_volume_per_logger_per_release and log_error_rate_per_session. Alert when either doubles release over release -- that's usually a regression, not a new feature.

Checklist

  • Exactly five levels are used: trace, debug, info, warn, error.
  • trace never ships; debug is off in release unless a gated flag is on.
  • No logs inside per-frame or per-scroll callbacks.
  • Support-log file is rotated, capped, encrypted, cleared on sign-out.
  • Verbose mode is gated by remote config and auto-expires.
  • Logger registry exists and code review enforces it.
  • Log-volume and log-error-rate dashboards alert on release-over-release doubling.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.