Communityコーディング&開発github.com

observability-and-instrumentation

コードに観測可能性(オブザーバビリティ)とインストゥルメンテーションを追加し、本番稼働時の動作を可視化・診断可能にします。ログ、メトリクス、トレース、アラートを追加する際に使用します。本番環境で動作する機能を出荷し、その動作を確認する証拠が必要な場合に使用します。本番環境で問題が報告されたが、入手可能なデータから何が起きたのかわからない場合に使用します。

observability-and-instrumentation とは?

このスキルは、コードに対して観測可能性(オブザーバビリティ)とインストゥルメンテーションを体系的に追加するための詳細なガイドです。「コードを観測できなければ、それを運用することはできない」という原則に基づき、構造化ログ、メトリクス、分散トレーシング、アラートといったテレメトリを、機能開発と同時に組み込むプロセスを提供します。特に、本番環境で動作するあらゆる機能(新規サービス、エンドポイント、バックグラウンドジョブ、外部統合)に対して、RED(レート、エラー、デュレーション)やUSE(ユーティリゼーション、サチュレーション、エラー)といった指標を用いた具体的な実装方法を、コード例を交えて解説します。また、相関IDの必須化、カーディナリティ爆発の回避、症状ベースのアラート設計、そしてテレメトリ自体の検証方法までを網羅しており、開発者が本番障害の原因特定を「発掘調査」ではなく「クエリ」に変えるための実践的な知識を提供します。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/addyosmani/agent-skills/tree/main/skills/observability-and-instrumentation

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

観測可能性とインストゥルメンテーション

概要

観測できないコードは運用できません。観測可能性とは、「システムは何をしているのか、なぜそうなっているのか」を、外部からコードが発するテレメトリを使って答えられる能力です。インストゥルメンテーションはリリース後のおまけではなく、テストと同様に機能と並行して記述されるものです。テレメトリなしで機能が出荷された場合、最初のユーザー報告バグは、クエリではなく発掘調査になります。

使用すべきタイミング

  • 本番環境で実行されるあらゆる機能を構築する場合
  • 新しいサービス、エンドポイント、バックグラウンドジョブ、外部統合を追加する場合
  • 本番インシデントの診断に時間がかかりすぎた場合(「何が起きたかわからなかった」)
  • アラートルールを設定またはレビューする場合
  • I/O、リトライ、キュー、クロスサービスコールを追加するPRをレビューする場合

使用すべきでないタイミング:

  • 現在発生している障害の診断 — debugging-and-error-recoveryスキルを使用してください(観測可能性は、次回そのスキルを高速化するためのものです)
  • 計測されたパフォーマンス低下のプロファイリングと最適化 — performance-optimizationスキルを使用してください
  • リリース日の監視チェックリストとロールバックトリガー — shipping-and-launchスキルを参照してください。このスキルはそれらに情報を提供するインストゥルメンテーションをカバーします

プロセス

1. インストゥルメントする前に「動作する」を定義する

質問のないテレメトリはノイズです。インストゥルメンテーションを追加する前に、オンコールのエンジニアがこの機能について尋ねるであろう2〜4の質問を書き留めてください。

FEATURE: checkout payment retry
QUESTIONS ON-CALL WILL ASK:
1. What fraction of payments succeed on first attempt vs after retry?
2. When a payment fails permanently, why? (provider error? timeout? validation?)
3. Is the payment provider slower than usual?
→ Every signal below must help answer one of these.

質問を明確にできないなら、インストゥルメントする準備はできていません — すべてを記録しても何も学べません。

2. 各質問に適切なシグナルを選ぶ

シグナル答えられることコストプロファイル例
構造化ログ「この特定のケースで何が起きたか?」イベント単位; トラフィックに応じて増加payment_failed とプロバイダエラーコード
メトリクス「どのくらいの頻度・速度で、集約するとどうか?」系列あたり固定; クエリが安価プロバイダ呼び出しのp99レイテンシ
トレース「サービス全体で時間はどこで費やされたか?」リクエスト単位; 通常サンプリング1つの遅いチェックアウト、ホップごとの内訳

経験則: メトリクスは何かが問題であることを教え、トレースはどこで問題が起きているかを教え、ログはなぜ問題が起きたかを教えます。

