Node系列 · ORM:log4js 日志记录

Node系列 · ORM:log4js 日志记录

生产环境不能用 console.log------它没法分级别、没法分类、没法按大小切分文件、没法自动清理。本章讲清楚 log4js 的核心概念和按环境配置的实战。

一、为什么不用 console.log

维度 console.log log4js
级别控制 ✅ trace / debug / info / warn / error / fatal
分类 ✅ category(按模块拆分日志)
输出目标 仅 stdout ✅ 控制台 / 文件 / 网络 / 数据库
文件切分 ✅ 按大小 / 日期
自动清理 log4js 自动管理
性能 阻塞 stdout 异步缓冲,不阻塞事件循环

::: tip

console.log 永远不是生产日志方案 。它没法分类、没法分级、还会在高并发下阻塞事件循环(stdout 同步写入)。

:::

二、log4js 三大核心概念

2.1 级别(level)

从低到高:

级别 用途
trace 最详细的调试信息(一般关闭)
debug 调试信息
info 正常运行日志
warn 警告(潜在问题)
error 错误(功能受影响)
fatal 致命(进程退出)

设置 level: 'warn' 后,只有 warn / error / fatal 会输出。

2.2 分类(category)

按模块 / 功能划分的日志命名空间:

javascript:log4js-basic.js 复制代码
log4js.getLogger('http');    // HTTP 请求日志
log4js.getLogger('db');      // 数据库日志
log4js.getLogger('user');    // 用户模块日志
log4js.getLogger('default'); // 默认日志(不分类时用)

每个 category 可以单独配置级别和输出目标。

2.3 输出源(appender)

日志写到哪里:

