89 lines
2.1 KiB
TypeScript
89 lines
2.1 KiB
TypeScript
|
|
/**
|
||
|
|
* Simple file logger for the Nitro server process.
|
||
|
|
*
|
||
|
|
* Writes to `~/.openpencil/logs/server-{YYYY-MM-DD}.log`.
|
||
|
|
* Also forwards to console for dev mode visibility.
|
||
|
|
* Keeps the last 7 days of logs, auto-cleans on first write.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs';
|
||
|
|
import { homedir } from 'node:os';
|
||
|
|
import { join } from 'node:path';
|
||
|
|
|
||
|
|
const MAX_LOG_DAYS = 7;
|
||
|
|
|
||
|
|
const logDir = join(homedir(), '.openpencil', 'logs');
|
||
|
|
let dirEnsured = false;
|
||
|
|
let cleanedUp = false;
|
||
|
|
|
||
|
|
function ensureDir(): void {
|
||
|
|
if (dirEnsured) return;
|
||
|
|
try {
|
||
|
|
if (!existsSync(logDir)) {
|
||
|
|
mkdirSync(logDir, { recursive: true });
|
||
|
|
}
|
||
|
|
dirEnsured = true;
|
||
|
|
} catch {
|
||
|
|
// Silently fail — logging is best-effort
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function todayStamp(): string {
|
||
|
|
return new Date().toISOString().slice(0, 10);
|
||
|
|
}
|
||
|
|
|
||
|
|
function timestamp(): string {
|
||
|
|
return new Date().toISOString();
|
||
|
|
}
|
||
|
|
|
||
|
|
function getLogFilePath(): string {
|
||
|
|
return join(logDir, `server-${todayStamp()}.log`);
|
||
|
|
}
|
||
|
|
|
||
|
|
function cleanOldLogs(): void {
|
||
|
|
if (cleanedUp) return;
|
||
|
|
cleanedUp = true;
|
||
|
|
try {
|
||
|
|
const files = readdirSync(logDir);
|
||
|
|
const cutoff = Date.now() - MAX_LOG_DAYS * 24 * 60 * 60 * 1000;
|
||
|
|
for (const file of files) {
|
||
|
|
if (!file.endsWith('.log')) continue;
|
||
|
|
const filePath = join(logDir, file);
|
||
|
|
try {
|
||
|
|
const s = statSync(filePath);
|
||
|
|
if (s.mtimeMs < cutoff) {
|
||
|
|
unlinkSync(filePath);
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
// ignore individual file errors
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
// ignore
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function writeLine(level: string, msg: string): void {
|
||
|
|
const line = `${timestamp()} [${level}] ${msg}\n`;
|
||
|
|
// Forward to console
|
||
|
|
if (level === 'ERROR') {
|
||
|
|
process.stderr.write(line);
|
||
|
|
} else {
|
||
|
|
process.stdout.write(line);
|
||
|
|
}
|
||
|
|
// Write to file
|
||
|
|
try {
|
||
|
|
ensureDir();
|
||
|
|
cleanOldLogs();
|
||
|
|
appendFileSync(getLogFilePath(), line, 'utf-8');
|
||
|
|
} catch {
|
||
|
|
// Disk full or permission error — silently drop
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const serverLog = {
|
||
|
|
info: (msg: string) => writeLine('INFO', msg),
|
||
|
|
warn: (msg: string) => writeLine('WARN', msg),
|
||
|
|
error: (msg: string) => writeLine('ERROR', msg),
|
||
|
|
};
|