mcpField
M
monitoring-observability

monitoring-observability

github.com/rohitg00云与 DevOps2.8k191 次安装24 周前更新
代码仓库

关于 monitoring-observability

面向服务工程师的监控与可观测性技能,提供遥测配置和运维检查指导。内容涵盖 OpenTelemetry、Prometheus 指标、结构化日志、告警规则及常见可观测性问题。

主要功能

  1. 01配置 OpenTelemetry 与自动埋点
  2. 02添加自定义跨度和指标
  3. 03采集 Prometheus 指标
  4. 04结构化日志与敏感信息脱敏
  5. 05告警规则与 SLO 检查
  6. 06可观测性反模式检查清单

适用场景

  1. 01为服务添加追踪和指标
  2. 02暴露并采集 Prometheus 指标
  3. 03对应用日志中的机密信息脱敏
  4. 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