mcpField
M
monitoring-setup

monitoring-setup

github.com/hieutrtr云与 DevOps842 次安装38 周前更新
代码仓库

关于 monitoring-setup

monitoring-setup 是面向 Python/FastAPI 服务的可观测性配置技能,指导设置指标、结构化日志、追踪、告警、健康检查和仪表板。它还要求将配置摘要写入 monitoring-config.md。

主要功能

  1. 01Prometheus 指标配置
  2. 02structlog 结构化日志
  3. 03OpenTelemetry 分布式追踪
  4. 04告警规则与阈值设计
  5. 05健康检查端点规划
  6. 06Grafana 仪表板结构

适用场景

  1. 01为 FastAPI 服务规划可观测性
  2. 02为 API 端点设计 RED 指标
  3. 03配置生产服务的告警规则
  4. 04整理并记录监控配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hieutrtr/ai1-skills --skill monitoring-setup

安装后在 Claude Code 中输入/monitoring-setup确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
alert-rules-template.yml
dashboard-template.json
logging-config-template.py
metrics-config-template.py

详细介绍

监控设置

适用场景

遇到以下情况时,启用此技能:

  • 为 Python/FastAPI 应用设置结构化日志记录
  • 配置 Prometheus 指标采集以及自定义计数器/直方图
  • 实现健康检查端点(存活和就绪)
  • 为生产服务设计告警规则和阈值
  • 创建用于服务监控的 Grafana 仪表板
  • 集成 Sentry 进行错误跟踪和性能监控
  • 使用 OpenTelemetry 实现分布式追踪
  • 审查或改进现有的可观测性覆盖范围

输出: 将可观测性配置摘要写入 monitoring-config.md,记录已设置的内容(指标、告警、仪表板、健康检查)。

请勿在以下情况下使用此技能:

  • 响应正在发生的生产事故(使用 incident-response)
  • 部署监控基础设施(使用 deployment-pipeline)
  • 编写应用业务逻辑(使用 python-backend-expert)
  • 配置 Docker 容器(使用 docker-best-practices)

说明

可观测性的四大支柱

每个生产服务都必须实现全部四大支柱。

┌─────────────────────────────────────────────────────────────────┐
│                    OBSERVABILITY                                │
├────────────────┬───────────────┬──────────────┬────────────────┤
│    METRICS     │   LOGGING     │   TRACING    │   ALERTING     │
│                │               │              │                │
│  Prometheus    │  structlog    │ OpenTelemetry│  Alert rules   │
│  counters,     │  structured   │ distributed  │  thresholds,   │
│  histograms,   │  JSON logs,   │ trace spans, │  notification  │
│  gauges        │  context      │ correlation  │  channels      │
├────────────────┴───────────────┴──────────────┴────────────────┤
│                    DASHBOARDS (Grafana)                         │
│        Visualize metrics, logs, and traces in one place        │
└─────────────────────────────────────────────────────────────────┘
支柱 1:指标(Prometheus)

对于请求驱动型服务,使用 RED 方法;对于资源,使用 USE 方法。

RED 方法(适用于每个 API 端点):

  • Rate —— 每秒请求数
  • Errors —— 每秒失败请求数
  • Duration —— 请求延迟分布

USE 方法(适用于基础设施资源):

  • Utilization —— 资源使用百分比(CPU、内存、磁盘)
  • Saturation —— 排队或等待的工作(连接池、队列深度)
  • Errors —— 错误事件(OOM 终止、连接失败)

需要采集的关键指标:

from prometheus_client import Counter, Histogram, Gauge, Info

# RED metrics
REQUEST_COUNT = Counter(
    "http_requests_total",
    "Total HTTP requests",
    labelnames=["method", "endpoint", "status_code"],
)

REQUEST_DURATION = Histogram(
    "http_request_duration_seconds",
    "HTTP request duration in seconds",
    labelnames=["method", "endpoint"],
    buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
)

# USE metrics
DB_POOL_USAGE = Gauge(
    "db_connection_pool_usage",
    "Database connection pool utilization",
    labelnames=["pool_name"],
)

DB_POOL_SIZE = Gauge(
    "db_connection_pool_size",
    "Database connection pool max size",
    labelnames=["pool_name"],
)

REDIS_CONNECTIONS = Gauge(
    "redis_active_connections",
    "Active Redis connections",
)

# Business metrics
ACTIVE_USERS = Gauge(
    "active_users_total",
    "Currently active users",
)

APP_INFO = Info(
    "app",
    "Application metadata",
)

用于自动采集指标的 FastAPI 中间件:

import time
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request

class PrometheusMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        method = request.method
        endpoint = request.url.path
        start_time = time.perf_counter()

        response = await call_next(request)

        duration = time.perf_counter() - start_time
        status_code = str(response.status_code)

        REQUEST_COUNT.labels(
            method=method, endpoint=endpoint, status_code=status_code
        ).inc()

        REQUEST_DURATION.labels(
            method=method, endpoint=endpoint
        ).observe(duration)

        return response

完整设置请参阅 references/metrics-config-template.py。

支柱 2:日志记录(structlog)

