Files
chatgpt-mcp/src/utils/logging.js
T
2026-06-11 09:40:28 +01:00

62 lines
1.7 KiB
JavaScript

// Safe logging utility (stderr only, JSON Lines).
import { redact } from './redact.js';
const LEVELS = { silent: 0, info: 10, warn: 20, error: 30 };
const SECRET_KEY_PATTERN = /(api[_-]?key|token|secret|password)/i;
function sanitizeMetadata(meta) {
if (!meta) return {};
const filtered = {};
for (const [key, value] of Object.entries(meta)) {
if (typeof value === 'string' && SECRET_KEY_PATTERN.test(key.toLowerCase())) {
filtered[key] = '[REDACTED]';
} else if (typeof value === 'string' && /^Bearer\s+/i.test(value)) {
// Preserve "Bearer " prefix, redact the token portion
const cleaned = value.replace(/(Bearer\s+).+/, '$1[REDACTED]');
filtered[key] = cleaned;
} else {
filtered[key] = value;
}
}
const jsonStr = JSON.stringify(filtered);
const redactedStr = redact(jsonStr);
try {
return JSON.parse(redactedStr);
} catch {
return filtered;
}
}
export function createLogger(level) {
if (!(level in LEVELS)) {
throw new Error(`Invalid log level: ${level}`);
}
const currentLevel = LEVELS[level];
function write(eventLevel, message, metadata) {
if (LEVELS[eventLevel] < currentLevel && currentLevel !== LEVELS.silent) return;
if (currentLevel === LEVELS.silent) return;
const meta = sanitizeMetadata(metadata);
const entry = JSON.stringify({
level: eventLevel,
ts: new Date().toISOString(),
msg: message,
meta,
});
process.stderr.write(entry + '\n');
}
return {
info: (message, metadata) => write('info', message, metadata),
warn: (message, metadata) => write('warn', message, metadata),
error: (message, metadata) => write('error', message, metadata),
};
}