3. 構造化ログ

イベントを記録し、散文を記録しないでください。すべてのログ行は、安定したイベント名と機械可読なフィールドを持つJSONオブジェクトです。

// BAD: string interpolation — unqueryable, inconsistent
logger.info(`Payment ${id} failed for user ${userId} after ${n} retries`);

// GOOD: stable event name + structured fields
logger.warn({
  event: 'payment_failed',
  paymentId: id,
  provider: 'stripe',
  errorCode: err.code,
  attempt: n,
}, 'payment failed');

ログレベル — 一貫して使用する:

レベル意味オンコール対応
error不変条件が破られた; 誰かが対応する必要がある可能性調査
warn低下したが処理済み(リトライ成功、フォールバック使用)傾向を監視
info重要なビジネスイベント(注文確定、ジョブ完了)なし
debug診断詳細デフォルトで本番ではオフ

相関IDは必須です。 システム境界でリクエストIDを生成(または受け入れ)、すべてのログ行、スパン、および外部呼び出しに付加します。これがないと、インターリーブされたログから単一のリクエストを再構築することはできません。

// Express: child logger per request, ID propagated downstream
app.use((req, res, next) => {
  req.id = req.headers['x-request-id'] ?? crypto.randomUUID();
  req.log = logger.child({ requestId: req.id });
  res.setHeader('x-request-id', req.id);
  next();
});

複数のエントリポイントが1つのログに書き込む場合は、エントリポイントに名前を付けます。 相関IDは実行を識別しますが、どのコードパスがそれを開始したかは示しません。スケジューラー、リプレイエンドポイント、手動CLI実行によって到達した同じジョブは、1つのシンク内で交換可能な行を生成するため、行の属性を特定するには消去法に頼ることになります — スケジューラーの履歴、プロセステーブル、デプロイログを相互参照する必要があり、その議論はそれらの外部レコードがたまたままだ存在する限り有効です。エントリポイントを実行開始時に、相関IDの隣にスタンプし、両方を同じ方法で伝播させてください。

// One helper for every entry point: the run's own logger carries both fields.
// `entryPoint`, not `source` — ECS reserves `source.*` for network fields.
export const runLog = (entryPoint: 'scheduler' | 'replay_endpoint' | 'cli', runId: string) =>
  logger.child({ entryPoint, requestId: runId });

// scheduler tick        -> runLog('scheduler', crypto.randomUUID())
// POST /jobs/:id/replay -> runLog('replay_endpoint', req.id)
// CLI invocation        -> runLog('cli', process.env.RUN_ID ?? crypto.randomUUID())

両方のフィールドは、相関IDと同じ境界(キュー・メタデータ、HTTPヘッダー)を越える必要があります。さもなければ、ワーカーがエントリポイントを再導出して推測することになります。エントリポイントと単に相関するだけのフィールドは、ヒントであり、属性の特定ではありません。ジョブを呼び出せるものは何でもそれを再現できます。

シークレット、トークン、パスワード、完全なPIIを決してログに記録しないでください。 これは security-and-hardening スキルからの厳格なルールです — テレメトリパイプラインは古典的なデータ漏洩経路です。フィールドを許可リストで管理し、リクエストボディ全体をログに記録しないでください。

4. メトリクス

リクエスト駆動型サービスの場合、すべてのエンドポイントとすべての外部依存関係に対してREDをインストゥルメントします: Rate(リクエスト/秒)、Errors(障害率)、Duration(レイテンシヒストグラム、平均ではない)。リソース(キュー、プール、ホスト)にはUSEを使用します: Utilization(利用率)、Saturation(飽和度)、Errors(エラー率)。

トレーシングと同様に、ベンダーニュートラルなパスはOpenTelemetryメトリクスAPIです(ステップ5と同じSDKとコンテキスト)。以下の例ではPrometheusのprom-clientを使用しています — これは一般的なバックエンドの1つであり、唯一の選択肢ではありません。RED/USEとカーディナリティのルールはどちらの場合でも同じです。

import { Histogram } from 'prom-client';

const httpDuration = new Histogram({
  name: 'http_request_duration_seconds',
  help: 'HTTP request duration',
  labelNames: ['method', 'route', 'status_class'],  // '2xx', not '200'
  buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
});

