Advanced

设计Logging and Monitoring Infrastructure:Claude Code 实战指南

了解designing logging and monitoring infrastructure:Claude Code 实战. 包含实用代码示例。

监控基盤の构建に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',
  });
});

总结

借助 Claude Code,構造化日志、分散トレーシング、メトリクス収集、ヘルスチェックを含む监控基盤を高效地构建可以。本番运维に必要な可観測性を最初から組み込むことで、トラブルシューティングの时间を大幅に短縮可以。开发环境の配置はCLAUDE.mdに記述しておくと、Claude Code 一貫した结构を生成します。微服务での监控は微服务设计也可以参考。

Claude Code 的详细信息请参阅Anthropic官方文档。OpenTelemetry的详细信息请参阅OpenTelemetry官方网站

#Claude Code #ログ #モニタリング #可観測性 #OpenTelemetry