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:
52
tests/soak/tests/logger.test.ts
Normal file
52
tests/soak/tests/logger.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { createLogger } from '../core/logger';
|
||||
|
||||
describe('logger', () => {
|
||||
let writes: string[];
|
||||
let write: (s: string) => boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
writes = [];
|
||||
write = (s: string) => {
|
||||
writes.push(s);
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
it('emits a JSON line per call with level and msg', () => {
|
||||
const log = createLogger({ runId: 'r1', write });
|
||||
log.info('hello');
|
||||
expect(writes).toHaveLength(1);
|
||||
const parsed = JSON.parse(writes[0]);
|
||||
expect(parsed.level).toBe('info');
|
||||
expect(parsed.msg).toBe('hello');
|
||||
expect(parsed.runId).toBe('r1');
|
||||
expect(parsed.timestamp).toBeTypeOf('string');
|
||||
});
|
||||
|
||||
it('merges meta into the log line', () => {
|
||||
const log = createLogger({ runId: 'r1', write });
|
||||
log.warn('slow', { turnMs: 3000 });
|
||||
const parsed = JSON.parse(writes[0]);
|
||||
expect(parsed.turnMs).toBe(3000);
|
||||
expect(parsed.level).toBe('warn');
|
||||
});
|
||||
|
||||
it('child logger inherits parent meta', () => {
|
||||
const log = createLogger({ runId: 'r1', write });
|
||||
const roomLog = log.child({ room: 'room-1' });
|
||||
roomLog.info('game_start');
|
||||
const parsed = JSON.parse(writes[0]);
|
||||
expect(parsed.room).toBe('room-1');
|
||||
expect(parsed.runId).toBe('r1');
|
||||
});
|
||||
|
||||
it('respects minimum level', () => {
|
||||
const log = createLogger({ runId: 'r1', write, minLevel: 'warn' });
|
||||
log.debug('nope');
|
||||
log.info('nope');
|
||||
log.warn('yes');
|
||||
log.error('yes');
|
||||
expect(writes).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user