カーディナリティは障害モードです。 一意のラベル値の組み合わせごとに個別の時系列が作成されます。ラベルは、小さく固定されたセット(ルートテンプレート、ステータスクラス、プロバイダ名)から取得する必要があります。ユーザーID、生のURL、エラーメッセージ、その他の無制限の値をラベルとして決して使用しないでください — それらはログとトレースに属します。

OK as label:    route="/api/tasks/:id"   status_class="5xx"   provider="stripe"
NEVER a label:  user_id, email, request_id, full URL, error message text

平均は決して追跡せず、パーセンタイルを常に追跡してください。平均は、ひどい時間を過ごしている1%のユーザーを隠してしまいます。ヒストグラムを使用し、p50/p95/p99を読み取ってください。

5. 分散トレーシング

OpenTelemetryを使用してください — これはベンダーニュートラルな標準であり、自動インストゥルメンテーションはHTTP、gRPC、および一般的なDBクライアントをほぼコードゼロでカバーします。

// tracing.ts — must be imported before anything else
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  serviceName: 'checkout-service',
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

意味のある内部作業単位(例: applyDiscounts、chargeProvider)の周りにのみ手動スパンを追加し、オンコール担当者がフィルタリングできる属性を付加してください。すべての非同期境界(HTTPヘッダー、キューメッセージメタデータ)を越えてコンテキストを伝播させないと、トレースはそのギャップで途絶えます。デフォルトでは低いレートでヘッドベースのサンプリングを行い、バックエンドがテールサンプリングをサポートしている場合はエラーを100%保持してください。

6. アラート

ユーザーが感じる症状にアラートを設定し、原因には設定しないでください。

SYMPTOM (page-worthy):           CAUSE (dashboard, not a page):
error rate > 1% for 5 min        CPU at 85%
p99 latency > 2s                 one pod restarted
queue age > 10 min               disk at 70%

原因ベースのアラートは、何も問題がないときに発報し、予測していなかった障害を見逃します。症状ベースのアラートは、原因に関係なく、ユーザーが実際に被害を受けているときに発報します。

作成するすべてのアラートのルール:

  1. アクション可能でなければなりません。 対応が「無視する、自己回復する」である場合は、アラートを削除してください。
  2. ランブックへのリンクがあること — たとえ3行でも: それが何を意味するか、最初に実行するクエリ、エスカレーションパス。
  3. しきい値と期間は、SLOまたは過去のデータによって正当化されていなければならず、推測によるものであってはなりません。
  4. 2つの重要度のみを使用してください: ページ(ユーザー影響あり、すぐに対応)とチケット(低下、今週中に対応)。3つ目の階層はノイズとなり、人々がすべてを無視するよう訓練することになります。

ランブックの作成

上記ルール2では、すべてのアラートにランブックへのリンクが必要です。ランブックの役割は、読者が考えることなく3つの質問に答えることです: 何が起きているのか、最初に何を確認すべきか、それが解決しない場合に誰に連絡すべきか。docs/runbooks/にアラート名で保存してください。

最小限のランブック(3行):

# Runbook: High Error Rate on /api/tasks
**Means:** DB connection pool likely exhausted, or a bad deploy.
**First check:** `SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';`
  — if count > pool limit, see Step 2. (Swap in the equivalent for your database.)
**Escalate to:** #db-oncall or engineering on-call rotation.

いつ3行を超えて拡張するか: 最初の確認だけでは判断に十分でない場合にのみステップを追加してください。最も一般的な3つの原因をカバーする5ステップのランブックは、すべてのエッジケースをカバーして流し読みされる20ページのドキュメントよりも優れています。

ランブックを最新に保ってください。 インシデントがクローズされるたびに、そのインシデントで使用されたランブックを更新してください — 古いランブックは誤った自信を築きます。ステップが間違っていたり欠けていたりした場合は、インシデントを解決済みとしてマークする前に修正してください。

7. テレメトリ自体を検証する

