monitoring-setup について
monitoring-setupは、Python/FastAPIサービスの可観測性設定を案内するスキルです。メトリクス、構造化ログ、トレース、アラート、ヘルスチェック、ダッシュボードを扱い、設定概要をmonitoring-config.mdに記録するよう指定します。
主な機能
- 01Prometheusメトリクスの設定
- 02structlogによる構造化ログ
- 03OpenTelemetryによる分散トレース
- 04アラートルールとしきい値の設計
- 05ヘルスチェックエンドポイントの指針
- 06Grafanaダッシュボードの構成
活用シーン
- 01FastAPIサービスの可観測性を計画する
- 02APIエンドポイントのREDメトリクスを設計する
- 03本番サービスのアラートを設定する
- 04監視設定を文書化する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hieutrtr/ ai1-skills --skill monitoring-setupインストール後、Claude Code で/monitoring-setupを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/alert-rules-template.ymldashboard-template.jsonlogging-config-template.pymetrics-config-template.py詳細
モニタリングの設定
使用するタイミング
以下の場合にこのスキルを有効にします:
- Python/FastAPI アプリケーションの構造化ログを設定する
- Prometheus のメトリクス収集とカスタムカウンター/ヒストグラムを設定する
- ヘルスチェックエンドポイント(ライブネスとレディネス)を実装する
- 本番サービスのアラートルールとしきい値を設計する
- サービスモニタリング用の Grafana ダッシュボードを作成する
- エラートラッキングとパフォーマンスモニタリングのために Sentry を統合する
- OpenTelemetry で分散トレーシングを実装する
- 既存のオブザーバビリティのカバレッジを確認または改善する
出力: 設定した内容(メトリクス、アラート、ダッシュボード、ヘルスチェック)を記録したオブザーバビリティ設定の概要を monitoring-config.md に書き込みます。
以下の場合、このスキルは使用しないでください:
- 本番環境で発生中のインシデントに対応する(
incident-responseを使用) - モニタリングインフラストラクチャをデプロイする(
deployment-pipelineを使用) - アプリケーションのビジネスロジックを記述する(
python-backend-expertを使用) - Docker コンテナーを設定する(
docker-best-practicesを使用)
手順
オブザーバビリティの4つの柱
すべての本番サービスで、4つの柱すべてを実装する必要があります。
┌─────────────────────────────────────────────────────────────────┐
│ 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 -- 1秒あたりのリクエスト数
- Errors -- 1秒あたりの失敗リクエスト数
- 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() や非構造化ログを使用しないでください。
ロギングの原則:
- 構造化 -- 機械で解析可能なJSON形式
- コンテキスト付き -- すべてのログにリクエストID、ユーザーID、トレースIDを含めます
- 適切なレベル -- 適切なログレベル(DEBUG、INFO、WARNING、ERROR、CRITICAL)を使用します
- 実用性 -- 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()
ビジネスロジック向けのカスタムスパン:
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)
Pillar 4:アラート
アラートは実行可能なものでなければなりません。すべてのアラートで、何が壊れているのか、何をすべきかを示す必要があります。
アラート設計の原則:
- ユーザーに影響する問題のみ通知する -- 緊急性のない警告では通知しないでください
- SLO に基づいてしきい値を設定する -- 恣意的な数値を使わないでください
- アラート疲れを避ける -- アクションにつながらず頻繁に発生するアラートは、修正するか削除してください
- ランブックへのリンクを含める -- すべてのアラートに、修復ガイドへのリンクを付けてください
- 複数ウィンドウのバーンレートを使用する -- 誤検知を避けながら、問題をより早く検出できます
一般的な FastAPI アプリケーションのアラートしきい値:
| アラート | 条件 | 重大度 | アクション |
|---|---|---|---|
| エラー率が高い | http_requests_total{status=~"5.."} が 5 分間、合計の 5% を超える | SEV2 | ログを確認し、ロールバックを検討する |
| レイテンシーが高い | http_request_duration_seconds の p99 が 5 分間、2s を超える | SEV3 | DB クエリと依存関係を確認する |
| サービス停止 | ヘルスチェックが 2 分間失敗する | SEV1 | 再起動し、ログを確認してエスカレーションする |
| DB 接続数が多い | プール使用率が 5 分間、80% を超える | SEV3 | 接続リークがないか確認する |
| DB 接続数が危険水準 | プール使用率が 2 分間、95% を超える | SEV2 | アプリを再起動して調査する |
| メモリ使用量が多い | コンテナーのメモリ使用量が 10 分間、85% を超える | SEV3 | メモリリークがないか確認する |
| ディスク容量が少ない | ディスク使用率が 85% を超える | SEV3 | ログを整理し、ボリュームを拡張する |
| 証明書の有効期限切れが近い | SSL 証明書の有効期限が 14 日未満 | SEV4 | 証明書を更新する |
Prometheus のアラートルールについては、references/alert-rules-template.yml を参照してください。
ヘルスチェックエンドポイント
すべてのサービスは、2 つのヘルスエンドポイントを公開する必要があります。
ライブネス(/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 ダッシュボードでは、一貫したレイアウトパターンに従ってください。
標準的なダッシュボードのセクション:
- 概要の行 -- 主要な SLI を一覧で確認(エラー率、レイテンシー、スループット)
- RED メトリクスの行 -- 各エンドポイントのレート、エラー、継続時間
- インフラストラクチャの行 -- CPU、メモリ、ディスク、ネットワーク
- 依存関係の行 -- データベース、Redis、外部 API の稼働状況
- ビジネスメトリクスの行 -- アプリケーション固有の 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] │
└─────────────────────────────────────────────────────────┘
Grafana ダッシュボードの完全なテンプレートについては、references/dashboard-template.json を参照してください。
稼働時間の監視
外部からの稼働時間監視により、ユーザーの視点からサービスを検証できます。
外部から監視する項目:
- 複数の地理的リージョンからの
/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。
新しいサービスの監視チェックリスト
- JSON 出力で structlog を設定済み
- リクエスト 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