你的浏览器无法正常显示内容,请更换或升级浏览器!

Node.js 日志记录最佳实践与方案选型

tenfei
tenfei
发布于2026-08-26 16:52 阅读23次
Node.js 日志记录最佳实践与方案选型
梳理 Node.js 生产环境日志记录的最佳实践,涵盖日志分级、结构化日志、winston 和 pino 两大主流日志库的对比与配置、日志切割与归档、日志采集等,附代码示例和常见踩坑。
# Node.js 日志记录最佳实践与方案选型 ## 前言 日志是排查问题的第一手资料,但很多项目要么 `console.log` 到处飞,要么日志格式混乱、级别缺失。本文系统梳理 Node.js 日志的正确做法。 ## 为什么不直接用 console.log - 无法区分日志级别(debug/info/error) - 无法结构化输出(JSON),不利于采集分析 - 无法控制输出目的地(文件/控制台/远程) - 无法按需切割、归档 生产环境应使用成熟的日志库。 ## 日志级别 ```javascript // 从低到高 // error: 错误,需要立即关注 // warn: 警告,潜在问题 // info: 关键业务信息 // debug: 调试信息,生产环境关闭 ``` 环境区分:开发环境输出 debug,生产环境只输出 info 及以上。 ## 方案一:winston ### 安装与基础配置 ```bash npm install winston ``` ```javascript const winston = require("winston"); const logger = winston.createLogger({ level: process.env.LOG_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" }), ], }); logger.info("用户登录成功", { userId: 123 }); logger.error("数据库连接失败", { err: error.message }); ``` ### 日志切割(按天/按大小) ```bash npm install winston-daily-rotate-file ``` ```javascript const DailyRotateFile = require("winston-daily-rotate-file"); const transport = new DailyRotateFile({ filename: "logs/app-%DATE%.log", datePattern: "YYYY-MM-DD", maxSize: "20m", maxFiles: "14d", }); const logger = winston.createLogger({ transports: [transport], }); ``` ## 方案二:pino ### 安装与使用 ```bash npm install pino ``` ```javascript const pino = require("pino"); const logger = pino({ level: process.env.LOG_LEVEL || "info", base: { pid: process.pid }, timestamp: pino.stdTimeFunctions.isoTime, }); logger.info({ userId: 123 }, "用户登录成功"); logger.error({ err }, "数据库连接失败"); ``` pino 以极高性能著称,适合高吞吐场景。 ## winston vs pino 对比 | 特性 | winston | pino | |------|---------|------| | 性能 | 中等 | 极高 | | 生态 | 丰富(transport 多) | 轻量高效 | | 学习成本 | 稍高 | 低 | | 适用场景 | 功能全面 | 高性能 | 追求性能选 pino,需要丰富 transport 选 winston。 ## Express 集成 ```javascript // 请求日志中间件 app.use((req, res, next) => { const start = Date.now(); res.on("finish", () => { logger.info({ method: req.method, url: req.originalUrl, status: res.statusCode, duration: Date.now() - start, }, "请求完成"); }); next(); }); // 全局错误日志 app.use((err, req, res, next) => { logger.error({ err, url: req.url }, "未捕获错误"); res.status(500).json({ error: "Internal Server Error" }); }); ``` ## 结构化日志规范 ```javascript // 好的做法:字段化,方便检索 logger.error({ error: err.message, stack: err.stack, userId: req.user?.id, traceId: req.headers["x-trace-id"], }, "订单处理失败"); // 避免:把变量拼进字符串 // logger.error("订单处理失败: " + err.message); ``` 结构化日志(JSON 字段)方便用 ELK、Loki 等工具检索分析。 ## 常见踩坑 ### 坑1:日志里打印敏感信息 ```javascript // 避免记录密码、token、身份证等敏感信息 // 脱敏后再记录 logger.info({ phone: maskPhone(phone) }, "注册成功"); ``` ### 坑2:日志量过大拖垮性能 - 生产环境关闭 debug 级别 - 避免在循环里高频打日志 - 日志异步写入,不阻塞主流程 ### 坑3:日志文件无限增长 务必配置日志切割和保留天数,防止磁盘占满。 ## 小结 日志记录的要点:分级输出、结构化 JSON、按天切割、敏感信息脱敏。选型上高性能用 pino,功能全面用 winston。配合请求日志中间件和全局错误捕获,排查问题会轻松很多。

2

0

文章点评
Copyright © from 2021 by namoer.com
458815@qq.com QQ:458815
蜀ICP备2022020274号-2