インストゥルメンテーションはコードです。間違っている可能性があります。作業が完了したと呼ぶ前に、パスをトリガーして実際の出力を確認してください。

  • ステージングでエラーを強制的に発生させる → requestIdでログ内を見つけ、フィールドが構造化されていることを確認する([object Object]ではない)
  • テストトラフィックを送信 → メトリクス系列が期待されるラベルと妥当な値で表示されることを確認する
  • トレーシングUIで1つのリクエストをサービス間で追跡する → 壊れたスパンがないこと
  • 新しいアラートをそれぞれ一度発報させる(一時的にしきい値を下げる) → 正しいチャネルに届き、ランブックリンクが機能することを確認する

よくある言い訳

言い訳現実
「動作確認ができたらログを追加する」「後で」は「最初のインシデントの後」になり、それが最も高くつく瞬間です。構築と同時にインストゥルメントしてください。
「ログが多ければ観測可能性が高い」非構造化ノイズはインシデントを遅くし、速くしません。クエリ可能な3つのイベントが、300行の散文よりも勝ります。
「console.logで十分だ」非構造化出力はフィルタリング、相関付け、アラート設定ができません。構造化ロガーは一度だけの5分の追加コストです。
「何か壊れたらダッシュボードを見ればいい」定義された質問なしで構築されたダッシュボードは、答え以外のすべてを表示します。オンコールの質問から始めてください。
「重要なものすべてにアラートを設定し、後で調整する」ノイズの多いページャーは人々に無視するよう訓練します。調整は決して行われず、本当のページを見逃します。
「ユーザーIDをメトリクスラベルにするとデバッグが楽になる」同時にメトリクスバックエンドをダウンさせます。高カーディナリティのルックアップはログとトレースに属します。
「トレーシングは2つのサービスにはオーバーキルだ」2つのサービスはすでに、ログが答えられないクロスサービスレイテンシの質問を意味します。自動インストゥルメンテーションはコストを些細なものにします。

レッドフラグ

  • リトライ、キュー、または外部呼び出しを含む機能PRで、新しいテレメトリがゼロ
  • 構造化フィールドではなく文字列補間で構築されたログ行
  • 相関/リクエストIDがない — 各ログ行は孤立している
  • スケジューラー、webhook、手動実行によって供給される単一のログストリームで、どのエントリポイントが行を生成したかを示すフィールドがない
  • ユーザーID、生のURL、またはエラーメッセージテキストでラベル付けされたメトリクス(カーディナリティ爆弾)
  • パーセンタイルなしで平均として追跡されたレイテンシ
  • 毎日発報され、アクションなしで確認されるアラート
  • CPUやメモリなどの原因にアラートを設定し、ユーザー向けエラー率は監視されていない
  • ログにシークレット、トークン、または完全なリクエストボディが出現する
  • 「自分のマシンでは動く」が本番機能の健全性の唯一の証拠

検証

機能をインストゥルメントした後、以下を確認してください。

  • この機能に関するオンコールの質問が書き留められ、各シグナルがその1つに対応している
  • すべてのログ出力が構造化(JSON)され、安定したイベント名とすべての行に相関IDがある
  • 複数のエントリポイントによって書き込まれるすべてのログシンクに、実行開始時に設定され、下流で推測されるのではなく相関IDとともに伝播されるエントリポイントフィールドがある
  • ログ行にシークレット、トークン、または編集されていないPIIがない(実際の出力をスポットチェックする)
  • すべての新しいエンドポイントとすべての外部依存関係にREDメトリクスが存在し、ラベルセットが制限されている
  • レイテンシがヒストグラムであり、p95/p99がクエリ可能である
  • 単一のリクエストがトレーシングUIでエンドツーエンドで追跡でき、壊れたスパンがない
  • すべての新しいアラートが症状ベースであり、ランブックリンクがあり、一度テスト発報されている
  • ステージングで誘発された障害が、ソースコードを読まずにテレメトリだけで特定された

このリストの簡易版(リリース前インストゥルメンテーションゲートを含む)については、../../references/observability-checklist.md を参照してください。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

addyosmani/agent-skills

Builds production-quality, accessible, responsive user-facing UIs. Use when building or modifying interfaces and pages, creating components, implementing layouts, meeting WCAG accessibility requirements, managing state, or when the output needs to look and feel production-quality rather than AI-generated.

addyosmani/agent-skills

