Node.js 服务如何设计结构化日志和可观测性?
简化版
Node.js 服务日志应使用结构化 JSON,统一包含时间、级别、traceId、接口、耗时、错误码等字段,并与 metrics、tracing 结合。可观测性的目标不是多打日志,而是能快速回答“哪里慢、哪里错、影响多大”。
详细版
结构化日志比纯文本更适合检索和聚合。
logger.info({
traceId,
method: req.method,
path: req.path,
status: res.statusCode,
durationMs
}, 'request finished')
服务可观测性通常由三类信号组成:日志 logs、指标 metrics、链路 tracing。日志看细节,指标看趋势,链路看调用路径。Node.js 项目还要避免同步写日志阻塞事件循环,并注意脱敏。
完整版教学
一、日志不是越多越好,而是要能查
线上事故时,你需要快速定位某个请求发生了什么。 如果日志只是散乱文本,检索和聚合会很痛苦。 结构化日志把关键字段拆出来,方便按 traceId、用户、接口、错误码过滤。
{
"level": "info",
"traceId": "abc123",
"path": "/api/order",
"status": 200,
"durationMs": 87
}
假设一分钟 10 万行日志,纯文本里搜“订单失败”很不稳定。
结构化字段能直接查询 path=/api/order AND status>=500。
二、请求日志要覆盖入口、结果和耗时
HTTP 服务至少应记录请求方法、路径、状态码、耗时、traceId、客户端 IP 和错误信息。 不要只在报错时打日志。 成功请求的耗时分布同样重要。
app.use((req, res, next) => {
const start = Date.now()
res.on('finish', () => {
logger.info({
method: req.method,
path: req.path,
status: res.statusCode,
durationMs: Date.now() - start
}, 'request finished')
})
next()
})
| 字段 | 作用 |
|---|---|
traceId | 串起一次请求 |
path | 定位接口 |
status | 判断结果 |
durationMs | 分析性能 |
errorCode | 聚合业务错误 |
如果接口 P99 从 200ms 变成 2s,日志和指标都应该能反映出来。
三、traceId 是串联调用链的线
一次请求可能经过 Node BFF、Java 服务、数据库和第三方支付。 没有 traceId,每层日志都像孤岛。 入口层应生成或透传 traceId,并在下游请求头里继续传递。
Browser
-> Node BFF traceId=abc
-> User Service traceId=abc
-> Payment Service traceId=abc
可以配合 AsyncLocalStorage 在 Node 内部自动带上 traceId。
对外调用时把它写入 x-trace-id 或标准 trace header。
四、metrics 用来看趋势和告警
日志适合查单个请求,指标适合看整体趋势。 常见指标包括 QPS、错误率、延迟分位数、事件循环延迟、内存、CPU、连接池状态。 告警应建立在指标上,而不是靠人工翻日志。
RED 指标:
Rate 请求速率
Errors 错误数量或比例
Duration 延迟分布
假设错误率 5 分钟内从 0.1% 升到 5%,应该自动告警。 如果只靠日志,可能等用户反馈才发现。
五、tracing 用来看跨服务路径
分布式链路追踪能展示请求经过哪些服务,每段耗时多少,哪里失败。 OpenTelemetry 是常见标准。 Node.js 服务可以通过自动 instrumentation 或手动 span 记录关键步骤。
trace abc
├─ HTTP /api/order 300ms
│ ├─ Redis get 8ms
│ ├─ User RPC 40ms
│ └─ Order DB 220ms
这个图一看就知道瓶颈在 Order DB。 没有 tracing 时,你可能要在多个系统里手动拼时间线。
六、日志要异步、高性能且脱敏
Node.js 主线程怕阻塞。 日志库应尽量使用高性能异步输出,例如 pino 这类 JSON logger。 同时必须脱敏手机号、身份证、token、密码和密钥。
记忆钩子:日志讲故事,指标看体温,链路画路线;三者合起来才叫可观测。
只打 console.log 不等于可观测。 能定位、能聚合、能告警、能保护隐私,才接近生产要求。
七、常见误区与追问
- 误区:日志越详细越好。 过量日志会增加成本和噪声,关键是结构化字段和采样策略。
- 误区:有日志就不需要指标。 日志查细节,指标做趋势和告警,两者职责不同。
- 误区:traceId 只在入口日志里有用。 它要贯穿下游服务和内部日志,才能串起整条链路。
- 追问:哪些字段必须脱敏? token、密码、手机号、身份证、银行卡、密钥和敏感业务字段。
- 追问:Node 日志为什么关注性能? 同步或过量日志会阻塞事件循环,影响请求延迟。
- 追问:可观测性三件套是什么? logs、metrics、traces,分别看细节、趋势和调用路径。
八、加强记忆
可观测性题按“三信号”答:结构化日志记录请求细节,metrics 提供趋势和告警,tracing 串联跨服务路径。Node 里特别注意 traceId 传播、异步日志性能和敏感字段脱敏。