feat(soak): structured JSONL logger with child contexts
Single file, no transport, writes one JSON line per call to stdout. Child loggers inherit parent meta so scenarios can bind room/game context once and forget about it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
59
tests/soak/core/logger.ts
Normal file
59
tests/soak/core/logger.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Structured JSONL logger for the soak harness.
|
||||
*
|
||||
* One JSON line per call, written to stdout by default. Child loggers
|
||||
* inherit parent meta so scenarios can bind room/game context once and
|
||||
* every subsequent call carries it automatically.
|
||||
*/
|
||||
|
||||
import type { Logger, LogLevel } from './types';
|
||||
|
||||
const LEVEL_ORDER: Record<LogLevel, number> = {
|
||||
debug: 0,
|
||||
info: 1,
|
||||
warn: 2,
|
||||
error: 3,
|
||||
};
|
||||
|
||||
export interface LoggerOptions {
|
||||
runId: string;
|
||||
minLevel?: LogLevel;
|
||||
/** Defaults to process.stdout.write bound to stdout. Override for tests. */
|
||||
write?: (line: string) => boolean;
|
||||
baseMeta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function createLogger(opts: LoggerOptions): Logger {
|
||||
const minLevel = opts.minLevel ?? 'info';
|
||||
const write = opts.write ?? ((s: string) => process.stdout.write(s));
|
||||
const baseMeta = opts.baseMeta ?? {};
|
||||
|
||||
function emit(level: LogLevel, msg: string, meta?: object): void {
|
||||
if (LEVEL_ORDER[level] < LEVEL_ORDER[minLevel]) return;
|
||||
const line = JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
level,
|
||||
msg,
|
||||
runId: opts.runId,
|
||||
...baseMeta,
|
||||
...(meta ?? {}),
|
||||
}) + '\n';
|
||||
write(line);
|
||||
}
|
||||
|
||||
const logger: Logger = {
|
||||
debug: (msg, meta) => emit('debug', msg, meta),
|
||||
info: (msg, meta) => emit('info', msg, meta),
|
||||
warn: (msg, meta) => emit('warn', msg, meta),
|
||||
error: (msg, meta) => emit('error', msg, meta),
|
||||
child: (meta) =>
|
||||
createLogger({
|
||||
runId: opts.runId,
|
||||
minLevel,
|
||||
write,
|
||||
baseMeta: { ...baseMeta, ...meta },
|
||||
}),
|
||||
};
|
||||
|
||||
return logger;
|
||||
}
|
||||
Reference in New Issue
Block a user