「 简记往来」第二十篇:日志系统设计——没有日志,出了问题只能靠猜

一、没有日志的代价

有一次,用户反馈“批量记礼功能用不了”。

我登录服务器,查了代码、查了数据库、查了网络……折腾了一个小时,才发现是MongoDB连接超时。

如果有日志,这个问题30秒就能定位。

没有日志,出了问题只能靠猜。

二、Node.js日志的基本原则

Node.js日志管理通常遵循**“应用层 + 系统层 + 运维层”三层结合的策略**。

核心原则:

  1. 使用结构化日志:采用JSON格式,便于检索和分析
  2. 分级记录:ERROR / WARN / INFO / DEBUG
  3. 包含上下文:requestId、userId、timestamp等
  4. 异步写入:不阻塞事件循环

三、日志库选型

Node.js生态推荐三个日志库:

特点适用场景
Winston功能最全、支持多传输需要多种输出方式
Pino性能最好、JSON原生高并发场景
Bunyan轻量、结构化简单应用

简记往来使用Winston

constwinston=require('winston');constlogger=winston.createLogger({level:process.env.LOG_LEVEL||'info',format:winston.format.combine(winston.format.timestamp(),winston.format.json()),transports:[newwinston.transports.File({filename:'logs/error.log',level:'error'}),newwinston.transports.File({filename:'logs/combined.log'})]});if(process.env.NODE_ENV!=='production'){logger.add(newwinston.transports.Console({format:winston.format.simple()}));}

四、日志分级

级别用途示例
ERROR系统错误,需要立即处理数据库连接失败
WARN异常但可恢复请求参数不完整,使用默认值
INFO关键业务操作用户登录、创建账本
DEBUG调试信息查询参数、中间件执行

生产环境建议将日志级别控制在WARN/ERROR,按需开启INFO/DEBUG。

五、日志格式规范

每条日志应包含:

{"timestamp":"2026-06-30T10:00:00.000Z","level":"INFO","service":"jianji-backend","requestId":"req_xxx","userId":"user_xxx","message":"用户登录成功","duration":125}

requestId是贯穿整个请求链路的唯一标识,方便追踪问题。

六、日志存储与轮转

日志文件需要定期轮转,防止磁盘占满:

constDailyRotateFile=require('winston-daily-rotate-file');consttransport=newDailyRotateFile({filename:'logs/application-%DATE%.log',datePattern:'YYYY-MM-DD',maxSize:'20m',maxFiles:'14d'});

七、总结

日志系统是运维的“眼睛”。

  • Winston/Pino记录结构化日志
  • ERROR/WARN/INFO/DEBUG分级
  • 包含requestId、userId、timestamp等上下文
  • 定期轮转,防止磁盘占满

没有日志,出了问题只能靠猜。有了日志,一切都有迹可循。

下一篇,我们来聊聊数据备份与恢复策略——数据丢了怎么办?

评论区聊聊:你的日志系统是怎么设计的?