JavaScript 应用程序中的日志记录:初学者最佳实践
日志记录是任何应用程序调试和监控的基础。没有高质量的日志,当出现问题时,您将如同"大海捞针"。在本文中,我们将介绍适用于小型项目和生产环境的 JavaScript (Node.js) 日志记录最佳实践。
1. 为什么不应依赖 console.log?
许多初学者开发者对所有情况都使用 console.log。这在开发阶段很方便,但在生产环境中,这种方法会导致问题:
- 没有日志级别 — 您无法将错误与信息消息区分开来。
- 难以管理输出 — 无法禁用特定模块的日志。
- 性能较差 —
console.log中的对象序列化可能开销很大。 - 缺乏结构 — 日志没有统一格式(JSON、时间、级别)。
相反,应使用专门的库。以下是一个使用 Winston 的简单但正确的示例:
// logger.jsconst winston = require('winston');
const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), ],});
if (process.env.NODE_ENV !== 'production') { logger.add(new winston.transports.Console({ format: winston.format.simple(), }));}
module.exports = logger;2. 日志级别:何时使用什么
标准日志级别(按严重性递增):debug、info、warn、error。理解何时应用哪个级别很重要:
- debug — 供开发人员使用的详细信息(变量值、系统状态)。在生产环境中禁用。
- info — 应用程序的正常事件(请求已处理、用户已注册)。
- warn — 潜在危险情况(内存不足、API 已弃用)。
- error — 需要干预的错误(异常、数据库故障)。
使用 Pino 库(Node.js 最快的库)的正确用法示例:
const pino = require('pino');
const logger = pino({ level: process.env.LOG_LEVEL || 'info', transport: { target: 'pino-pretty', options: { colorize: true } }});
// 使用logger.info({ userId: 123 }, '用户已登录系统');logger.error(new Error('数据库连接错误'), '严重错误');logger.debug('变量 x 的值 = 42'); // 如果 level = 'info',则不会输出3. 结构化日志记录:JSON 和上下文
不要使用文本字符串,而应使用 结构化日志(通常是 JSON)。这允许:
- 使用工具(ELK、Graylog)轻松解析日志。
- 添加上下文(请求 ID、用户、版本)。
- 过滤和聚合数据。
带上下文的结构化日志示例:
const logger = require('./logger');
app.use((req, res, next) => { req.requestId = uuidv4(); next();});
app.get('/api/users', async (req, res) => { logger.info({ requestId: req.requestId, method: req.method, url: req.originalUrl, ip: req.ip }, '传入请求');
try { const users = await getUsers(); logger.info({ requestId: req.requestId, count: users.length }, '已获取用户'); res.json(users); } catch (err) { logger.error({