在 Debian 上运行 Node.js 应用,日志看起来是小事,真正到了排障、定位性能问题和接入运维体系时,差别会非常明显。本文按照“从能用到好用”的顺序,拆开介绍 console.log、winston、pino、系统日志接入,以及用环境变量控制日志级别这几种方案,方便你根据应用规模、性能要求和运维方式选出合适做法。
开发调试阶段:先用 console.log 快速验证
如果你只是刚把服务跑起来,想确认请求有没有进来、启动是否正常,Node.js 自带的 console.log 依然是最省事的办法。它不需要额外安装依赖,写完就能看结果,适合开发期快速排查。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log('Request received at', new Date());
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
不过它的边界也很清楚:格式单一、没有等级区分、不方便落盘,也不适合后续集中收集。换句话说,console.log 更适合“先确认程序有没有按预期执行”,而不是长期承担生产日志任务。
进入生产环境后,优先考虑专业日志库
当应用开始进入多人协作、线上部署和长期维护阶段,日志通常需要同时满足分级、格式化、持久化和多目标输出等要求。这时候第三方日志库基本就是必选项,最常见的两类代表是 winston 和 pino。
为什么很多项目先选 winston
winston 的优势在于功能完整,支持控制台、文件、HTTP 等多种传输方式,适合需要较强可配置性的项目。先安装依赖:
npm install winston
下面这个示例同时把日志输出到控制台和文件:
const express = require('express');
const winston = require('winston');
const app = express();
// 配置winston
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console(),
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()
}));
}
app.get('/', (req, res) => {
logger.info('Request received at', new Date());
res.send('Hello World!');
});
app.listen(3000, () => {
logger.info('Server is running on port 3000');
});
这里有几个关键信息需要注意:
error.log只记录error级别日志;combined.log记录所有级别日志;- 非生产环境额外使用简单格式输出到控制台,方便实时查看。
如果你的重点是“输出到哪里、按什么格式、不同环境怎么区分”,winston 往往更顺手。
对吞吐量敏感时,可以考虑 pino
如果你的服务请求量大,或者希望尽量降低日志对性能的影响,pino 会更有吸引力。它的设计目标就是高性能,尤其适合生产环境中的高频日志输出场景。
安装命令:
npm install pino
基础用法如下:
const express = require('express');
const pino = require('pino');
const app = express();
// 配置pino
const logger = pino({
level: 'info'
});
app.get('/', (req, res) => {
logger.info('Request received at', { timestamp: new Date() });
res.send('Hello World!');
});
app.listen(3000, () => {
logger.info('Server is running on port 3000');
});
pino 默认输出 JSON,后续无论是写入文件,还是接到日志收集系统,都比较方便。和 winston 相比,它的吞吐量更高,但功能面相对精简,因此更适合把重点放在性能和结构化输出的项目。
需要统一纳管时,把日志接入 syslog
如果你的 Debian 服务器已经有现成的系统日志体系,希望 Node.js 应用日志直接进入系统日志服务统一归档,那么接入 syslog 会更符合运维习惯。文中的做法是给 winston 增加 winston-syslog 传输插件。
安装命令:
npm install winston-syslog
配置示例如下:
const express = require('express');
const winston = require('winston');
const SyslogTransport = require('winston-syslog').SyslogTransport;
const app = express();
// 配置winston
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new SyslogTransport({
host: 'localhost',
port: 514,
protocol: 'udp4'
})
]
});
app.get('/', (req, res) => {
logger.info('Request received at', new Date());
res.send('Hello World!');
});
app.listen(3000, () => {
logger.info('Server is running on port 3000');
});
按这个配置,日志会发送到本机 localhost 的 514 端口,使用 udp4 协议交给 syslog 服务处理。这里的前提也不能忽略:系统里必须已经配置并运行了对应的 syslog 守护进程,否则应用虽然能发日志,系统侧也接不到。
不同环境的日志粒度,建议交给环境变量
实际部署时,开发、测试、生产对日志详细程度的要求通常不同。把日志级别写死在代码里,后期调整会很麻烦;更实用的方式是通过环境变量动态控制。
const express = require('express');
const winston = require('winston');
const app = express();
// 配置winston
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
app.get('/', (req, res) => {
logger.info('Request received at', new Date());
res.send('Hello World!');
});
app.listen(3000, () => {
logger.info('Server is running on port 3000');
});
例如启动时设置 LOG_LEVEL=debug,就可以输出更细的调试信息;默认保持 info,则能避免生产环境被大量细碎日志刷屏。这种方式在容器化部署里尤其常见,因为它不需要改代码,只通过启动参数就能切换日志策略。
怎么选:按应用阶段和运维目标来定
如果你只是本地开发或临时验证逻辑,console.log 已经足够。需要文件落盘、日志分级和多路输出时,winston 更适合大多数常规项目。对性能更敏感、希望结构化输出更轻量时,可以优先看 pino。而当 Debian 服务器已经有成熟的日志归档链路,希望应用直接纳入系统统一管理,就可以把日志发往 syslog。

从维护成本看,一个比较稳妥的思路是:开发阶段先快速验证,进入生产后尽早切到专业日志库,再配合环境变量控制日志级别。这样既不会在前期过度设计,也能给后续排障和运维留出足够空间。













