/** * Minimaler strukturierter Logger für Server-Code. Stdout/stderr in einem * konsistenten Format, sodass Caddy/Docker-Aggregation davor zurechtkommt. * * Bewusst keine externe Lib (pino, winston) — Adapter-Node läuft lean, * und das kleine Volumen rechtfertigt keinen extra Dep + Bundle-Overhead. * * Nutzung in `catch`-Blöcken statt swallowen: * * } catch (err) { * logWarn('cms.batchFetch', err, { collection }); * } * * Der Scope (`'cms.batchFetch'`) ist freier Text — Konvention: `area.action`. */ type LogContext = Record; function format(level: string, scope: string, err: unknown, ctx?: LogContext): string { const message = err instanceof Error ? err.message : String(err); const stack = err instanceof Error && err.stack ? err.stack : undefined; const parts: string[] = [`[${level}] ${scope}: ${message}`]; if (ctx && Object.keys(ctx).length) { parts.push(JSON.stringify(ctx)); } if (stack && level === 'error') { parts.push(stack); } return parts.join(' '); } export function logWarn(scope: string, err: unknown, ctx?: LogContext): void { console.warn(format('warn', scope, err, ctx)); } export function logError(scope: string, err: unknown, ctx?: LogContext): void { console.error(format('error', scope, err, ctx)); } export function logInfo(scope: string, message: string, ctx?: LogContext): void { const parts: string[] = [`[info] ${scope}: ${message}`]; if (ctx && Object.keys(ctx).length) parts.push(JSON.stringify(ctx)); console.log(parts.join(' ')); }