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() 刷写缓冲
相关推荐
FungLeo2 小时前
成为全栈·Go 后端篇·重写之前先锁基线:契约、Node 版本与行为清单
golang·node.js·go·openapi·契约测试·成为全栈
七夜zippoe3 小时前
Agent 网关设计:统一入口、智能路由与负载均衡
运维·ai·log4j·负载均衡·agent·网关设计
FungLeo21 小时前
成为全栈·Go 后端篇·契约一致性与差分测试:两套实现如何互相校验
golang·node.js·go·合约测试·差分测试·成为全栈·api兼容
月夏1 天前
前端第一次接自己的后端:mock 切真接口踩了 2 个坑,组件只改了一行 import
前端·后端·node.js
SEO_juper1 天前
Node.js 页面主题聚焦度检测:title 和正文各说各的,AI 也读不懂
开发语言·人工智能·node.js·seo·外贸独立站
SEO_juper2 天前
Node.js 重定向链检测工具:301 跳了几跳、有没有成环,一次看清
xml·开发语言·python·node.js·json·bash
king13598745502 天前
AI Agent 端云协同选型:Node.js 任务成本算例与权限检查清单(2027—2028 展望)
人工智能·ai·node.js·ai agent
居里先生7522 天前
PDF 批注到底存在文件的哪里?从 /Annots 讲到导出验证
node.js
MasonYyp3 天前
安装npm依赖仓库Verdaccio
前端·npm·node.js
编程的一拳超人4 天前
【元宝搜索开发者征文大赛】四语实战:Java/Python/Go/Node.js 构建 AI 搜索应用全攻略
java·python·golang·node.js·agent