关于 monitoring-observability
面向服务工程师的监控与可观测性技能,提供遥测配置和运维检查指导。内容涵盖 OpenTelemetry、Prometheus 指标、结构化日志、告警规则及常见可观测性问题。
主要功能
- 01配置 OpenTelemetry 与自动埋点
- 02添加自定义跨度和指标
- 03采集 Prometheus 指标
- 04结构化日志与敏感信息脱敏
- 05告警规则与 SLO 检查
- 06可观测性反模式检查清单
适用场景
- 01为服务添加追踪和指标
- 02暴露并采集 Prometheus 指标
- 03对应用日志中的机密信息脱敏
- 04围绕服务错误率和延迟创建告警
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill monitoring-observability安装后在 Claude Code 中输入/monitoring-observability确认已加载。
详细介绍
监控与可观测性
OpenTelemetry 配置
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg";
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
const sdk = new NodeSDK({
serviceName: "order-service",
traceExporter: new OTLPTraceExporter({
url: "http://otel-collector:4318/v1/traces",
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: "http://otel-collector:4318/v1/metrics",
}),
exportIntervalMillis: 15000,
}),
instrumentations: [
new HttpInstrumentation(),
new PgInstrumentation(),
],
});
sdk.start();
process.on("SIGTERM", () => sdk.shutdown());
自定义 Span 和指标
import { trace, metrics, SpanStatusCode } from "@opentelemetry/api";
const tracer = trace.getTracer("order-service");
const meter = metrics.getMeter("order-service");
const orderCounter = meter.createCounter("orders.created", {
description: "Number of orders created",
});
const orderDuration = meter.createHistogram("orders.processing_duration_ms", {
description: "Order processing duration in milliseconds",
unit: "ms",
});
async function createOrder(input: CreateOrderInput) {
return tracer.startActiveSpan("createOrder", async (span) => {
try {
span.setAttributes({
"order.customer_id": input.customerId,
"order.item_count": input.items.length,
});
const start = performance.now();
const order = await db.order.create({ data: input });
orderCounter.add(1, { status: "success" });
orderDuration.record(performance.now() - start);
span.setStatus({ code: SpanStatusCode.OK });
return order;
} catch (error) {
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
orderCounter.add(1, { status: "error" });
throw error;
} finally {
span.end();
}
});
}
Prometheus 指标
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "api-servers"
static_configs:
- targets: ["api-1:9090", "api-2:9090"]
metrics_path: /metrics
- job_name: "node-exporter"
static_configs:
- targets: ["node-exporter:9100"]
import { collectDefaultMetrics, Counter, Histogram, Registry } from "prom-client";
const registry = new Registry();
collectDefaultMetrics({ register: registry });
const httpRequestDuration = new Histogram({
name: "http_request_duration_seconds",
help: "HTTP request duration in seconds",
labelNames: ["method", "route", "status"],
buckets: [0.01, 0.05, 0.1, 0.5, 1, 5],
registers: [registry],
});
app.use((req, res, next) => {
const end = httpRequestDuration.startTimer();
res.on("finish", () => {
end({ method: req.method, route: req.route?.path ?? req.path, status: res.statusCode });
});
next();
});
app.get("/metrics", async (req, res) => {
res.set("Content-Type", registry.contentType);
res.end(await registry.metrics());
});
结构化日志
import pino from "pino";
const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
formatters: {
level: (label) => ({ level: label }),
},
redact: ["req.headers.authorization", "password", "token"],
});
function requestLogger(req, res, next) {
const start = Date.now();
res.on("finish", () => {
logger.info({
method: req.method,
url: req.url,
status: res.statusCode,
duration_ms: Date.now() - start,
trace_id: req.headers["x-trace-id"],
});
});
next();
}
告警规则
groups:
- name: api-alerts
rules:
- alert: HighErrorRate
expr: rate(http_request_duration_seconds_count{status=~"5.."}[5m]) / rate(http_request_duration_seconds_count[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "Error rate above 5% for {{ $labels.route }}"
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 2
for: 10m
labels:
severity: warning
反模式
- 记录敏感数据(密码、令牌、个人身份信息),且未进行脱敏
- 在日志消息中使用字符串插值,而不是结构化字段
- 在指标标签中使用无界基数(例如,将用户 ID 用作标签)
- 未使用共享的 Trace ID 关联日志和追踪信息
- 未了解根本原因就针对症状(如 CPU 使用率过高)发出告警
- 构建仪表板前未定义 SLO
检查清单
- 已初始化 OpenTelemetry SDK,并为 HTTP、数据库和消息传递配置自动检测
- 已为业务关键操作添加自定义 Span
- 指标使用有界标签基数
- 使用结构化日志,以 JSON 格式输出并对机密信息进行脱敏
- 已在服务边界之间传递追踪上下文
- 告警规则基于 SLO(错误率、延迟百分位数)
- 仪表板按服务展示 RED 指标(请求率、错误数、耗时)
- 已配置日志保留和轮转策略
评论
支持 Markdown