mcpField
O
observability

observability

github.com/itallstartedwithaideaクラウド・DevOps4479 回インストール29 週間前に更新
リポジトリ

observability について

Cloudflare Workersやエッジアプリケーションを開発する人向けの可観測性スキルです。構造化ログ、分散トレーシング、エラー監視を扱い、リクエスト単位のトレースとログ・スパンの非同期送信で本番環境を把握します。

主な機能

  1. 01相関 ID 付き構造化 JSON ログ
  2. 02リクエスト単位の分散トレーシング
  3. 03コンテキストを含むエラー捕捉
  4. 04エラー率とレイテンシの監視
  5. 05ログとスパンの非同期送信

活用シーン

  1. 01Workers へのログ追加
  2. 02本番リクエストのトレース
  3. 03エラー監視とアラートの設定
  4. 04レイテンシ百分位数の測定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/itallstartedwithaidea/agent-skills --skill observability

インストール後、Claude Code で/observabilityを入力して読み込まれたか確認します。

詳細

可観測性

googleadsagent.ai™ による Agent Skills™ の一部です

説明

可観測性では、Cloudflare Workers とエッジアプリケーション向けに、構造化ログ、分散トレーシング、エラー監視を実装します。エージェントは、コンテキスト付きのログエントリー、トレーススパン、エラー境界、アラートルールをコードに組み込み、パフォーマンスを損なうことなく、本番環境での動作を完全に把握できるようにします。

Workers には、特有の可観測性に関する課題があります。プロファイラーを接続する永続プロセスも、ログファイルを保存するファイルシステムも、挿入できる APM エージェントもありません。可観測性は、外部コレクターに送信する構造化ログイベント、リクエスト単位のトレースコンテキスト、スタックトレースとリクエストメタデータを含む明示的なエラー捕捉を通じて、アプリケーション層に組み込む必要があります。

このスキルでは、3 つの柱を扱います。ロギング(相関 ID を含む構造化 JSON イベント)、トレーシング(リクエスト単位のスパンとタイミング・メタデータ)、モニタリング(エラー率の追跡、レイテンシのパーセンタイル、アラートのしきい値)です。これらを組み合わせることで、本番環境のデバッグで確認すべき 3 つの問い、つまり「何が起きたか」「どれだけ時間がかかったか」「どのくらいの頻度で失敗するか」に答えられます。

使用する場面

  • Workers やエッジアプリケーションにロギングを追加するとき
  • 分散リクエストトレーシングで本番環境の問題をデバッグするとき
  • エラー監視とアラートを設定するとき
  • ヘルスチェックエンドポイントを実装するとき
  • レイテンシのパーセンタイルを測定・報告するとき
  • 運用状況を把握するためのダッシュボードを構築するとき

仕組み

graph TD
    A[Incoming Request] --> B[Generate Trace ID]
    B --> C[Start Root Span]
    C --> D[Execute Handler]
    D --> E[Child Spans for Subrequests]
    E --> F{Error?}
    F -->|Yes| G[Capture Error + Context]
    F -->|No| H[Record Success Metrics]
    G --> I[Structured Log: ERROR]
    H --> J[Structured Log: INFO]
    I --> K[Ship to Collector via waitUntil]
    J --> K
    K --> L[External: Datadog / Grafana / Sentry]
    C --> M[End Root Span + Record Latency]
    M --> K

すべてのリクエストにトレース ID が割り当てられ、すべてのサブリクエストとログエントリーに伝播します。スパンによって、個々の処理にかかった時間を測定します。レスポンスに遅延を加えないよう、ログとスパンはバッチ処理され、waitUntil() を介して非同期に送信されます。

実装

interface LogEntry {
  timestamp: string;
  level: "debug" | "info" | "warn" | "error";
  traceId: string;
  spanId: string;
  message: string;
  data?: Record<string, unknown>;
  error?: { name: string; message: string; stack?: string };
  duration_ms?: number;
}

class RequestTracer {
  private traceId: string;
  private spans: LogEntry[] = [];
  private startTime: number;

  constructor(request: Request) {
    this.traceId = request.headers.get("x-trace-id") ?? crypto.randomUUID();
    this.startTime = performance.now();
  }

  span<T>(name: string, fn: () => Promise<T>): Promise<T> {
    const spanId = crypto.randomUUID().slice(0, 8);
    const start = performance.now();
    return fn().then(
      result => {
        this.log("info", name, { duration_ms: performance.now() - start }, spanId);
        return result;
      },
      error => {
        this.log("error", name, {
          duration_ms: performance.now() - start,
          error: { name: error.name, message: error.message, stack: error.stack },
        }, spanId);
        throw error;
      }
    );
  }

  log(level: LogEntry["level"], message: string, data?: Record<string, unknown>, spanId?: string): void {
    this.spans.push({
      timestamp: new Date().toISOString(),
      level,
      traceId: this.traceId,
      spanId: spanId ?? "root",
      message,
      ...data,
    });
  }

  async flush(env: { LOG_COLLECTOR: Fetcher }): Promise<void> {
    const rootDuration = performance.now() - this.startTime;
    this.log("info", "request_complete", { duration_ms: rootDuration });

    await env.LOG_COLLECTOR.fetch("https://collector/ingest", {
      method: "POST",
      body: JSON.stringify(this.spans),
      headers: { "Content-Type": "application/json" },
    });
  }
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const tracer = new RequestTracer(request);
    try {
      const data = await tracer.span("fetch_data", () => fetchData(env));
      const html = await tracer.span("render", () => render(data));
      return new Response(html, { status: 200 });
    } catch (error) {
      tracer.log("error", "unhandled_error", {
        error: { name: (error as Error).name, message: (error as Error).message },
        url: request.url,
        method: request.method,
      });
      return new Response("Internal Error", { status: 500 });
    } finally {
      ctx.waitUntil(tracer.flush(env));
    }
  },
} satisfies ExportedHandler<Env>;

ベストプラクティス

  • レスポンスに遅延を加えないよう、ログは waitUntil() を介して非同期に送信します
  • デバッグ時にユーザーが報告できるよう、すべてのエラーレスポンスにトレース ID を含めます
  • 構造化 JSON ロギングを使用します。本番環境では、構造化されていない console.log を決して使用しません
  • エラー率(>1%)と p99 レイテンシ(>500ms)にアラートのしきい値を設定します
  • ログ量とコストを抑えるため、本番環境ではデバッグレベルのログをサンプリングします(1-10%)
  • x-trace-id ヘッダーを使用して、サービス間でトレース ID を伝播させます

プラットフォームの互換性

プラットフォームサポート備考
Cursor完全計装コードの生成
VS Code完全ログビューアーとの連携
Windsurf完全可観測性のパターン
Claude Code完全Worker の計装
Cline完全ロギングとトレーシングの設定
aider部分的コードレベルの計装

関連スキル

キーワード

observability structured-logging distributed-tracing error-monitoring cloudflare-workers alerting latency trace-id


© 2026 googleadsagent.ai™ | Agent Skills™ | MIT License

コメント