# Logging ## Overview All server-side logging goes through [Winston](https://github.com/winstonjs/winston). A single root logger is created at module load and shared across the process. Each domain gets a **child logger** that automatically attaches a `domain` field to every log entry, making it easy to filter, tail, and route logs by domain in any log aggregation system. Logging is server-only. Client-side code does not import from `$lib/server/`. ## Request Tracing Every request is assigned a UUID (`requestId`) generated in `handle()` and stored in both `event.locals.requestId` and the request-scoped `AsyncLocalStorage` context (`src/lib/server/context.ts`). A custom Winston format reads from `AsyncLocalStorage` on every log call and injects `requestId` automatically. This means every log line emitted anywhere during a request — across domain loggers, infrastructure clients, auth — carries the same `requestId` with no manual threading required. ## Log Format Format is selected by `NODE_ENV`: | `NODE_ENV` | Format | Use case | | ------------- | ------------------------------------------------------------------------------------------------- | -------------------- | | `development` | Colorized, human-readable `HH:mm:ss LEVEL [domain] (requestId) message {...extra}` | Local dev | | anything else | Structured JSON with `timestamp`, `level`, `domain`, `requestId`, `message`, and any extra fields | Production / staging | JSON output is structured so every field is at the top level — no nested `meta` objects — which makes querying in tools like Loki, Elasticsearch, or CloudWatch straightforward. ## Log Levels Standard Winston levels in descending severity: `error`, `warn`, `info`, `http`, `verbose`, `debug`, `silly`. Set `LOG_LEVEL` env var to control the minimum level emitted (default: `info`). ## Domain Loggers Each server module imports its own named logger from `$lib/server/logger.ts`. The `domain` field is injected automatically by the child logger — callers never set it manually. | Logger export | Domain tag | Used in | | -------------- | ---------------- | ------------------------------- | | `logger` | _(root, no tag)_ | General / unclassified | | `serverLogger` | `server` | `server.ts`, `hooks.server.ts` | | `authLogger` | `auth` | `auth.ts` | | `gitLogger` | `git` | `git/github.ts`, `git/cache.ts` | | `k8sLogger` | `k8s` | `k8s.ts` | Domain-specific loggers for agents, models, tools, knowledge-bases, and gateways are added as those modules are implemented. ## Usage ```ts import { serverLogger as log } from '$lib/server/logger'; log.info('Server ready'); log.warn('K8s CR not found', { name, namespace }); log.error('Failed to open PR', { err, agentName }); // always pass error as `err` for stack capture ``` Pass structured fields as the second argument rather than interpolating into the message string. This keeps the message string stable (searchable as a constant) and fields queryable individually. ## What to Log | Event | Level | Fields | | ---------------------- | ------- | --------------------------------------- | | Server init / shutdown | `info` | — | | Component initialized | `info` | component name, key config (no secrets) | | Login success | `info` | `username` | | Login failure | `warn` | `username` (never log passwords) | | Outbound API call | `debug` | `url`, method | | Outbound API error | `error` | `url`, `status`, `err` | | Unhandled exception | `error` | `err` (stack) | Never log secrets, passwords, tokens, or full request/response bodies.