new node.js impl., removed old stuff

This commit is contained in:
2026-02-12 17:03:00 -06:00
parent 4343aefb76
commit 16469de068
33 changed files with 2762 additions and 2731 deletions

View File

@@ -0,0 +1,98 @@
/**
* Structured logging for email worker with daily rotation
*
* Uses pino for high-performance JSON logging.
* Console output is human-readable via pino-pretty in dev,
* and JSON in production (for Docker json-file driver).
*
* File logging uses a simple daily rotation approach.
*/
import pino from 'pino';
import { existsSync, mkdirSync, createWriteStream, type WriteStream } from 'node:fs';
import { join } from 'node:path';
// ---------------------------------------------------------------------------
// Configuration
// ---------------------------------------------------------------------------
const LOG_DIR = '/var/log/email-worker';
const LOG_FILE_PREFIX = 'worker';
// ---------------------------------------------------------------------------
// File stream (best-effort, never crashes the worker)
// ---------------------------------------------------------------------------
let fileStream: WriteStream | null = null;
let currentDateStr = '';
function getDateStr(): string {
return new Date().toISOString().slice(0, 10); // YYYY-MM-DD
}
function ensureFileStream(): WriteStream | null {
const today = getDateStr();
if (fileStream && currentDateStr === today) return fileStream;
try {
if (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true });
const filePath = join(LOG_DIR, `${LOG_FILE_PREFIX}.${today}.log`);
fileStream = createWriteStream(filePath, { flags: 'a' });
currentDateStr = today;
return fileStream;
} catch {
// Silently continue without file logging (e.g. permission issue)
return null;
}
}
// ---------------------------------------------------------------------------
// Pino logger
// ---------------------------------------------------------------------------
const logger = pino({
level: 'info',
formatters: {
level(label) {
return { level: label };
},
},
timestamp: pino.stdTimeFunctions.isoTime,
// In production Docker we write plain JSON to stdout;
// pino-pretty can be used during dev via `pino-pretty` pipe.
});
// ---------------------------------------------------------------------------
// Log level mapping (matches Python worker levels)
// ---------------------------------------------------------------------------
type LogLevel = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL' | 'SUCCESS';
const LEVEL_MAP: Record<LogLevel, keyof pino.Logger> = {
DEBUG: 'debug',
INFO: 'info',
WARNING: 'warn',
ERROR: 'error',
CRITICAL: 'fatal',
SUCCESS: 'info',
};
// ---------------------------------------------------------------------------
// Public API mirrors Python's log(message, level, worker_name)
// ---------------------------------------------------------------------------
export function log(
message: string,
level: LogLevel = 'INFO',
workerName = 'unified-worker',
): void {
const prefix = level === 'SUCCESS' ? '[SUCCESS] ' : '';
const formatted = `[${workerName}] ${prefix}${message}`;
// Pino
const method = LEVEL_MAP[level] ?? 'info';
(logger as any)[method](formatted);
// File (best-effort)
const stream = ensureFileStream();
if (stream) {
const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
const line = `[${ts}] [${level}] [${workerName}] ${prefix}${message}\n`;
stream.write(line);
}
}