Node.js 实战六:日志系统设计 —— 不只是 console.log,而是可追溯的行为记录链

开发时你写:

console.log('进来了');

上线后出 bug,产品问:

“这个用户为啥订单创建失败?”

你打开服务器一看,啥也没有。于是陷入盲猜、靠运气 debug 的地狱模式。

你需要日志。不是调试用的,而是生产可追溯的

本篇我们讲讲:

如何在 Node.js 项目中构建一个 结构清晰、功能全面、适合生产环境的日志系统

一、日志系统需要满足哪些核心能力?

能力

含义

分级分类

info、warn、error、debug,不同级别记录

可持久化

存磁盘、发远程、进数据库

可筛查

带时间、用户、路径、traceId 等信息

可格式化

JSON、文本、彩色 console

可扩展

接入监控系统,发送告警,支持日志聚合服务

二、日志库推荐:winston / pino

winston(功能全、文档好、插件多)

npm install winston
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console(),              // 控制台
    new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
    new winston.transports.File({ filename: 'logs/combined.log' }),
  ],
});

三、日志等级与使用规范

等级

用于记录

error

程序异常、业务错误

warn

潜在问题、预期外但非致命事件

info

请求成功、关键行为记录

debug

调试信息,开发/测试环境开启

使用建议:

logger.info('User login success', { userId: 123 });
logger.error('Create order failed', { error: e.message, reqId });

四、给每个请求打上 traceId(链路追踪)

为了把一串相关日志串起来:

  1. 在中间件中生成唯一 ID(如 uuid)

  2. 注入到 ctx/request 中,写入每条日志

const { v4: uuidv4 } = require('uuid');

app.use(async (ctx, next) => {
  ctx.traceId = uuidv4();
  await next();
});

然后写日志时统一带上:

logger.info('Processing payment', { traceId: ctx.traceId });

这样你就能一眼查出“这一波请求发生了啥”。

五、日志落盘与分环境配置

推荐结构:

logs/
├── error.log
├── combined.log
├── access.log

开发环境只打印 console

生产环境写文件 + 控制台(可彩色输出)

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.simple()
  }));
}

六、接入远程日志系统(推荐方式)

目标系统

工具

阿里云 SLS

aliyun-sls-sdk

ElasticSearch

filebeat + logstash

Loki + Grafana

winston-loki 插件

日志告警(如钉钉)

winston-dingding 等 webhook 插件

建议:关键 error 日志可额外推送报警渠道

七、扩展:用户行为日志 / 操作记录系统设计

除了系统层级的 error/info/debug,你还应该记录 业务行为日志,例如:

  • 谁登录了系统?

  • 谁删除了某条数据?

  • 谁修改了用户权限?

  • 谁导出了哪些数据?

这些信息不仅有助于:

  • 审计追责

  • 用户行为分析

  • 风控与安全预警

  • 后台展示操作记录

建议做法:

  1. 定义一个 log_behavior 表,结构如:

CREATE TABLE log_behavior (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT,
  action VARCHAR(64),
  target_type VARCHAR(64),
  target_id BIGINT,
  timestamp DATETIME,
  detail TEXT
);

2. 在关键业务逻辑中插入行为日志:

await behaviorLogger.log({
  userId: ctx.state.user.id,
  action: 'delete_user',
  targetType: 'user',
  targetId: deletedUser.id,
  detail: JSON.stringify({ reason: 'admin operation' }),
});

3. 可配合后台系统展示为“操作日志模块”。

八、日志系统落地注意事项清单 

建议做法

❯ 文件命名

按日期拆分,或按级别分文件(logs/error-20240512.log)

❯ 格式

JSON 格式日志利于机器读取(如 ELK)

❯ 打印内容

包含 userId、traceId、req.path、IP、UA 等上下文信息

❯ 保留期限

每日日志建议保留 7~30 天,可用定时清理脚本

❯ 安全性

过滤敏感字段,如密码、token,不应打印入日志

总结

日志不是“写给自己看的调试输出”,它是:

  • 问题追溯的核心线索

  • 用户行为的安全记录

  • 系统稳定的前置保障

  • 可观测性的最底层能力

稳定的项目,不是靠程序没出 bug,而是出了 bug 你“知道它在哪、为什么、什么时候发生的”。

构建一套规范、分级、可扩展的日志系统,是任何线上项目的“标配基建”。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值