linux

Node.js日志记录最佳实践是什么

小樊
51
2025-10-12 22:31:55
栏目: 编程语言

1. 选择合适的日志库
根据应用场景(如性能需求、功能复杂度)选择日志库是基础。常用库包括:

2. 配置环境适配的日志级别
根据环境调整日志详细程度,避免不必要的性能消耗:

const level = process.env.NODE_ENV === 'production' ? 'warn' : 'debug';

3. 使用结构化日志(JSON格式)
结构化日志(如JSON)便于后续解析、分析和可视化,是现代日志管理的核心要求。相比纯文本,JSON日志可通过工具(如ELK、Grafana)快速提取字段(如eventuserIdtimestamp),支持聚合和过滤。示例如下:

logger.info({
  event: 'user_login',
  userId: '12345',
  username: 'john_doe',
  ip: '192.168.1.1',
  userAgent: 'Chrome/120.0.0.0'
});

4. 实现日志轮转(避免文件过大)
当日志文件过大时,需通过轮转分割文件,防止磁盘空间耗尽。可使用winston-daily-rotate-file等工具,配置如下:

const DailyRotateFile = require('winston-daily-rotate-file');
const transport = new DailyRotateFile({
  filename: 'application-%DATE%.log', // 按日期命名(如application-2025-10-12.log)
  datePattern: 'YYYY-MM-DD',          // 日期格式
  zippedArchive: true,                // 压缩旧日志
  maxSize: '20m',                     // 单个文件最大20MB
  maxFiles: '14d'                     // 保留14天内的日志
});
const logger = winston.createLogger({
  transports: [transport]
});

5. 敏感信息脱敏
日志中避免记录用户密码、信用卡号、身份证号等敏感数据,防止泄露。可通过以下方式处理:

const sanitize = require('sanitize-html');
app.post('/login', (req, res) => {
  const sanitizedBody = sanitize(req.body, {
    allowedTags: [],
    allowedAttributes: {}
  });
  logger.info('Login attempt:', { userId: req.body.userId, password: '*****' });
});

6. 集成监控与报警
将日志与监控系统(如Prometheus、Grafana、Sentry)集成,实现实时监控和异常报警:

const Sentry = require('@sentry/node');
Sentry.init({ dsn: 'your-sentry-dsn' });
app.use((err, req, res, next) => {
  logger.error('Unhandled error:', { error: err.message, stack: err.stack });
  Sentry.captureException(err); // 上报到Sentry
  res.status(500).send('Internal Server Error');
});

7. 全链路日志追踪(Request ID)
在微服务或分布式系统中,使用唯一requestId标记每个请求,跟踪其在整个链路中的流动(如从API网关到数据库)。通过requestId可快速关联不同服务的日志,定位跨服务问题。示例如下:

const { v4: uuidv4 } = require('uuid');
app.use((req, res, next) => {
  const requestId = req.headers['x-request-id'] || uuidv4(); // 获取或生成requestId
  req.requestId = requestId;
  logger.info(`Request started: ${requestId}`, { method: req.method, url: req.url });
  res.on('finish', () => {
    logger.info(`Request completed: ${requestId}`, { status: res.statusCode });
  });
  next();
});

8. 异步日志记录(避免阻塞主线程)
日志写入是IO密集型操作,应使用异步方式避免阻塞应用主线程。多数日志库(如Winston、Pino)默认支持异步,例如Winston的transports.File会自动使用异步写入,确保日志记录不影响请求处理性能。

0
看了该问题的人还看了