devops
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
可観測性(Observability)入門:ログ・メトリクス・トレース
Observabilityの3本柱であるLogs・Metrics・Tracesを解説。OpenTelemetry・Prometheus・Grafana・Jaegerを使ったモニタリングスタックの構築方法を紹介します。
一言結論
ログ・メトリクス・トレースの3本柱をOpenTelemetryで統一計装しておくことが、本番障害を「何が起きたか」「どこで起きたか」「なぜ起きたか」の全レイヤーで即座に診断できる組織の前提条件だ。
Observability の3本柱
Logs(ログ)
何が起きたか。構造化されたイベントの記録。
→ "2026-04-08T10:00:00Z ERROR user_id=123 payment failed: insufficient funds"
Metrics(メトリクス)
どのくらいの規模で起きているか。時系列の数値データ。
→ HTTP リクエスト数・エラー率・レスポンスタイム・CPU 使用率
Traces(トレース)
なぜ起きたか。リクエストの処理経路を追跡。
→ API → DB クエリ → 外部API 呼び出しの各レイテンシ
OpenTelemetry — 標準化された計装
OpenTelemetry(OTel)はLogs・Metrics・Traces を統一した標準です。
// Node.js での OpenTelemetry 設定
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: "http://otel-collector:4318/v1/traces",
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
// Express・http・pg・redis などが自動で計装される
Metrics — Prometheus + Grafana
// prom-client でメトリクスを公開
import { Counter, Histogram, Registry } from "prom-client";
import express from "express";
const registry = new Registry();
// カウンター: 単調増加する値
const httpRequests = new Counter({
name: "http_requests_total",
help: "Total HTTP requests",
labelNames: ["method", "path", "status"],
registers: [registry],
});
// ヒストグラム: レスポンスタイムの分布
const requestDuration = new Histogram({
name: "http_request_duration_seconds",
help: "HTTP request duration",
buckets: [0.01, 0.05, 0.1, 0.5, 1, 5],
labelNames: ["method", "path"],
registers: [registry],
});
// ミドルウェアで計測
app.use((req, res, next) => {
const end = requestDuration.startTimer({ method: req.method, path: req.route?.path ?? req.path });
res.on("finish", () => {
httpRequests.inc({ method: req.method, path: req.path, status: res.statusCode });
end();
});
next();
});
// Prometheus がスクレイプするエンドポイント
app.get("/metrics", async (req, res) => {
res.set("Content-Type", registry.contentType);
res.end(await registry.metrics());
});
# prometheus.yml
scrape_configs:
- job_name: "my-app"
static_configs:
- targets: ["app:3000"]
metrics_path: "/metrics"
scrape_interval: 15s
Traces — 分散トレーシング
// カスタムスパンを作成
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("my-app");
async function processOrder(orderId: string) {
const span = tracer.startSpan("processOrder");
span.setAttribute("order.id", orderId);
try {
const result = await tracer.startActiveSpan("fetchOrderDetails", async (childSpan) => {
const order = await db.orders.findById(orderId);
childSpan.setAttribute("order.amount", order.amount);
childSpan.end();
return order;
});
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (err) {
span.recordException(err);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
}
構造化ログ
// JSON 形式のログ(検索・集計しやすい)
import pino from "pino";
const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
transport: process.env.NODE_ENV === "development"
? { target: "pino-pretty" } // 開発時は読みやすく
: undefined, // 本番は JSON
});
// ❌ 構造化されていないログ
console.log(`User ${userId} failed to login`);
// ✅ 構造化ログ
logger.warn({ userId, reason: "invalid_password", attempts: 3 }, "Login failed");
// → {"level":"warn","userId":"123","reason":"invalid_password","attempts":3,"msg":"Login failed"}
アラートの設計
# Prometheus Alerting Rules
groups:
- name: app-alerts
rules:
- alert: HighErrorRate
expr: |
rate(http_requests_total{status=~"5.."}[5m])
/ rate(http_requests_total[5m]) > 0.01
for: 2m
labels:
severity: critical
annotations:
summary: "エラー率が1%を超えています"
- alert: SlowResponse
expr: |
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
for: 5m
annotations:
summary: "P95レスポンスタイムが1秒を超えています"
まとめ
| ツール | 用途 |
|---|---|
| OpenTelemetry | 計装の標準化(ベンダー非依存) |
| Prometheus | メトリクス収集・アラート |
| Grafana | ダッシュボード可視化 |
| Jaeger / Tempo | 分散トレーシング |
| Loki / ELK | ログ集約・検索 |
観測できないシステムは運用できません。最低限「エラー率」「レスポンスタイム」「スループット」の3指標(RED メソッド)から始めることを推奨します。