Prepares production launches. Use when preparing to deploy to production, or when asking what needs to be in place before shipping. Use when you need a pre-launch checklist, when setting up monitoring, when planning a staged rollout, or when you need a rollback strategy.

addyosmani/agent-skills

Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.

addyosmani/browser-testing-with-devtools

Tests in real browsers via Chrome DevTools MCP. Use when building or debugging anything that runs in a browser. Use when you need to inspect the DOM, capture console errors, analyze network requests, profile performance, or verify visual output with real runtime data. Requires the chrome-devtools MCP server to be configured.

addyosmani/ci-cd-and-automation

Automates CI/CD pipeline setup. Use when setting up or modifying build and deployment pipelines. Use when you need to automate quality gates, configure test runners in CI, or establish deployment strategies.

addyosmani/code-review-and-quality

Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.

addyosmani/code-simplification

Simplifies code for clarity. Use when refactoring code for clarity without changing behavior. Use when code works but is harder to read, maintain, or extend than it should be. Use when reviewing code that has accumulated unnecessary complexity.

addyosmani/constraint-driven-development

Establishes a project's quality bar as a written contract and stops agents quietly lowering it. Interviews the user on which dimensions matter, supplies sane default thresholds when they have no number in mind, records everything in CONSTRAINTS.md, and watches the diff for a weakened bar — new @ts-ignore or eslint-disable suppressions, skipped or deleted tests, assertions stripped out, unimplemented stubs, thresholds edited down. Use when no quality bar is written down, when the user says "set up constraints" or "define our standards", when the user wants dimensions they care about — accessibility, web performance, coverage — set up as enforced constraints, when an agent keeps silencing checks or skipping tests to get to green, when you need a coverage or performance threshold and don't know what number to pick, or when an agent writes more code than anyone will read.

addyosmani/debugging-and-error-recovery

Guides systematic root-cause debugging. Use when tests fail, builds break, behavior doesn't match expectations, or you encounter any unexpected error. Use when you need a systematic approach to finding and fixing the root cause rather than guessing.

addyosmani/deprecation-and-migration

Manages deprecation and migration. Use when removing old systems, APIs, or features. Use when migrating users from one implementation to another. Use when deciding whether to maintain or sunset existing code.

addyosmani/documentation-and-adrs

Records decisions and documentation. Use when making architectural decisions, changing public APIs, shipping features, or when you need to record context that future engineers and agents will need to understand the codebase.

addyosmani/doubt-driven-development

Subjects every non-trivial decision to a fresh-context adversarial review before it stands. Use when correctness matters more than speed, when working in unfamiliar code, when stakes are high (production, security-sensitive logic, irreversible operations), or any time a confident output would be cheaper to verify now than to debug later.

addyosmani/git-workflow-and-versioning

Structures git workflow practices. Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams.

addyosmani/idea-refine

Refines raw ideas into sharp, actionable concepts through structured divergent and convergent thinking. Use when an idea is still vague, when you need to stress-test assumptions before committing to a plan, or when you want to expand options before converging on one. Triggers on "ideate", "refine this idea", or "stress-test my plan".

addyosmani/incremental-implementation

Delivers changes incrementally. Use when implementing any feature or change that touches more than one file. Use when you're about to write a large amount of code at once, or when a task feels too big to land in one step.

addyosmani/interview-me

Extracts what the user actually wants instead of what they think they should want. Achieves this through one-question-at-a-time interview until ~95% confidence about the underlying intent. Use when an ask is underspecified ("build me X" without "for whom" or "why now"), when the user explicitly invokes ("interview me", "grill me", "are we sure?", "stress-test my thinking"), or when you catch yourself silently filling in ambiguous requirements before any plan, spec, or code exists.

addyosmani/performance-optimization

Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.

addyosmani/planning-and-task-breakdown

Breaks work into ordered tasks. Use when you have a spec or clear requirements and need to break work into implementable tasks. Use when a task feels too large to start, when you need to estimate scope, or when parallel work is possible.

addyosmani/security-and-hardening

Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.

addyosmani/source-driven-development

Grounds every implementation decision in official documentation. Use when you want authoritative, source-cited code free from outdated patterns. Use when building with any framework or library where correctness matters.

関連スキル