Observability checklist
What good observability looks like — structured logs, trace spans, metrics, correlation ids, and the instrumentation rules that turn logs into answers. Use when adding a feature, reviewing a service, or debugging a prod issue.From its SKILL.md
npx -y skills add atuljha23/holocron --skill observability-checklistAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 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.
SKILL.md
4.2 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
Observability checklist
The goal isn't logs — it's answering "what happened" in under five minutes at 2am. Design backward from the question.
Logs
Structured or nothing
- JSON (or logfmt), not free text.
- Every log has:
ts,level,service,request_id,msg, and relevant fields. - Fields are snake_case or camelCase — pick one per service. No mixing.
- Durations in milliseconds as numbers, not "took 2s" strings.
Levels are a contract
error: something failed the user can't recover from. Alert-worthy.warn: something unexpected but handled. Review-worthy.info: the shape of normal traffic. Sampling OK.debug: developer-only. Off in prod.- Don't invent new levels.
What to log
- Request entry (method, path, user, request_id).
- Outcome (status, duration).
- Branch decisions that matter (authz check, cache hit/miss, retry).
- Errors with the full context you need to reproduce.
What NOT to log
- Secrets, tokens, passwords, PII — scrub before logging.
- The full request body by default. Specific fields, yes. Everything, no.
- Stack traces as separate lines — include as a
stackfield so they stay with the event.
Traces
Span per unit of work
- HTTP request handler = 1 span.
- Outbound call = child span.
- DB query = child span (with
db.statementtruncated / hashed, not raw if PII risk). - Background job step = 1 span.
Mandatory attributes
service.name,service.version.- For HTTP:
http.method,http.route,http.status_code. - For DB:
db.system,db.operation. - For errors:
exception.type,exception.message.
Propagation
- Every outbound request carries trace context headers.
- Every background job enqueues with trace context.
- A trace that ends at the HTTP edge and restarts at the worker is useless.
Metrics
RED for services
- Rate — requests per second, per endpoint.
- Errors — error rate, per endpoint.
- Duration — p50/p95/p99, per endpoint.
USE for resources
- Utilization — % of capacity in use.
- Saturation — queue depth / wait time.
- Errors — failed operations.
Cardinality discipline
- No unbounded tags (user_id, tenant_id, url with params). They explode your TSDB bill.
- Pre-aggregate cardinal dimensions; keep labels coarse.
http.route(the template), nothttp.url(the instance).
Correlation
request_idin: logs, traces (asrequest.idattr), response headers, error payloads.trace_idin: logs (auto-injected by SDK), response headers for user bug reports.- A user reporting "I got a 500" should give you enough to find the request — the
request_idis visible and searchable.
Per-language
Node
- Pino or Winston with JSON transport.
- OpenTelemetry SDK (
@opentelemetry/sdk-node). - Prom-client for metrics.
Python
structlogwithProcessorFormatter.opentelemetry-sdk+opentelemetry-instrumentation-*.prometheus_client.
Go
slog(stdlib, Go 1.21+) with JSON handler.go.opentelemetry.io/otel+ auto-instrumentation.prometheus/client_golang.
Rust
tracing+tracing-subscriberwith JSON formatter.opentelemetry-otlp.prometheuscrate.
Anti-patterns
- "Log everything, we'll figure it out later" — the noise hides the signal you need.
- Traces without sampling — you'll drown; sample intelligently (head-based at edges, tail-based for errors).
- Metrics where logs would do — counting "user clicked button" 1M times/day is cheaper as a metric than a log.
- Logs where metrics would do — "latency: 247ms" as a log line is wasting money; it's a histogram.
- Alerts on everything — page only on symptoms that hurt users, not causes.
Smells
- A single log line has more than ~10 fields — probably two events glued together.
- You use
grepto find things — you should have a field + dashboard. - Error messages are generic ("an error occurred") — they cost you the 2am minutes.
console.login prod code — belongs in a logger, tagged and leveled.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 2 of the 12 instructions most monitoring observability skills give in ~1.0k tokens
Counted across 530 of the 532 authors here whose files we hold, read 2026-09-06
- Use structured JSON logginghere, and in 40 of 530, across 36 files
- Link every alert to a runbookin 29 of 530, across 27 files
- Attach correlation IDs to every log linein 19 of 530, across 16 files
- Alert on symptoms rather than causesin 19 of 530, across 17 files
- Use OpenTelemetry for distributed tracingin 15 of 530, across 14 files
- Alert on symptoms users feelin 15 of 530, across 13 files
- Implement health check endpointsin 14 of 530, across 10 files
- Inspect existing dashboards firstin 12 of 530, across 4 files
- Build the minimum useful boardin 12 of 530, across 4 files
- Start from operator questionsin 12 of 530, across 4 files
- Propagate trace context across boundarieshere, and in 11 of 530, across 10 files
- Include trace id in all log entriesin 10 of 530, across 9 files
Said here and by no other author read
- Scrub secrets before logging
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.