/ src / lib / server / logger.ts
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  }