テレメトリ

システムの状態をメトリクス、ログ、トレースの 3 本柱で収集 / 送信する仕組み

オブザーバビリティ運用

テレメトリとは

テレメトリ (Telemetry) は、システムの状態をメトリクス、ログ、トレースの 3 本柱 (Three Pillars of Observability) で収集 / 送信する仕組みである。計測する側 (アプリケーション) と受け取る側 (監視サービス) の間で作法を決めておかないと、監視サービスを乗り換えるたびに計装コードを書き直すことになる。この境界を仕様として切り出したのが OpenTelemetry で、公式サイトの記載では CNCF のガバナンスの下で仕様と各言語の SDK が開発されている。仕様の成熟度や導入手順は OpenTelemetry の項に譲る。

3 本柱

3 つは並列に見えるが、実務で差が出るのは種類の数ではなく粒度とコストである。メトリクスは集計済みの数値なので長く安く持てて異常の検知に向く。ログは 1 件ずつの事実なので原因の特定に効くが量が増える。トレースは 1 リクエストが通った経路を時間軸に並べたもので、どの処理で待たされたかを示す。検知はメトリクス、経路の絞り込みはトレース、確定はログという順に降りるのが基本形だ。

柱説明AWS サービス
メトリクス数値データ (CPU, レイテンシ, エラー率)CloudWatch Metrics
ログイベントの記録CloudWatch Logs
トレースリクエストの経路追跡X-Ray

OpenTelemetry

計装のコードは、処理を span という単位で囲み、その span に属性と結果を付ける形になる。span を閉じ忘れると終わらないまま残るので、finally で必ず end を呼ぶのが定型だ。結果は生の数値ではなく列挙値 (SpanStatusCode) で表し、既定が UNSET、成功を明示するときが OK、失敗が ERROR である。

import { trace, SpanStatusCode } from '@opentelemetry/api';

const tracer = trace.getTracer('my-service');

export async function handleRequest(event: any) {
  const span = tracer.startSpan('handleRequest');
  try {
    span.setAttribute('user.id', event.userId);
    const result = await processOrder(event);
    span.setStatus({ code: SpanStatusCode.OK });
    return result;
  } catch (e) {
    span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
    throw e;
  } finally {
    span.end();
  }
}

カスタムメトリクス

メトリクスは 3 本柱のうち最も安く長く保持できるので、業務上の意味を持つ数値 (注文が通った件数、決済が失敗した回数) を自分で送っておくと効く。ディメンションには後から切り分けたい軸だけを入れる。

import { CloudWatch } from '@aws-sdk/client-cloudwatch';

const cw = new CloudWatch({});

await cw.putMetricData({
  Namespace: 'MyApp',
  MetricData: [{
    MetricName: 'OrderProcessed',
    Value: 1,
    Unit: 'Count',
    Dimensions: [{ Name: 'Environment', Value: 'prod' }],
  }],
});

構造化ログ

テレメトリの基盤となるログは、JSON 形式の構造化ログで出力する。フィールド単位でクエリ / 集計が可能になり、CloudWatch Logs Insights でリクエスト ID やエラーコードを条件にした分析が行える。

// ✅ 構造化ログ (JSON)
console.log(JSON.stringify({
  level: 'info',
  message: 'Order processed',
  orderId,
  duration: 150,
  timestamp: new Date().toISOString(),
}));

テレメトリの設計指針

メトリクスのディメンションにユーザー ID のように取り得る値が際限なく増える項目を入れると、組み合わせの数だけ時系列が作られて保存量と課金が膨らむ。個別の識別子はメトリクスではなくログやトレースの属性側へ置き、メトリクスは環境名や API 名のように値を数え上げられる軸だけで区切る。

トレースを全リクエスト分送れば取り込み量はリクエスト数に比例するので、間引き (サンプリング) を前提に設計する。ただし間引くと「この 1 件だけ調べたい」が成立しなくなるため、エラーや遅い応答は必ず残すという条件を先に決めておく。

3 本柱が効くのは互いに紐付いているときだけだ。ログとトレースが別々に貯まっているだけでは、遅いトレースを見つけてもその瞬間のログを引き当てられない。トレース ID を構造化ログのフィールドとして出し、メトリクスの異常から該当時間帯のトレースへ、そこから同じ ID を持つログへと辿れる状態を作っておく。

テレメトリは運用のためのデータだが、中身は利用者の行動そのものである。属性に個人情報 / 認証情報 / リクエストの生の本文を入れない、収集する項目は決めておいて増やすときに見直す、外部の監視サービスへ送るなら送信先と保存期間を把握しておく。ライブラリや利用者の端末側で計測を仕込む場合は、収集を止められる手段を用意しておくことが前提になる。

共有:

この記事は役に立ちましたか?

関連用語

関連する記事