Split monolithic chat service into modular structure with Matrix client support, extract web server into per-resource route modules, introduce bootstrap/main-loop separation, and add comprehensive vitest coverage across services, repositories, and utilities. Adds project docs and CLAUDE.md agent instructions.
58 lines
1.7 KiB
TypeScript
58 lines
1.7 KiB
TypeScript
import winston from 'winston';
|
|
|
|
export interface LogEntry {
|
|
level: string;
|
|
message: string;
|
|
meta: Record<string, unknown>;
|
|
timestamp: string;
|
|
}
|
|
|
|
export function createMockLogger(): winston.Logger & { logs: LogEntry[] } {
|
|
const logs: LogEntry[] = [];
|
|
|
|
const logger = winston.createLogger({
|
|
level: 'debug',
|
|
format: winston.format.combine(
|
|
winston.format.timestamp(),
|
|
winston.format.json()
|
|
),
|
|
transports: [
|
|
new winston.transports.Console({
|
|
format: winston.format.printf(({ level, message, timestamp, ...meta }) => {
|
|
logs.push({ level: String(level), message: String(message), meta, timestamp: String(timestamp) });
|
|
return '';
|
|
}),
|
|
}),
|
|
],
|
|
}) as winston.Logger & { logs: LogEntry[] };
|
|
|
|
// Override all log levels to capture
|
|
const levels = ['error', 'warn', 'info', 'http', 'debug'] as const;
|
|
for (const level of levels) {
|
|
const original = logger[level];
|
|
logger[level] = ((message: unknown, ...meta: unknown[]) => {
|
|
logs.push({
|
|
level,
|
|
message: String(message),
|
|
meta: meta[0] as Record<string, unknown> || {},
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
return logger;
|
|
}) as any;
|
|
}
|
|
|
|
(logger as any).logs = logs;
|
|
|
|
logger.logs = logs;
|
|
|
|
return logger as winston.Logger & { logs: LogEntry[] };
|
|
}
|
|
|
|
export function getLogsByLevel(logger: winston.Logger & { logs: LogEntry[] }, level: string): LogEntry[] {
|
|
return logger.logs.filter(l => l.level === level);
|
|
}
|
|
|
|
export function hasLog(logger: winston.Logger & { logs: LogEntry[] }, level: string, messageContains: string): boolean {
|
|
return logger.logs.some(l => l.level === level && l.message.includes(messageContains));
|
|
}
|