在《上篇》中,我们深入探讨了"Pino极速生成 + PM2守护落盘 + OpenSearch集中分析"的黄金日志架构。理论固然精妙,但真正的价值在于落地。
本文将手把手带你完成这套架构的代码配置,彻底打通从 Node.js 底层日志打印,到海量日志上云检索的完整闭环。
第一步:Node.js 端的极速日志输出 (Pino 配置)
在实际开发中,我们对日志的核心诉求是:本地开发时赏心悦目(彩色文本),线上生产时高效规范(纯 JSON) 。
首先,安装必要的依赖:
css
npm install pino
npm install pino-pretty --save-dev
接下来,在项目中创建一个 logger.js 文件,封装 Pino 实例。通过判断 NODE_ENV 环境变量,我们可以优雅地实现环境隔离:
javascript
// logger.js
const pino = require('pino');
// 判断是否为生产环境
const isProduction = process.env.NODE_ENV === 'production';
const logger = pino({
// 生产环境只记录 info 及以上级别,开发环境开启 debug 方便排错
level: isProduction ? 'info' : 'debug',
// 核心逻辑:本地开发使用 pino-pretty 格式化,生产环境则直接输出极速 JSON
transport: isProduction
? undefined
: {
target: 'pino-pretty',
options: {
colorize: true, // 开启色彩高亮
translateTime: 'SYS:yyyy-mm-dd HH:MM:ss', // 转换时间戳为可读格式
ignore: 'pid,hostname' // 本地调试时隐藏冗余的系统信息
}
},
// 统一生产环境下的 JSON 时间戳格式,便于 OpenSearch 建立精确的时间轴索引
timestamp: pino.stdTimeFunctions.isoTime,
});
module.exports = logger;
在业务代码中,你只需直接引入并使用即可:
php
// app.js
const logger = require('./logger');
logger.info({ user_id: 1024, action: 'login' }, '用户登录成功');
logger.error(new Error('Database Timeout'), '连接数据库失败');
第二步:PM2 的无侵入式进程守护与日志接管
线上环境不能裸跑 Node.js,我们需要 PM2 来榨干多核 CPU 性能并接管标准输出(stdout/stderr)。
在项目根目录创建 PM2 的生态配置文件 ecosystem.config.js:
java
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'my-node-api', // 你的微服务名称
script: './app.js', // 启动入口文件
instances: 'max', // 开启集群模式(Cluster Mode),打满 CPU 核心
exec_mode: 'cluster',
// === 日志接管核心配置 ===
out_file: './logs/app-out.log', // 业务正常 JSON 日志存放路径
error_file: './logs/app-err.log',// 异常崩溃日志存放路径
merge_logs: true, // 将多个 Cluster 进程的日志安全地合并到同一文件
// 【避坑指南】这里必须设为 false!
// Pino 已经在内部生成了高性能的 JSON 格式时间戳。
// 如果 PM2 再往行首追加纯文本时间,会破坏整行的 JSON 结构,导致后续解析失败。
time: false,
env: {
NODE_ENV: 'development',
},
env_production: {
NODE_ENV: 'production',
}
}
]
};
配置完成后,使用 pm2 start ecosystem.config.js --env production 一键启动你的高可用集群。
第三步:扼杀爆盘隐患:PM2 日志自动切分
PM2 默认会将日志无限追加到同一个文件中。对于高并发业务,如果不加限制,短短几天内几十 GB 的日志就能把服务器硬盘撑爆。
借助 pm2-logrotate 插件,我们可以轻松实现日志的自动化轮转。直接在服务器终端执行以下全局命令:
bash
# 安装 PM2 日志轮转插件
pm2 install pm2-logrotate
# 设置单个日志文件的体积上限为 50MB
pm2 set pm2-logrotate:max_size 50M
# 仅保留最近的 14 个历史日志文件,旧文件自动清理
pm2 set pm2-logrotate:retain 14
# 每天凌晨 0 点执行一次强制切割
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'
第四步:日志上云:使用 Fluent Bit 实时搬运至 OpenSearch
目前为止,完美的 JSON 日志已经安全落盘到 ./logs/app-out.log。最后一步,我们需要一个轻量级的"搬运工"将它们实时投递到 OpenSearch 引擎中。
这里推荐使用内存占用极低的 Fluent Bit 。它的配置(fluent-bit.conf)逻辑非常清晰:监听文件 ➡️ 声明为 JSON ➡️ 输出到 OpenSearch。
perl
[INPUT]
Name tail
# 监听 PM2 持续写入的日志文件
Path /your/project/path/logs/app-out.log
# 告诉 Fluent Bit 直接以 JSON 格式解析数据,提取字段
Parser json
Tag node_api_logs
[OUTPUT]
# 使用 OpenSearch 原生输出插件
Name opensearch
Match node_api_logs
# 配置你的 OpenSearch 集群端点
Host search-my-domain.us-east-1.opensearch.amazonaws.com
Port 443
TLS On
# 动态索引命名规则(按天分表),例如:node-api-logs-2023.10.25
Index node-api-logs-%Y.%m.%d
# 权限认证(如有)
HTTP_User admin
HTTP_Passwd your_password
总结
至此,我们的代码实战闭环彻底完成。
当你在业务层敲下 logger.info() 的那一刻,数据会瞬间被 Pino 序列化为极速 JSON,被 PM2 无声无息地落盘并按天切割,随后立刻被 Fluent Bit 嗅探并推送到远端的 OpenSearch 集群。最终,研发团队可以在 OpenSearch Dashboards 中,享受毫秒级的全文检索和华丽的可视化监控大盘。
这不仅仅是一次代码配置的升级,更是服务端可观测性(Observability)的一次质的飞跃。