mcpskills.net
技能MCP智能体提示词
mcpskills.net — A curated directory of AI agent Skills and MCP servers
TermsPrivacy
← 返回技能
Development

可观测性与埋点

为代码添加埋点,使生产环境中的行为可见且可诊断。在添加日志、指标、链路追踪或告警时使用。

作者:Addy Osmani仓库 →来源 →

无法观测的代码就是无法运维的代码。埋点应当与功能一同编写,而不是上线后再补充。

使用场景

  • 构建任何将在生产环境运行的功能
  • 新增服务、端点、后台任务或外部集成
  • 某次生产事故诊断耗时过长
  • 设置或审查告警规则

流程

1. 在埋点之前先定义“正常工作”的含义

在添加任何埋点之前,先写下一名值班工程师将会提出的 2–4 个问题:

FEATURE: checkout payment retry
QUESTIONS ON-CALL WILL ASK:
1. What fraction of payments succeed on first attempt vs after retry?
2. When a payment fails permanently, why?
3. Is the payment provider slower than usual?
→ Every signal below must help answer one of these.

2. 为每个问题选择正确的信号

| 信号 | 回答的问题 | 成本特征 | |---|---|---| | 结构化日志 | “这个具体场景里发生了什么?” | 按事件计 | | 指标 | “总体上多频繁 / 多快?” | 每序列固定 | | 链路追踪 | “时间消耗在跨服务的哪一环?” | 按请求计 |

指标告诉你出了问题,链路追踪告诉你问题出在哪里,日志告诉你为什么。

3. 结构化日志

记录事件,而非散文:

// BAD: string interpolation — unqueryable
logger.info(`Payment ${id} failed for user ${userId} after ${n} retries`);

// GOOD: stable event name + structured fields
logger.warn({
  event: 'payment_failed',
  paymentId: id,
  provider: 'stripe',
  errorCode: err.code,
  attempt: n,
}, 'payment failed');

日志级别:

| 级别 | 含义 | 值班动作 | |---|---|---| | error | 不变量被破坏;可能需要有人处理 | 调查 | | warn | 已降级但已被处理 | 关注趋势 | | info | 重要业务事件 | 无 | | debug | 诊断细节 | 生产环境关闭 |

关联 ID(Correlation ID)是必需的:

app.use((req, res, next) => {
  req.id = req.headers['x-request-id'] ?? crypto.randomUUID();
  req.log = logger.child({ requestId: req.id });
  res.setHeader('x-request-id', req.id);
  next();
});

4. 指标

对于请求驱动的服务,在每个端点上埋设 RED 指标:速率(Rate)、错误(Errors)、时延(Duration)。

import { Histogram } from 'prom-client';

const httpDuration = new Histogram({
  name: 'http_request_duration_seconds',
  help: 'HTTP request duration',
  labelNames: ['method', 'route', 'status_class'],
  buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
});

高基数(Cardinality)是失败的根源。 切勿将用户 ID、原始 URL 或错误信息用作标签。

永远不要追踪平均值,始终追踪百分位。

5. 分布式链路追踪

使用 OpenTelemetry——它是厂商中立的标准:

import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  serviceName: 'checkout-service',
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

6. 告警

针对用户能感受到的症状告警,而非针对原因:

SYMPTOM (page-worthy):           CAUSE (dashboard, not a page):
error rate > 1% for 5 min        CPU at 85%
p99 latency > 2s                 one pod restarted
queue age > 10 min               disk at 70%

每条告警的规则:

  1. 它必须是可处置的。 如果应对方式是“忽略它”,那就删掉这条告警。
  2. 它要链接到一份运维手册(runbook)。
  3. 它要有由 SLO 论证的阈值和持续时间。

验证

为功能埋点之后:

  • [ ] 值班问题已写下,且每个信号都对应到其中一个问题
  • [ ] 所有日志输出均为结构化(JSON)并带有关联 ID
  • [ ] 任何日志行中都没有密钥或未脱敏的 PII
  • [ ] 每个新端点都有 RED 指标
  • [ ] 时延以直方图记录;p95/p99 可查询
  • [ ] 单个请求可以在链路追踪 UI 中端到端追踪
  • [ ] 每条新告警都基于症状并带有运维手册链接
  • [ ] 仅凭遥测数据即可定位在预发环境中诱发的故障