logger.ts
1 import fs from 'fs' 2 import path from 'path' 3 4 import { DATA_DIR } from './data-dir' 5 6 const LOG_FILE = path.join(DATA_DIR, 'app.log') 7 const MAX_SIZE = 5 * 1024 * 1024 // 5MB — rotate when exceeded 8 9 function rotate() { 10 try { 11 const stat = fs.statSync(LOG_FILE) 12 if (stat.size > MAX_SIZE) { 13 const old = LOG_FILE + '.old' 14 if (fs.existsSync(old)) fs.unlinkSync(old) 15 fs.renameSync(LOG_FILE, old) 16 } 17 } catch { 18 // file doesn't exist yet, fine 19 } 20 } 21 22 function write(level: string, tag: string, message: string, data?: unknown) { 23 const ts = new Date().toISOString() 24 let line = `[${ts}] [${level}] [${tag}] ${message}` 25 if (data !== undefined) { 26 try { 27 const s = typeof data === 'string' ? data : JSON.stringify(data, null, 0) 28 line += ' | ' + s.slice(0, 2000) 29 } catch { 30 line += ' | [unserializable]' 31 } 32 } 33 line += '\n' 34 try { 35 rotate() 36 fs.appendFileSync(LOG_FILE, line) 37 } catch (e) { 38 console.error('[logger] write failed:', e) 39 } 40 } 41 42 export const log = { 43 info: (tag: string, msg: string, data?: unknown) => write('INFO', tag, msg, data), 44 warn: (tag: string, msg: string, data?: unknown) => write('WARN', tag, msg, data), 45 error: (tag: string, msg: string, data?: unknown) => write('ERROR', tag, msg, data), 46 debug: (tag: string, msg: string, data?: unknown) => write('DEBUG', tag, msg, data), 47 }