Designing Logging and Monitoring Infrastructure with Claude Code
Learn about designing logging and monitoring infrastructure using Claude Code. Includes practical code examples.
モニタリング基盤の構築にClaude Codeを活用する
本番環境のトラブルシューティングには、適切なログとモニタリングが不可欠です。Claude Codeは構造化ログ、分散トレーシング、メトリクス収集の基盤を一括で構築でき、可観測性(Observability)の高いシステムを効率的に実現します。
構造化ログの実装
> pinoを使った構造化ログのセットアップを作成して。
> リクエストID、ユーザーID、処理時間を含めて。
> 環境ごとにログレベルを切り替えられるようにして。
// src/lib/logger.ts
import pino from 'pino';
export const logger = pino({
level: process.env.LOG_LEVEL || (process.env.NODE_ENV === 'production' ? 'info' : 'debug'),
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty', options: { colorize: true } }
: undefined,
formatters: {
level(label) {
return { level: label };
},
},
base: {
service: process.env.SERVICE_NAME || 'my-app',
env: process.env.NODE_ENV,
},
timestamp: pino.stdTimeFunctions.isoTime,
redact: ['password', 'token', 'authorization', 'cookie'],
});
// リクエストスコープのロガー
export function createRequestLogger(requestId: string, userId?: string) {
return logger.child({
requestId,
userId,
});
}
リクエストログミドルウェア
// src/middleware/request-logger.ts
import { Request, Response, NextFunction } from 'express';
import { createRequestLogger } from '@/lib/logger';
import { randomUUID } from 'crypto';
export function requestLogger(req: Request, res: Response, next: NextFunction) {
const requestId = (req.headers['x-request-id'] as string) || randomUUID();
const start = Date.now();
const log = createRequestLogger(requestId, req.user?.id);
req.log = log;
res.setHeader('X-Request-Id', requestId);
log.info({
method: req.method,
url: req.url,
userAgent: req.headers['user-agent'],
}, 'Request started');
res.on('finish', () => {
const duration = Date.now() - start;
const level = res.statusCode >= 500 ? 'error' : res.statusCode >= 400 ? 'warn' : 'info';
log[level]({
method: req.method,
url: req.url,
statusCode: res.statusCode,
duration,
}, 'Request completed');
});
next();
}
OpenTelemetryによる分散トレーシング
> OpenTelemetryを使った分散トレーシングを設定して。
> HTTP、DB、Redis呼び出しの自動計装を有効にして。
// src/instrumentation.ts
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
resource: new Resource({
[ATTR_SERVICE_NAME]: process.env.SERVICE_NAME || 'my-app',
[ATTR_SERVICE_VERSION]: process.env.APP_VERSION || '1.0.0',
}),
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces',
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/metrics',
}),
exportIntervalMillis: 30000,
}),
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-http': { enabled: true },
'@opentelemetry/instrumentation-express': { enabled: true },
'@opentelemetry/instrumentation-pg': { enabled: true },
'@opentelemetry/instrumentation-redis': { enabled: true },
}),
],
});
sdk.start();
process.on('SIGTERM', () => {
sdk.shutdown().then(() => process.exit(0));
});
カスタムメトリクスの収集
// src/lib/metrics.ts
import { metrics } from '@opentelemetry/api';
const meter = metrics.getMeter('my-app');
// リクエストカウンター
export const requestCounter = meter.createCounter('http_requests_total', {
description: 'Total HTTP requests',
});
// レスポンスタイムのヒストグラム
export const responseTime = meter.createHistogram('http_response_time_ms', {
description: 'HTTP response time in milliseconds',
unit: 'ms',
});
// アクティブユーザー数のゲージ
export const activeUsers = meter.createUpDownCounter('active_users', {
description: 'Number of active users',
});
// ビジネスメトリクス
export const orderCounter = meter.createCounter('orders_total', {
description: 'Total orders placed',
});
// Usage example
export function recordRequest(method: string, path: string, statusCode: number, duration: number) {
requestCounter.add(1, { method, path, statusCode: String(statusCode) });
responseTime.record(duration, { method, path });
}
ヘルスチェックエンドポイント
// src/app/api/health/route.ts
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/db';
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL!);
export async function GET() {
const checks = {
status: 'ok' as 'ok' | 'degraded' | 'error',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
checks: {} as Record<string, { status: string; latency?: number }>,
};
// DB接続チェック
try {
const start = Date.now();
await prisma.$queryRaw`SELECT 1`;
checks.checks.database = { status: 'ok', latency: Date.now() - start };
} catch {
checks.checks.database = { status: 'error' };
checks.status = 'degraded';
}
// Redis接続チェック
try {
const start = Date.now();
await redis.ping();
checks.checks.redis = { status: 'ok', latency: Date.now() - start };
} catch {
checks.checks.redis = { status: 'error' };
checks.status = 'degraded';
}
const statusCode = checks.status === 'ok' ? 200 : 503;
return NextResponse.json(checks, { status: statusCode });
}
エラートラッキング
// src/lib/error-tracker.ts
import { logger } from './logger';
export function trackError(error: Error, context?: Record<string, unknown>) {
logger.error({
err: {
name: error.name,
message: error.message,
stack: error.stack,
},
...context,
}, 'Unhandled error');
// Sentryなどの外部サービスへ送信
if (process.env.SENTRY_DSN) {
// Sentry.captureException(error, { extra: context });
}
}
// グローバルエラーハンドラー
process.on('uncaughtException', (error) => {
trackError(error, { type: 'uncaughtException' });
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
trackError(reason instanceof Error ? reason : new Error(String(reason)), {
type: 'unhandledRejection',
});
});
Zusammenfassung
Claude Codeを使えば、構造化ログ、分散トレーシング、メトリクス収集、ヘルスチェックを含むモニタリング基盤を効率的に構築できます。本番運用に必要な可観測性を最初から組み込むことで、トラブルシューティングの時間を大幅に短縮できます。開発環境の設定はCLAUDE.mdに記述しておくと、Claude Codeが一貫した構成を生成します。マイクロサービスでのモニタリングはマイクロサービス設計も参考にしてください。
Claude Codeの詳細はAnthropic公式ドキュメントをご覧ください。OpenTelemetryの詳細はOpenTelemetry公式サイトを参照してください。
Related Posts
Claude Code Hooks meistern: Auto-Formatierung, Auto-Tests und mehr
Erfahren Sie, wie Sie Auto-Formatierung und Auto-Tests mit Claude Code Hooks einrichten. Inklusive praktischer Konfigurationsbeispiele und realer Anwendungsfälle.
Claude Code MCP-Server: Einrichtung und praktische Anwendungsfälle
Ein umfassender Leitfaden zu den MCP-Server-Funktionen von Claude Code. Erfahren Sie, wie Sie externe Tools anbinden, Server konfigurieren, und entdecken Sie praxisnahe Integrationsbeispiele.
Der komplette Leitfaden zum Schreiben von CLAUDE.md: Best Practices für die Projektkonfiguration
Ein umfassender Leitfaden zum Schreiben effektiver CLAUDE.md-Dateien. Erfahren Sie, wie Sie Ihren Tech-Stack, Konventionen und Projektstruktur kommunizieren, um die Ausgabequalität von Claude Code zu maximieren.