使用带有上下文信息的结构化 JSON 日志。生产环境中绝不使用 print() 或非结构化日志记录。

日志记录原则:

  1. 结构化 —— JSON 格式,可由机器解析
  2. 包含上下文 —— 每条日志都包含请求 ID、用户 ID、追踪 ID
  3. 分级 —— 使用恰当的日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)
  4. 可操作 —— 每条 WARNING/ERROR 日志都应指出需要调查的内容

日志级别及其适用场景:

级别适用场景示例
DEBUG详细的诊断信息,生产环境中禁用Processing item 42 of 100
INFO正常操作、重要事件User created, Payment processed
WARNING意外但已处理的情况Retry attempt 2 of 3, Cache miss
ERROR操作失败,需要关注Database query failed, External API timeout
CRITICAL系统级故障,需要立即处理Cannot connect to database, Out of memory

structlog 设置:

import structlog

structlog.configure(
    processors=[
        structlog.contextvars.merge_contextvars,
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.stdlib.PositionalArgumentsFormatter(),
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.StackInfoRenderer(),
        structlog.processors.format_exc_info,
        structlog.processors.UnicodeDecoder(),
        structlog.processors.JSONRenderer(),
    ],
    wrapper_class=structlog.stdlib.BoundLogger,
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True,
)

添加请求上下文:

from starlette.middleware.base import BaseHTTPMiddleware
import structlog
import uuid

class LoggingContextMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
        structlog.contextvars.clear_contextvars()
        structlog.contextvars.bind_contextvars(
            request_id=request_id,
            method=request.method,
            path=request.url.path,
        )
        response = await call_next(request)
        response.headers["X-Request-ID"] = request_id
        return response

完整设置请参阅 references/logging-config-template.py。

支柱 3:追踪(OpenTelemetry)

分布式追踪可跨服务边界关联日志和指标。

FastAPI 追踪设置:

from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

def setup_tracing(app, service_name: str = "backend"):
    resource = Resource.create({"service.name": service_name})
    provider = TracerProvider(resource=resource)

    exporter = OTLPSpanExporter(endpoint="http://otel-collector:4317")
    provider.add_span_processor(BatchSpanProcessor(exporter))

    trace.set_tracer_provider(provider)

    # Auto-instrument FastAPI, SQLAlchemy, Redis
    FastAPIInstrumentor.instrument_app(app)
    SQLAlchemyInstrumentor().instrument()
    RedisInstrumentor().instrument()

为业务逻辑添加自定义 Span:

tracer = trace.get_tracer(__name__)

async def process_order(order_id: str):
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)

        with tracer.start_as_current_span("validate_order"):
            await validate_order(order_id)

        with tracer.start_as_current_span("charge_payment"):
            result = await charge_payment(order_id)
            span.set_attribute("payment.status", result.status)

        with tracer.start_as_current_span("send_confirmation"):
            await send_confirmation(order_id)
支柱 4:告警

告警必须可执行。每条告警都应指出出了什么问题以及该怎么做。

告警设计原则:

  1. 仅针对影响用户的问题触发页面通知——不要针对非紧急警告触发页面通知
  2. 根据 SLO 设置阈值——不要使用随意设定的数字
  3. 避免告警疲劳——如果某条告警频繁触发却无需采取行动,就修复或移除它
  4. 包含操作手册链接——每条告警都应链接到修复指南
  5. 使用多窗口消耗速率——更快地检测问题,同时避免误报

典型 FastAPI 应用的告警阈值:

告警条件严重程度操作
错误率高http_requests_total{status=~"5.."} 在 5 分钟内 > 总请求数的 5%SEV2检查日志,考虑回滚
延迟高http_request_duration_seconds p99 在 5 分钟内 > 2sSEV3检查 DB 查询和依赖项
服务宕机健康检查连续 2 分钟失败SEV1重启、检查日志并升级处理
DB 连接数偏高连接池使用率在 5 分钟内 > 80%SEV3检查是否存在连接泄漏
DB 连接数严重偏高连接池使用率在 2 分钟内 > 95%SEV2重启应用并调查原因
内存使用率高容器内存使用率在 10 分钟内 > 85%SEV3检查是否存在内存泄漏
磁盘空间不足磁盘使用率 > 85%SEV3清理日志并扩展卷
证书即将过期SSL 证书将在 < 14 天后过期SEV4续订证书

请参阅 references/alert-rules-template.yml 中的 Prometheus 告警规则。

健康检查端点

每个服务都必须公开两个健康检查端点。

**存活状态(/health):**进程是否正在运行?如果应用处于存活状态,则返回 200。

**就绪状态(/health/ready):**服务是否能够处理请求?检查所有依赖项。

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text
from datetime import datetime, timezone

router = APIRouter(tags=["health"])

@router.get("/health")
async def liveness():
    """Liveness probe -- is the process running?"""
    return {
        "status": "healthy",
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "version": settings.APP_VERSION,
    }

