Skip to content

Logging

kneshi edited this page May 7, 2026 · 1 revision

Logging

The backend emits structured JSON via nestjs-pino. Separate concern from audit logging - this is operational app logs, not the tamper-evident business trail.

Format

Every line is one JSON object with level, time, context, msg, an event field, and a requestId for HTTP-scoped events. Example (pretty-printed for readability - prod emits it as a single line):

{
  "level": "info",
  "time": "2026-04-19T14:23:07.142Z",
  "context": "TreatmentsService",
  "requestId": "01HQK7X1...",
  "userId": "usr_9f3...",
  "event": "treatment.created",
  "treatmentId": "trt_...",
  "refNumber": 42,
  "msg": "treatment.created"
}

Request correlation

Every HTTP response carries an x-request-id header. If the client sends one matching ^[A-Za-z0-9_-]{1,128}$, it is echoed back; otherwise the server generates a ULID. The same id is bound into every log line within that request's scope, including failures deep in guards and interceptors. Paste an id into docker logs backend | jq 'select(.requestId == "01HQ...")' to reconstruct a request.

Background jobs (RSS sync, monthly compliance snapshot) run under jobId/jobName context in the same way.

PII / credential redaction

Runtime redaction via pino's redact. Two tiers defined in backend/src/common/logging/redact-paths.ts:

  • Strip (disappears entirely): password, passwordHash, resetToken, sessionSecret, req.headers.authorization, req.headers.cookie.
  • Censor ("[Redacted]"): email, phone, remoteAddress, ip, req.headers["x-forwarded-for"].

Both tiers match up to two levels of nesting. Call sites should log IDs, never whole Prisma entities.

For auth flows that do not yet know a userId (signup, login-failed, password-reset), log an emailHash (10-char truncated SHA-256) instead of a raw address - correlatable across lines, low-entropy enough to not survive as a persistent identifier.

Env knobs

Var Default Values
LOG_LEVEL debug in dev, info elsewhere trace / debug / info / warn / error / fatal / silent
LOG_PRETTY on in dev, off elsewhere true / false - turns on pino-pretty for colored human-readable lines
LOG_HTTP true false disables the per-request access log (http.request.completed / http.request.failed)

In tests, test/setup.ts forces LOG_LEVEL=silent and LOG_HTTP=false, and test/silence-logger.ts silences @nestjs/common's classic Logger via Logger.overrideLogger(false) per worker.

Clone this wiki locally