appender 类型 输出目标
console 控制台 stdout / stderr
file 单个文件
dateFile 按日期切分(如 app.2024-08-15.log
fileSync 同步写文件(启动期用)
tcp 远程日志服务器
gelf Graylog 扩展日志格式

每个 appender 还可指定 layout(输出格式):

layout 格式
pattern 自定义模板字符串
colored 带 ANSI 颜色(开发用)
json JSON 格式(机器解析)

三、安装与基础使用

bash 复制代码
npm install log4js
javascript:log4js-basic.js 复制代码
const log4js = require('log4js');

log4js.configure({
  appenders: { console: { type: 'console' } },
  categories: { default: { appenders: ['console'], level: 'info' } },
});

const logger = log4js.getLogger();

logger.info('服务启动');
logger.warn('配置项缺失');
logger.error('请求失败', err);
bash 复制代码
$ node app.js
[2024-08-15T14:30:00.000] [INFO] default - 服务启动

四、按环境配置

4.1 配置代码

javascript:log4js-config.js 复制代码
const path = require('path');
const log4js = require('log4js');

const isDev = process.env.NODE_ENV !== 'production';

log4js.configure({
  appenders: {
    // 控制台:开发期彩色
    consoleOut: {
      type: 'console',
      layout: { type: 'colored' },
    },
    // 按日期切分文件
    appFile: {
      type: 'dateFile',
      filename: path.join('logs', 'app.log'),
      pattern: 'yyyy-MM-dd',
      // 文件名格式:app.2024-08-15.log
      compress: true,
    },
    // 错误单独一个文件
    errorFile: {
      type: 'file',
      filename: path.join('logs', 'error.log'),
      // 旧文件超 10MB 自动备份
      maxLogSize: 10 * 1024 * 1024,
      backups: 5,
    },
  },
  categories: {
    default: {
      appenders: isDev ? ['consoleOut'] : ['appFile', 'errorFile'],
      level: isDev ? 'debug' : 'info',
    },
    http: {
      appenders: ['appFile'],
      level: 'info',
    },
    db: {
      appenders: ['appFile'],
      level: 'warn',
    },
  },
});

module.exports = log4js;

4.2 各级别模块用不同 logger

javascript:use-categories.js 复制代码
const log4js = require('log4js');

const httpLogger = log4js.getLogger('http');
const dbLogger = log4js.getLogger('db');

httpLogger.info('GET /api/users 200');
dbLogger.warn('慢查询:耗时 1200ms');

五、Express 中间件

log4js 提供 Express 中间件自动记录请求:

javascript:express-middleware.js 复制代码
const log4js = require('log4js');
const express = require('express');

const app = express();

// 自动记录每个 HTTP 请求
app.use(log4js.connectLogger(log4js.getLogger('http'), {
  level: 'auto',                    // 5xx → error,4xx → warn,其他 → info
  format: (req, res, format) => format(
    ':remote-addr - :method :url :status :res[content-length] - :response-time ms'
  ),
}));

app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

输出示例:

复制代码
[INFO] http - 127.0.0.1 - GET /api/users 200 42 - 12 ms
[ERROR] http - 127.0.0.1 - POST /api/users 500 89 - 234 ms

六、关闭与刷新

javascript:shutdown.js 复制代码
// 应用退出前优雅关闭
process.on('SIGTERM', () => {
  log4js.shutdown(() => {
    console.log('日志系统已关闭');
    process.exit(0);
  });
});

shutdown() 等待所有缓冲日志写完再回调------避免最后几条日志丢失。

七、配置模板

javascript:log4js-template.js 复制代码
// config/log4js.js
const path = require('path');
const log4js = require('log4js');

const LOG_DIR = path.resolve(__dirname, '../logs');
const isDev = process.env.NODE_ENV !== 'production';

log4js.configure({
  appenders: {
    // 开发期:控制台彩色输出
    devConsole: {
      type: 'console',
      layout: { type: 'colored' },
    },
    // 生产期:分文件 + 错误单独
    prodAll: {
      type: 'dateFile',
      filename: path.join(LOG_DIR, 'app.log'),
      pattern: 'yyyy-MM-dd',
      compress: true,
    },
    prodError: {
      type: 'levelFilter',
      // level: 'error' 之后的级别都写这个文件
      appender: {
        type: 'file',
        filename: path.join(LOG_DIR, 'error.log'),
        maxLogSize: 10 * 1024 * 1024,
        backups: 5,
      },
      level: 'error',
    },
  },
  categories: {
    default: {
      appenders: isDev ? ['devConsole'] : ['prodAll', 'prodError'],
      level: isDev ? 'debug' : 'info',
    },
    http: {
      appenders: isDev ? ['devConsole'] : ['prodAll'],
      level: 'info',
    },
    db: {
      appenders: isDev ? ['devConsole'] : ['prodAll'],
      level: 'warn',
    },
  },
});

module.exports = log4js;

八、最佳实践

场景 推荐
开发期 控制台 + level: 'debug'
生产期 文件 + 错误单独 + level: 'info'
HTTP 请求 connectLogger 自动记录
慢查询 / 错误 单独 category + level: 'warn'
敏感字段 日志前脱敏(密码、token、手机号中间四位)
应用退出 log4js.shutdown 刷写缓冲
文件清理 dateFile + compress: true 自动管理

::: warning

永远不要把密码、token、完整手机号、身份证号写日志。即使是错误日志,也要先脱敏:

javascript:log4js-template.js 复制代码
logger.info('登录失败', { email: user.email, ip: req.ip });
// ❌ logger.info('登录失败', { password });  // 永远不要

:::

九、与其他日志库对比

风格 性能 适合
log4js 配置式 中(同步阻塞风险用 stream 解决) 传统项目 / 文件输出
pino JSON 输出 极快(异步) 性能敏感 / 日志聚合
winston 配置式 老牌项目
bunyan JSON 输出 微服务 / 日志聚合

::: tip

新项目推荐 pino ------JSON 输出 + 异步 = 不阻塞事件循环 + 易聚合到 ELK / Loki。但 log4js 在国内中小项目里依然主流,本文按 log4js 展开。

:::

十、小结

  • 生产环境永远用日志库,不用 console.log
  • 三大核心:level(级别)/ category(分类)/ appender(输出源)
  • dateFile appender 按日期切分日志;file + maxLogSize 按大小
  • 按环境配置:开发期控制台 + debug;生产期文件 + info
  • Express 用 connectLogger 自动记录请求日志
  • 敏感字段永远不写日志(密码、token 等)
  • 应用退出前 log4js.shutdown() 刷写缓冲
相关推荐
BreezeJiang3 小时前
别把 WebSocket 当成一门新协议学:搞懂"借 HTTP 握手",双端 Demo 和跨域就都通了
websocket·node.js
65岁退休Coder6 小时前
把 Agent 框架拆开:PI 开发生产级 Harness
后端·node.js·agent
65岁退休Coder1 天前
PI Agent 开发一个生产级 Harness
后端·node.js·agent
szephyr1 天前
WebSocket 实战:心跳、断线重连、鉴权,一次讲清
前端·websocket·node.js·长连接·实时通信
秋秋小事1 天前
node postgreSQL的select与include
node.js
ID34610744201 天前
【课程设计】基于Spring Boot+Vue的游戏账号租赁系统的设计与实现-计算机毕设 附源码50345
javascript·vue.js·spring boot·python·node.js·php·课程设计
柚yuzumi1 天前
彻底搞懂 JavaScript 类型转换:显式转换、隐式转换与 ToPrimitive
前端·javascript·node.js
cpolar技术支持1 天前
本地登录正常,公网却掉线?Express Session 经 cpolar HTTPS 访问的 Cookie 排障实战
node.js·express·cpolar·cookie·session
秋秋小事1 天前
node prisma+postgreSQL数据库事务
node.js
badhope1 天前
C++、Node.js、Python 写最小 HTTP 服务谁快?我实测了 6 万次请求
node.js