import type { LogLevel, LogPayload, Logger, LoggerConfig } from './types.js'; function formatPayload( service: string, level: LogLevel, message: string, error?: unknown, extra?: Record ): LogPayload { const payload: LogPayload = { level, message, timestamp: new Date().toISOString(), service, ...extra, }; if (error instanceof Error) { payload.error = error.message; payload.stack = error.stack; } else if (error !== undefined) { payload.error = String(error); } return payload; } function emit(payload: LogPayload, isDev: boolean): void { if (isDev) { const { level, message, error: err, ...rest } = payload; const prefix = `[${level.toUpperCase()}]`; const extras = Object.keys(rest).length > 2 ? ` ${JSON.stringify(rest)}` : ''; const errStr = err ? ` — ${err}` : ''; if (level === 'error' || level === 'warn') { // eslint-disable-next-line no-console console.error(`${prefix} ${message}${errStr}${extras}`); } else { // eslint-disable-next-line no-console console.log(`${prefix} ${message}${extras}`); } } else { const out = JSON.stringify(payload); if (payload.level === 'error' || payload.level === 'warn') { process.stderr.write(out + '\n'); } else { process.stdout.write(out + '\n'); } } } /** * Create a structured logger for a service or dashboard. * * @example * ```ts * import { createLogger } from "@bytelyst/logger"; * const log = createLogger({ service: "admin-dashboard" }); * log.error("Login failed", error, { userId }); * log.info("Seed complete", { containers: 8 }); * ``` */ export function createLogger(config: LoggerConfig): Logger { const { service } = config; const isDev = config.isDev ?? process.env.NODE_ENV !== 'production'; return { error(message: string, error?: unknown, extra?: Record): void { emit(formatPayload(service, 'error', message, error, extra), isDev); }, warn(message: string, extra?: Record): void { emit(formatPayload(service, 'warn', message, undefined, extra), isDev); }, info(message: string, extra?: Record): void { emit(formatPayload(service, 'info', message, undefined, extra), isDev); }, debug(message: string, extra?: Record): void { if (isDev) { emit(formatPayload(service, 'debug', message, undefined, extra), isDev); } }, }; }