Files
SRCmail/lib/logger.ts
Matthieu MALVACHEandMatthieu MALVACHE fb414bf2c9 feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA
- Contact groups/lists, vCard import/export (RFC 6350), bulk operations
- Advanced search with JMAP filter panel, search chips, cross-mailbox queries
- Vacation responder with JMAP VacationResponse, settings tab, sidebar indicator
- TOTP two-factor authentication support
- Docker multi-stage build with standalone output and docker-compose
- CSP Report-Only headers and security headers via proxy middleware
- Virtual scrolling for large email lists
- Structured server-side logger (text/JSON, configurable level)
- 450+ tests (contacts, vCard, threads, headers, identity, components)
- Playwright E2E framework setup
- Updated README and ROADMAP with all new features
2026-02-16 18:51:30 +01:00

63 lines
2.0 KiB
TypeScript

type LogLevel = 'error' | 'warn' | 'info' | 'debug';
const LEVELS: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };
const COLORS: Record<LogLevel, string> = {
error: '\x1b[31m',
warn: '\x1b[33m',
info: '\x1b[34m',
debug: '\x1b[90m',
};
const RESET = '\x1b[0m';
function getLevel(): number {
const env = process.env.LOG_LEVEL?.toLowerCase() as LogLevel | undefined;
return env && env in LEVELS ? LEVELS[env] : LEVELS.info;
}
function isJson(): boolean {
return process.env.LOG_FORMAT?.toLowerCase() === 'json';
}
function log(level: LogLevel, message: string, extra?: Record<string, unknown>): void {
if (LEVELS[level] > getLevel()) return;
if (isJson()) {
const entry: Record<string, unknown> = {
timestamp: new Date().toISOString(),
level,
message,
...extra,
};
const out = JSON.stringify(entry);
if (level === 'error' || level === 'warn') {
console.error(out);
} else {
console.log(out);
}
return;
}
const color = COLORS[level];
const tag = `${color}[${level.toUpperCase().padEnd(5)}]${RESET}`;
const ts = new Date().toISOString();
const suffix = extra && Object.keys(extra).length > 0
? ` ${COLORS.debug}${JSON.stringify(extra)}${RESET}`
: '';
if (level === 'error' || level === 'warn') {
console.error(`${tag} ${ts} ${message}${suffix}`);
} else {
console.log(`${tag} ${ts} ${message}${suffix}`);
}
}
export const logger = {
error: (message: string, extra?: Record<string, unknown>) => log('error', message, extra),
warn: (message: string, extra?: Record<string, unknown>) => log('warn', message, extra),
info: (message: string, extra?: Record<string, unknown>) => log('info', message, extra),
debug: (message: string, extra?: Record<string, unknown>) => log('debug', message, extra),
request: (method: string, path: string, status: number, durationMs: number) =>
log('info', `${method} ${path} ${status}`, { method, path, status, durationMs }),
};