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公式サイトを参照してください。
Free PDF: Claude Code Cheatsheet in 5 Minutes
Just enter your email and we'll send you the single-page A4 cheatsheet right away.
We handle your data with care and never send spam.
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Safe Agent Harness Design for Claude Code and Codex: Permissions, Checks, and Rollback
Build a practical agent harness for Claude Code and Codex with policy, planning, verification, and recovery layers.
10 Powerful Subagent Patterns for Claude Code
Master Claude Code's subagent feature with 10 practical patterns. Learn how to use parallel processing, specialization, and context isolation to double your development speed.
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.
Related Products
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.
The Complete Claude Code Setup & Configuration Guide
From install to team-ready workflow.
A practical guide to installation, CLAUDE.md, hooks, MCP servers, permissions, IDE setup, and CI/CD workflows.