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',
});
});
Summary
Claude Codeを使えば、構造化ログ、分散トレーシング、メトリクス収集、ヘルスチェックを含むモニタリング基盤を効率的に構築できます。本番運用に必要な可観測性を最初から組み込むことで、トラブルシューティングの時間を大幅に短縮できます。開発環境の設定はCLAUDE.mdに記述しておくと、Claude Codeが一貫した構成を生成します。マイクロサービスでのモニタリングはマイクロサービス設計も参考にしてください。
Claude Codeの詳細はAnthropic公式ドキュメントをご覧ください。OpenTelemetryの詳細はOpenTelemetry公式サイトを参照してください。
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Key commands, shortcuts, and prompt examples on a single printable page.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Getting Started with Claude Code Agent SDK — Build Autonomous Agents Fast
Learn how to build autonomous AI agents with Claude Code Agent SDK. Covers setup, tool definitions, and multi-step execution with practical code examples.
The Complete Guide to Context Management in Claude Code
Learn practical techniques to maximize Claude Code's context window. Covers token optimization, conversation splitting, and CLAUDE.md usage.
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More. A practical guide with code examples.