@router.get("/health/ready")
async def readiness(db: AsyncSession = Depends(get_db)):
    """Readiness probe -- can we handle traffic?"""
    checks = {}

    # Check database
    try:
        await db.execute(text("SELECT 1"))
        checks["database"] = {"status": "ok", "latency_ms": 0}
    except Exception as e:
        checks["database"] = {"status": "error", "error": str(e)}

    # Check Redis
    try:
        start = time.perf_counter()
        await redis.ping()
        latency = (time.perf_counter() - start) * 1000
        checks["redis"] = {"status": "ok", "latency_ms": round(latency, 2)}
    except Exception as e:
        checks["redis"] = {"status": "error", "error": str(e)}

    all_ok = all(c["status"] == "ok" for c in checks.values())
    return JSONResponse(
        status_code=200 if all_ok else 503,
        content={
            "status": "ready" if all_ok else "not_ready",
            "checks": checks,
            "timestamp": datetime.now(timezone.utc).isoformat(),
        },
    )
使用 Sentry 进行错误追踪

Sentry 会捕获未处理的异常和性能数据。

设置:

import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration

sentry_sdk.init(
    dsn=settings.SENTRY_DSN,
    environment=settings.APP_ENV,
    release=settings.APP_VERSION,
    traces_sample_rate=0.1,  # 10% of requests for performance monitoring
    profiles_sample_rate=0.1,
    integrations=[
        FastApiIntegration(),
        SqlalchemyIntegration(),
    ],
    # Do not send PII
    send_default_pii=False,
    # Filter out health check noise
    before_send=filter_health_checks,
)

def filter_health_checks(event, hint):
    """Do not send health check errors to Sentry."""
    if "request" in event and event["request"].get("url", "").endswith("/health"):
        return None
    return event
仪表板设计

Grafana 仪表板应采用一致的布局模式。

标准仪表板分区:

  1. 概览行——一目了然地查看关键 SLI(错误率、延迟、吞吐量)
  2. RED 指标行——每个端点的速率、错误和持续时间
  3. 基础设施行——CPU、内存、磁盘、网络
  4. 依赖项行——数据库、Redis、外部 API 的运行状况
  5. 业务指标行——应用特有的 KPI

仪表板布局:

┌─────────────────────────────────────────────────────────┐
│  Service Overview                                       │
│  [Error Rate %] [p99 Latency] [Requests/s] [Uptime]    │
├────────────────────────┬────────────────────────────────┤
│  Request Rate          │  Error Rate                    │
│  (by endpoint)         │  (by endpoint, status code)    │
├────────────────────────┼────────────────────────────────┤
│  Latency (p50/p95/p99) │  Active Connections            │
│  (by endpoint)         │  (DB pool, Redis)              │
├────────────────────────┴────────────────────────────────┤
│  Infrastructure                                         │
│  [CPU %] [Memory %] [Disk %] [Network IO]              │
├─────────────────────────────────────────────────────────┤
│  Dependencies                                           │
│  [DB Latency] [Redis Latency] [External API Status]    │
└─────────────────────────────────────────────────────────┘

请参阅 references/dashboard-template.json,获取完整的 Grafana 仪表板模板。

正常运行时间监控

外部正常运行时间监控从用户的角度验证服务。

外部监控内容:

  • 从多个地理区域检查 /health 端点
  • 关键用户界面页面(登录、仪表板、API 文档)
  • SSL 证书有效性和到期时间
  • DNS 解析时间

建议的检查间隔:

检查项间隔超时区域
健康检查端点30 秒10 秒3 个或更多区域
关键页面1 分钟15 秒2 个或更多区域
SSL 证书6 小时30 秒1 个区域
DNS 解析5 分钟5 秒3 个或更多区域
快速参考

完整模板请参阅 references/:logging-config-template.py、metrics-config-template.py、alert-rules-template.yml、dashboard-template.json。

新服务监控清单
  • 已配置 structlog,并启用 JSON 输出
  • 已配置请求日志中间件,并关联请求 ID
  • 已在 /metrics 公开 Prometheus 指标端点
  • 已埋点 RED 指标(请求数、错误数、持续时间)
  • 已实现健康检查端点(/health、/health/ready)
  • 已初始化 Sentry SDK,并设置环境和发布版本标签
  • 已定义错误率、延迟和可用性的告警规则
  • 已创建包含标准分区的 Grafana 仪表板
  • 已配置外部正常运行时间监控
  • 已定义日志保留策略(默认:30 天)
输出文件

将监控配置摘要写入 monitoring-config.md:

# Monitoring Configuration: [Service Name]

## Metrics

| Metric | Type | Labels | Purpose |
|--------|------|--------|---------|
| http_requests_total | Counter | method, endpoint, status | RED: Request rate |
| http_request_duration_seconds | Histogram | method, endpoint | RED: Latency |

## Alerts

| Alert | Condition | Severity | Runbook |
|-------|-----------|----------|---------|
| HighErrorRate | error_rate > 5% for 5m | SEV2 | docs/runbooks/high-error-rate.md |

## Health Checks

- `/health` — Liveness probe
- `/health/ready` — Readiness probe (checks DB, Redis)

## Dashboards

- Grafana: Service Overview (imported from references/dashboard-template.json)

## Next Steps

- Run `/deployment-pipeline` to deploy with monitoring enabled
- Run `/incident-response` if alerts fire

评论

支持 Markdown