chore: replace pino/pino-pretty with built-in logger
Drop 23 transitive dependencies by replacing pino + pino-pretty with a ~70-line logger that matches the same output format and API. All 80+ call sites work unchanged. Production deps now: @onecli-sh/sdk, better-sqlite3, cron-parser. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,72 @@
|
||||
import pino from 'pino';
|
||||
const LEVELS = { debug: 20, info: 30, warn: 40, error: 50, fatal: 60 } as const;
|
||||
type Level = keyof typeof LEVELS;
|
||||
|
||||
export const logger = pino({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
transport: { target: 'pino-pretty', options: { colorize: true } },
|
||||
});
|
||||
const COLORS: Record<Level, string> = {
|
||||
debug: '\x1b[34m',
|
||||
info: '\x1b[32m',
|
||||
warn: '\x1b[33m',
|
||||
error: '\x1b[31m',
|
||||
fatal: '\x1b[41m\x1b[37m',
|
||||
};
|
||||
const KEY_COLOR = '\x1b[35m';
|
||||
const MSG_COLOR = '\x1b[36m';
|
||||
const RESET = '\x1b[39m';
|
||||
const FULL_RESET = '\x1b[0m';
|
||||
|
||||
// Route uncaught errors through pino so they get timestamps in stderr
|
||||
const threshold =
|
||||
LEVELS[(process.env.LOG_LEVEL as Level) || 'info'] ?? LEVELS.info;
|
||||
|
||||
function formatErr(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return `{\n "type": "${err.constructor.name}",\n "message": "${err.message}",\n "stack":\n ${err.stack}\n }`;
|
||||
}
|
||||
return JSON.stringify(err);
|
||||
}
|
||||
|
||||
function formatData(data: Record<string, unknown>): string {
|
||||
let out = '';
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
if (k === 'err') {
|
||||
out += `\n ${KEY_COLOR}err${RESET}: ${formatErr(v)}`;
|
||||
} else {
|
||||
out += `\n ${KEY_COLOR}${k}${RESET}: ${JSON.stringify(v)}`;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function ts(): string {
|
||||
const d = new Date();
|
||||
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}.${String(d.getMilliseconds()).padStart(3, '0')}`;
|
||||
}
|
||||
|
||||
function log(level: Level, dataOrMsg: Record<string, unknown> | string, msg?: string): void {
|
||||
if (LEVELS[level] < threshold) return;
|
||||
const tag = `${COLORS[level]}${level.toUpperCase()}${level === 'fatal' ? FULL_RESET : RESET}`;
|
||||
const stream = LEVELS[level] >= LEVELS.warn ? process.stderr : process.stdout;
|
||||
if (typeof dataOrMsg === 'string') {
|
||||
stream.write(`[${ts()}] ${tag} (${process.pid}): ${MSG_COLOR}${dataOrMsg}${RESET}\n`);
|
||||
} else {
|
||||
stream.write(
|
||||
`[${ts()}] ${tag} (${process.pid}): ${MSG_COLOR}${msg}${RESET}${formatData(dataOrMsg)}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const logger = {
|
||||
debug: (dataOrMsg: Record<string, unknown> | string, msg?: string) =>
|
||||
log('debug', dataOrMsg, msg),
|
||||
info: (dataOrMsg: Record<string, unknown> | string, msg?: string) =>
|
||||
log('info', dataOrMsg, msg),
|
||||
warn: (dataOrMsg: Record<string, unknown> | string, msg?: string) =>
|
||||
log('warn', dataOrMsg, msg),
|
||||
error: (dataOrMsg: Record<string, unknown> | string, msg?: string) =>
|
||||
log('error', dataOrMsg, msg),
|
||||
fatal: (dataOrMsg: Record<string, unknown> | string, msg?: string) =>
|
||||
log('fatal', dataOrMsg, msg),
|
||||
};
|
||||
|
||||
// Route uncaught errors through logger so they get timestamps in stderr
|
||||
process.on('uncaughtException', (err) => {
|
||||
logger.fatal({ err }, 'Uncaught exception');
|
||||
process.exit(1);
|
||||
|
||||
@@ -9,16 +9,10 @@
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import pino from 'pino';
|
||||
|
||||
import { MOUNT_ALLOWLIST_PATH } from './config.js';
|
||||
import { logger } from './logger.js';
|
||||
import { AdditionalMount, AllowedRoot, MountAllowlist } from './types.js';
|
||||
|
||||
const logger = pino({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
transport: { target: 'pino-pretty', options: { colorize: true } },
|
||||
});
|
||||
|
||||
// Cache the allowlist in memory - only reloads on process restart
|
||||
let cachedAllowlist: MountAllowlist | null = null;
|
||||
let allowlistLoadError: string | null = null;
|
||||
|
||||
Reference in New Issue
Block a user