import pino from 'pino'; import type { Logger } from 'pino'; export type { Logger }; /** * Builds the root pino logger. Called once at startup with the config values. * * In development, pino-pretty is used for human-readable output (lazy import * so it is never bundled in production paths). In test/production, raw JSON is * emitted — fast and parseable by log aggregators. */ export function createLogger(options: { level: string; nodeEnv: string; instanceId: string; }): Logger { const { level, nodeEnv, instanceId } = options; const base = { service: 'tcp-ingestion', instance_id: instanceId, }; // Emit `"level":"info"` instead of pino's default `"level":30` so log // viewers (Portainer, etc.) show a human-readable label rather than the // numeric level. const formatters = { level: (label: string) => ({ level: label }), }; if (nodeEnv === 'development') { return pino({ level, base, timestamp: pino.stdTimeFunctions.isoTime, formatters, transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', ignore: 'pid,hostname', }, }, }); } // Production and test: plain JSON — fast, no extra deps. // ISO-8601 string timestamps (vs default epoch-ms) survive downstream // log renderers (Portainer, Docker --timestamps) without losing seconds. return pino({ level, base, timestamp: pino.stdTimeFunctions.isoTime, formatters }); }