observability について
Cloudflare Workersやエッジアプリケーションを開発する人向けの可観測性スキルです。構造化ログ、分散トレーシング、エラー監視を扱い、リクエスト単位のトレースとログ・スパンの非同期送信で本番環境を把握します。
主な機能
- 01相関 ID 付き構造化 JSON ログ
- 02リクエスト単位の分散トレーシング
- 03コンテキストを含むエラー捕捉
- 04エラー率とレイテンシの監視
- 05ログとスパンの非同期送信
活用シーン
- 01Workers へのログ追加
- 02本番リクエストのトレース
- 03エラー監視とアラートの設定
- 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