Observability
A portable Claude Code skills library (plugin) for a Django 5.2 + Next.js 16 house stack: 30 model-agnostic, tenant-isolation-and-security-first skills.
npx -y skills add Deadlymind/nanolama --skill observabilityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 21 days oldThe repository was created 21 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 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
Instruments a Django/DRF plus Celery plus Channels stack so production failures are visible — structured JSON logs carrying a correlation id, tenant id (entreprise) and user id on every line, that same id propagated across the request, the task it enqueues and any consumer, plus tracing spans on state-changing work, scrubbed error tracking, and RED metrics with alerts that page a human. Use when adding logging or a logging filter, threading a correlation id through Celery or Channels, wiring an error tracker or metrics dashboard, or asking how to make one user action one traceable thread. Not for triaging a live incident (see incident-response) or auditing a diff for leaks (see security-review).
SKILL.md
6.3 KB, as published. Nobody here has run it
Observability (tenant-correlated logs, traces, metrics)
When to use
Adding or reviewing anything that must be debuggable in production without a repro: a new logging config, a Celery task or Channels consumer whose failures you can't currently trace, an error-tracker integration, or a metrics dashboard. The goal is that one user action reads as one traceable thread across the web request, the background task it fires, and any realtime consumer — all stamped with who (user) and which tenant (entreprise).
Pattern
Four signals, one correlation id tying them together:
- Structured logs. Emit JSON, not free text. Every line carries a
correlation_id,entreprise_id, anduser_id— injected by a logging filter, never hand-passed. Grep-by-tenant and grep-by-request both work. - Propagated correlation id. Generate (or accept) the id at the DRF request edge, put it in a context var, and pass it explicitly into every Celery task and Channels consumer that request spawns. Background work inherits the thread.
- Distributed tracing. Open a span (OpenTelemetry-style) around every state-changing action and every background task, so you can see the request → task → consumer causal chain and where the latency lives.
- Metrics with alerts. Track the RED signals — request Rate, Error rate, Duration — plus queue depth and live websocket-connection counts, and set thresholds that page a human, not just color a chart.
Absolute rule: never log a secret, token, cookie, Authorization header, or
raw PII. Scrub before the record leaves the process. This is a security boundary,
not a nicety (ties security-review).
Steps / idioms
-
Stamp every log line via a filter. A
logging.Filterreads the current request's context and attaches the ids to each record, so no call site has to remember. Point a JSON formatter at the same fields:# observability/logging.py — inject correlation + tenant into every record. import logging from contextvars import ContextVar correlation_id: ContextVar[str] = ContextVar("correlation_id", default="-") entreprise_id: ContextVar[str] = ContextVar("entreprise_id", default="-") user_id: ContextVar[str] = ContextVar("user_id", default="-") class ContextFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: record.correlation_id = correlation_id.get() record.entreprise_id = entreprise_id.get() record.user_id = user_id.get() return True # filter only enriches; it never drops the recordSet the context vars in DRF middleware from
request.user(reuse the same tenant accessor asmulti-tenancy); read an inboundX-Correlation-IDheader if present, else mint a UUID and echo it back on the response. -
Carry the id into background work. Context vars do not cross a process, so pass the id as an explicit task argument (or a header) and re-set it at the top of the task; do the same in a Channels consumer's
connect:# Enqueue with the id; the worker re-establishes context on receipt. process_invoice.delay(invoice_id, correlation_id=correlation_id.get()) -
Wrap state-changing work in a span. Name it for the action (
invoice.approve), tag it withentreprise_id, and let the task span link to the request span via the propagated id. Read-only GETs rarely need their own. -
Scrub before export. Configure the error tracker's before-send hook to drop
Authorization/Cookieheaders,password/token/secretkeys, and known PII fields — allowlist what may leave, don't blocklist and hope. -
Wire alerts, not just dashboards. An error-rate spike, a growing Celery queue, or a websocket-connection cliff should page on-call (see
incident-responsefor what happens after the page).
Adapt to your repo
Rename entreprise_id/Entreprise and the tenant/user accessor path to match
your models. Choose your own transport for the correlation id into Celery (task
kwarg vs. message header) and Channels (scope entry). Do not pin tool versions
here — Sentry, OpenTelemetry, and your metrics backend all move; confirm the
current SDK and API surface with version-check before wiring. The stable facts
you can rely on are the RED signal set and the correlation-id discipline, not any
one vendor's helper names.
Gotchas
- Context vars are per-process, per-task. A
.delay()does not carry yourContextVar— pass the id explicitly and re-set it in the worker, or the task's logs showcorrelation_id=-and the thread breaks exactly where you need it. - Logging the request body re-leaks what the serializer hid. A debug line that
dumps
request.datacan spill a token or PII the API response never exposed — scrub at the logging boundary too, not only at the API edge (security-review). - Sampling hides the rare error. Trace-sample normal traffic if you must, but keep error traces at 100% or the one failure you're chasing gets dropped.
- A dashboard nobody watches is not monitoring. If a signal has no threshold that pages, treat it as decoration — the outage will be found by a customer.
- High-cardinality metric labels explode cost. Never label a metric with
user_idor a raw id; keepentreprise_idfor logs/traces, aggregate metrics. - Don't rebuild an id that already exists. If an upstream proxy or gateway already sets a request/trace id, adopt it instead of minting a competing one.
See also
incident-responsesecurity-reviewcelery-tasksdeploy-aws