示例说明
不同级别日志的消费路径天然不同:全量日志上 stdout 交给采集器,错误日志需要立即可检索、可告警。Pino 的 transports 数组让一行日志同时进入多个目的地,每条传输器可以设独立的级别门槛——错误传输器只收 error 及以上,既省索引成本又保证告警延迟。开发态与生产态的传输器配置在此处分流。
技术要点
- 多传输器并行分发同一行日志
- 每个传输器可独立设置级别门槛
- 环境分支切换开发与生产配置
代码解读
生产分支的两个传输器分别把 info 级写向 stdout 文件描述符、error 级批量送进 Elasticsearch 专用索引,flushInterval 控制批量刷新窗口;开发分支只剩彩色美化控制台输出。base 字段给全部日志行附加服务与区域维度。unref 的心跳定时器不阻塞进程退出。
使用建议
传输器跑在工作线程,进程退出前要 flush。Elasticsearch 写入失败要有兜底防止静默丢日志。索引按日期滚动控制体积。
代码示例
import { pino } from 'pino';
const isProd = process.env.NODE_ENV === 'production';
const logger = pino({
level: process.env.LOG_LEVEL ?? 'info',
base: { service: 'billing', region: 'eu-1' },
transports: isProd
? [
{
level: 'info',
target: 'pino/file',
options: { destination: 1, mkdir: false },
},
{
level: 'error',
target: 'pino-elasticsearch',
options: {
node: 'http://elastic:9200',
index: 'billing-errors',
flushInterval: 2000,
},
},
]
: [
{
target: 'pino-pretty',
options: { colorize: true, translateTime: 'SYS:HH:MM:ss' },
},
],
});
logger.info({ invoiceId: 'inv-9', amount: 4200 }, 'invoice settled');
logger.warn({ retries: 2 }, 'settlement retried');
logger.error({ invoiceId: 'inv-10', reason: 'gateway timeout' }, 'settlement failed');
setInterval(() => {
logger.debug('heartbeat');
}, 30_000).unref();