码桶

发现社区成员的开源项目

奶狗 /

ng-webot

公开
main
ng-webot/lib/logger.js
logger.js2.1 KB
/**
 * 日志落地模块
 * 拦截 console.log/info/warn/error/debug,在保持原样输出到终端的同时,
 * 追加写入到 data/logs/app-YYYY-MM-DD.log(按天滚动)。
 * 供「日志控制台」页面读取展示。
 */
const fs = require('fs');
const path = require('path');

const LOG_DIR = path.join(__dirname, '..', 'data', 'logs');
try { fs.mkdirSync(LOG_DIR, { recursive: true }); } catch (e) { /* ignore */ }

function pad(n) { return String(n).padStart(2, '0'); }
function dateStamp(d) {
  d = d || new Date();
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}
function timeStamp(d) {
  d = d || new Date();
  return `${dateStamp(d)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

let currentDate = dateStamp();
function logFileFor(date) {
  return path.join(LOG_DIR, `app-${date}.log`);
}

function serialize(a) {
  if (typeof a === 'string') return a;
  if (a instanceof Error) return a.stack || a.message;
  try { return JSON.stringify(a); } catch (e) { try { return String(a); } catch (e2) { return '[unserializable]'; } }
}

function append(level, args) {
  try {
    const d = dateStamp();
    if (d !== currentDate) currentDate = d; // 跨天滚动到新文件
    const msg = args.map(serialize).join(' ');
    const line = `[${timeStamp()}] [${level}] ${msg}\n`;
    fs.appendFile(logFileFor(currentDate), line, () => {});
  } catch (e) { /* 写入失败不影响主流程 */ }
}

// 保存原始方法,避免递归
const orig = {
  log: console.log.bind(console),
  info: console.info.bind(console),
  warn: console.warn.bind(console),
  error: console.error.bind(console),
  debug: console.debug.bind(console),
};

function wrap(level, origFn) {
  return function (...args) {
    try { origFn(...args); } catch (e) { /* 原输出异常也不影响 */ }
    append(level, args);
  };
}

console.log = wrap('LOG', orig.log);
console.info = wrap('INFO', orig.info);
console.warn = wrap('WARN', orig.warn);
console.error = wrap('ERROR', orig.error);
console.debug = wrap('DEBUG', orig.debug);

module.exports = { LOG_DIR, dateStamp, logFileFor };