feat: add LogService with ring buffer and subscriber push
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { createLogService } from '../logService.js';
|
||||
|
||||
describe('LogService', () => {
|
||||
let logService: ReturnType<typeof createLogService>;
|
||||
|
||||
beforeEach(() => {
|
||||
logService = createLogService();
|
||||
});
|
||||
|
||||
it('logs entries and returns them via getRecent', () => {
|
||||
logService.log('info', 'Game', 'Server started');
|
||||
const entries = logService.getRecent();
|
||||
expect(entries).toHaveLength(1);
|
||||
expect(entries[0].severity).toBe('info');
|
||||
expect(entries[0].category).toBe('Game');
|
||||
expect(entries[0].message).toBe('Server started');
|
||||
expect(entries[0].timestamp).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('enforces ring buffer limit of 200', () => {
|
||||
for (let i = 0; i < 210; i++) {
|
||||
logService.log('info', 'Game', `Entry ${i}`);
|
||||
}
|
||||
const entries = logService.getRecent();
|
||||
expect(entries).toHaveLength(200);
|
||||
expect(entries[0].message).toBe('Entry 10');
|
||||
});
|
||||
|
||||
it('notifies subscribers on new entry', () => {
|
||||
const received: any[] = [];
|
||||
const unsub = logService.subscribe((entry) => received.push(entry));
|
||||
logService.log('error', 'LLM', 'Timeout');
|
||||
expect(received).toHaveLength(1);
|
||||
expect(received[0].severity).toBe('error');
|
||||
unsub();
|
||||
logService.log('info', 'Game', 'Ignored');
|
||||
expect(received).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { LogEntry, LogSeverity, LogCategory } from '@dflike/shared';
|
||||
|
||||
const MAX_ENTRIES = 200;
|
||||
|
||||
export function createLogService() {
|
||||
const entries: LogEntry[] = [];
|
||||
const subscribers = new Set<(entry: LogEntry) => void>();
|
||||
|
||||
return {
|
||||
log(severity: LogSeverity, category: LogCategory, message: string): void {
|
||||
const entry: LogEntry = {
|
||||
timestamp: Date.now(),
|
||||
severity,
|
||||
category,
|
||||
message,
|
||||
};
|
||||
entries.push(entry);
|
||||
if (entries.length > MAX_ENTRIES) {
|
||||
entries.shift();
|
||||
}
|
||||
for (const cb of subscribers) {
|
||||
cb(entry);
|
||||
}
|
||||
},
|
||||
|
||||
getRecent(): LogEntry[] {
|
||||
return [...entries];
|
||||
},
|
||||
|
||||
subscribe(cb: (entry: LogEntry) => void): () => void {
|
||||
subscribers.add(cb);
|
||||
return () => { subscribers.delete(cb); };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export type LogService = ReturnType<typeof createLogService>;
|
||||
Reference in New Issue
Block a user