本文へスキップ
CoRISE

OpenTelemetryを入れた後の問い — 障害を説明できる信号になっているか

Question InventoryとSignal Contractを起点に,Resource・相関・Samplingの品質を点検し,障害を説明できるかを受入確認と訓練で確かめます.

T. Asano公開 更新 約18分で読めます
  • Observability
  • Operations
  • Reliability
目次を開く

Traceが届いた後に,何を確認するか

OpenTelemetryを導入し,TraceがBackendへ届く.MetricsもLogsも表示できる.これは収集経路が動いたという重要な一歩です.次に確かめたいのは,障害時にそのSignalを使って説明を組み立てられるかです.

例えば「Deployment後から,一部の顧客だけCheckoutが遅い」と問い合わせが来たとします.どのVersion,どのDependency,どのRequestに共通点があるか.同じ処理のLogは何を示すか.最初に用意したDashboardの外へ進み,その場で生まれた問いを調べられるでしょうか.OpenTelemetryのObservability Primerも,事前に想定しなかった問題について問いを立て,内部状態を外部から理解することを重視しています.[1]

本稿は監視から可観測性への運用モデルと,VectorとOpenTelemetry Collectorの収集経路を踏まえ,集めたSignalの品質をどう確かめるかを扱います.

サンプル一式にはQuestion Inventory,Signal Contract,Sampling設定の断片,受入確認と障害訓練の計画を収録しています.架空のCheckoutを題材とした設計資料です.Collector設定の検証・起動,SDK計装,Backendへの送信,障害注入,時間測定は実行していません.実行状態はすべてNOT_RUNとし,改善効果を実測した記事とは区別します.

1.最初にQuestion Inventoryを作る

InstrumentationをSpanやMetricの一覧から始めると,「取れるData」の範囲に問いが引かれます.先に,運用者が判断するために何を知りたいかを書きます.

問い必要なEvidence確認する経路
Q1:いつから,どれだけ影響したかRequest量,Latency分布,最終OutcomeService Metricと対象期間
Q2:どのVersion・Cellか実際に稼働するResource IdentityVersion・Cell別の比較
Q3:どのDependencyで待ったかRequest全体と依存Callの時間関係Traceの親子関係とCritical Path
Q4:一部だけなら共通点は何かProvider,Tier,Feature Variant許可したAttributeで絞り込み
Q5:Retryで回復したのかAttemptと最終OperationのOutcomeSpan,Event,構造化Log
Q6:同じ処理の詳細は何かTrace ID・Span IDとResourceTraceとLogの相互参照
Q7:Dataがない理由は何かSampling,遅延,拒否,配送失敗Telemetry Pipelineの独立した観測

横にスクロールして図全体をご覧いただけます.

問いからEvidenceと受入確認を逆算する どのVersion・Dependency・Requestが影響したかという問いから,必要なContextと相関を決める.SDK,Pipeline,Backendを確認し,未回答をGapへ戻す.Dataの存在だけでは完了としない.
Fig. 01 — 問いからEvidenceと受入確認を逆算する
図を文章で読む

どのVersion・Dependency・Requestが影響したかという問いから,必要なContextと相関を決める.SDK,Pipeline,Backendを確認し,未回答をGapへ戻す.Dataの存在だけでは完了としない.

この表の「答えられる」は,Attribute名が存在するだけでは埋めません.対象環境,期間,検索手順,取得したEvidenceを確認して記録します.未確認,答えられない,対象外も残します.未知の問いをすべて予見することはできませんが,共通のIdentityと比較軸があれば,新しい組合せで調べられます.

2.Service Identityと変更Contextを揃える

Trace Viewerにunknown_serviceが並んでは,発生源の切り分けが難しくなります.最初にResourceの命名と設定経路を揃えます.service.name,service.namespace,service.version,deployment.environment.nameを,本稿の例では組織内の必須項目にします.OpenTelemetryの全項目が仕様上必須という意味ではありません.[2][3]

# Illustrative staging identity; SDK support for env configuration varies.
export OTEL_SERVICE_NAME=checkout-api
export OTEL_RESOURCE_ATTRIBUTES='service.namespace=commerce,service.version=1.0.0,deployment.environment.name=staging'

service.instance.idはReplica間の違いを調べる際に有用です.Pod UID等を利用する場合も,実際のService Instanceを識別できる単位を選びます.一つのPod内に異なるServiceがある場合などは,単純な付与で十分かを確認します.Resource AttributeをすべてMetric Labelへ自動展開する必要はありません.[2]

VersionとLatencyが同時に変わっても,それだけで因果関係は確定しません.新Versionだけ別Regionにある,負荷やTenant構成が違う,Feature Flagも変わった,という交絡があり得ます.TelemetryのVersionは「どの変更を疑い,比較するか」のEvidenceです.

Deployment Event,Config Revision,Feature Variantも必要に応じて関連付けます.Git上の予定版ではなく,実際に動くProcessが報告する版を確認します.Environmentは検索上の重要な軸ですが,Service Identityそのものとの扱いを混同せず,QueryではNamespaceやEnvironmentも明示します.

3.Spanを運用上の責任境界へ置く

自動計装でHTTPとDatabaseのEdgeを押さえ,業務上必要な意味を追加します.すべてのFunctionをSpanにする必要はありません.公式のLibrary向けGuidanceも,利用者に意味のあるOperationを中心に計装する方針を示しています.[4]

POST /checkout
├─ inventory.reserve
├─ payment.authorize
│  ├─ payment.attempt  [timeout]
│  └─ payment.attempt  [success]
└─ db.create_order

Span名はOperation Classとし,注文IDや顧客IDを埋め込みません.HTTPのPathは/orders/{id}のようなRoute Templateで集約し,実URLやQuery Stringの無制限な記録を避けます.Domain Attributeは例えばcorise.payment.providerとし,独自語彙であることを明確にします.

「Payment Spanが1.6秒だった」ことは,そのCall区間で時間を使ったEvidenceです.Remote ServerのCPUが原因とまでは分かりません.Connection Pool待ち,DNS,Network,Retryを含む可能性があります.並列Spanの所要時間を単純に足すこともできません.重なりと待ち合わせを見て,Critical Pathを調べます.

処理Errorの扱い
個別AttemptがTimeoutそのAttemptを失敗として記録
Retry後にAuthorizeが成功Authorize全体へ回復済みのErrorを持ち上げない
Checkoutが最終的に失敗Rootの最終Outcomeを失敗として記録
HTTP 404Client / Server SpanのConventionとOperationの意味を確認

一般的なHTTP計装では,4xxに対するClientとServerのStatus規則が異なります.Business上の拒否とも区別します.Exceptionの記録だけでSpan Statusが自動設定されると仮定せず,利用するAPIを確認します.成功は通常UNSETでよく,何でも明示的にOKへ上書きする必要はありません.[5][6]

4.Contextを伝搬し,Logとの往復を確かめる

HTTPだけでなく,Queue,Task,Callbackを跨ぐ箇所を確認します.OutboundでInjectし,InboundでExtractする経路があっても,非同期処理でActive Contextを失えば,関係のないSpanやLogになることがあります.[4]

QueueのWorkerが別Traceを開始すること自体は問題ではありません.長時間Job,Batch,複数MessageのFan-inでは,Parentを一つに固定するよりSpan Linkが適する場合があります.Messaging Convention,実装,BackendのLink表示・検索まで含めて,因果関係を追えるかを判断します.「同じTrace IDにする」だけを受入条件にしません.[7]

{
  "event": "payment.attempt.failed",
  "severity": "WARN",
  "trace_id": "0123456789abcdef0123456789abcdef",
  "span_id": "0123456789abcdef",
  "error.type": "timeout",
  "corise.payment.provider": "provider-a",
  "corise.retry.attempt": 1
}

これは構造化Logの説明用表現であり,OTLP Wire Formatではありません.実際のLogRecordにはResource,Timestamp,TraceId,SpanId等を適切に載せます.既存Loggerに相関Bridgeを設定し,TraceからLog,LogからTraceへ移動できるBackend設定まで確かめます.Trace IDがLogにあっても,参照先Traceが保存されているとは限りません.[9]

Rustのtracingを使う場合も,SpanからOpenTelemetryへの接続と,LogのExport・相関を別に確認します.tracing-opentelemetryを加えただけで全LogがOTel Logsとして配送されるとは限りません.SDK,Bridge,Runtime,Exporterの版と設定を揃えて確認します.[14]

5.MetricsからTraceへ進む導線と限界

Latency Histogramで悪化を見つけ,対象RequestのTraceで待ち時間を調べ,Logで詳細を読む.この往復ができると調査は進めやすくなります.

横にスクロールして図全体をご覧いただけます.

MetricからTraceとLogへ進み,参照切れも扱う 影響は集約Metric,待ち時間はTrace,詳細はLogで調べる.Exemplarは任意の参照で,Trace保存やp99代表性を保証しない.期間・Service・Version検索を代替経路にする.
Fig. 02 — MetricからTraceとLogへ進み,参照切れも扱う
図を文章で読む

影響は集約Metric,待ち時間はTrace,詳細はLogで調べる.Exemplarは任意の参照で,Trace保存やp99代表性を保証しない.期間・Service・Version検索を代替経路にする.

ExemplarはMetricの集約に関連する具体的なObservationを保持し,Trace IDやSpan IDを含むことがあります.SDKのReservoir・Filter,Exporter,Collector,Backend,UIの対応が必要です.Exemplarはp99を作った唯一のRequestでも,必ずSlow Requestを指すものでもありません.[10]

さらにTail Samplingが参照先を落としたり,TraceとMetricの保持期間が異なったりするとLink切れになります.Exemplarが使えない場合も,Service・Version・期間を渡してTrace検索へ進める導線を用意します.

ユーザー影響を測るRequest数,Error Rate,Latencyは,Traceの選別と独立した計測経路を基本にします.Error・Slowを優先保持したTrace集合から,無補正で全体のError Rateやp99を計算してはいけません.Spanから作るMetricの場合は,どのSamplingより前に計算しているかを確認します.

Histogramの集計も,Instance別のp99を平均する方法では全体のp99になりません.互換性のあるBucket等を集計してからQuantileを求めます.直接計測したMetricsにもExportの欠落はあり得るため,「非Sampling」と「欠損なし」は分けます.

6.AttributeにCardinality・機密性・信頼境界を持たせる

「Tenant Aだけ遅い」を調べるために,全Tenant IDをすべてのMetricへ付ける必要はありません.MetricsにはTierやCell等の上限を管理できる軸を使い,個別調査のIDは必要性とアクセス権を確認したTrace / Logに限定します.Trace側でもIndex Costや保持量は増えます.

Opaque IDやHashは,自動的な匿名化ではありません.再識別や外部Dataとの結合が可能かを考えます.Payload,Authorization Header,Token,メールアドレス等を安易に送らず,Attribute,Span名,Event,Log Body,Exceptionを含めて収集許可を決めます.

Baggageは伝搬用のContextです.それだけでSpan・Metric・Log Attributeへ自動追加されるわけではなく,明示的な転記やProcessorが必要です.また組込みの完全性保証がなく,第三者APIへ流れる可能性があります.[8]

Untrusted inbound baggage
  → validate / allowlist / discard at the boundary
  → approved diagnostic context
  → explicit signal attributes where needed

role=adminやtenant_idを受け取っただけで認可しません.認証済みIdentityとPolicyから判断し,観測用Contextも必要ならそこから再構築します.外向きの伝搬には宛先別の制御を設けます.

7.SamplingをEvidenceの保持方針として設計する

Error,Slow,正常Baselineを残したい.この方針は有用ですが,「すべてのErrorを必ず残せる」とは言えません.Head Samplingで生成・ExportされなかったSpanを,Tail Samplingは復元できません.

以下はCollector Contrib v0.161.0を参照した未検証の設定断片です.Receiver,Exporter,Memory Limit,TLS,認証,Trace ID Routingは含みません.数値は説明用で,Capacityの推奨値ではありません.[11]

# Reference: Collector Contrib v0.161.0. NOT validated or executed.
# Fragment only: no receiver/exporter/TLS/auth/routing/memory limit.
# Illustrative values, not a sizing recommendation.
processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 50000
    policies:
      - name: errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: slow
        type: latency
        latency:
          threshold_ms: 1000
      - name: baseline
        type: probabilistic
        probabilistic:
          sampling_percentage: 5

この単純な構成は,ErrorまたはSlowに一致するTraceと,確率Policyに選ばれるBaselineを保持する意図です.5%は総保持率でも保証された実測比率でもありません.複数Policyの組合せ,Drop Policy,Feature Gateを変更した場合はDecisionの意味を再確認します.

横にスクロールして図全体をご覧いただけます.

Tail Samplingへ届く前後の欠落を分ける Head判断,SDK Export,Trace ID Routing,Tail判断,Backend保存の各段階に条件がある.ErrorやSlowの保持Policyは,未生成SpanやLate Span,障害による欠落を回復しない.
Fig. 03 — Tail Samplingへ届く前後の欠落を分ける
図を文章で読む

Head判断,SDK Export,Trace ID Routing,Tail判断,Backend保存の各段階に条件がある.ErrorやSlowの保持Policyは,未生成SpanやLate Span,障害による欠落を回復しない.

Tail Samplerには同じTraceのSpanを同じInstanceへ集める必要があります.Scale変更でRouting先が変わる場合や,Collector再起動,Buffer上限,判断後のLate Spanを考慮します.decision_waitは最初のSpanを受けてからの判断待ち時間で,任意長のTraceの完了保証ではありません.

Latency Policyも,観測した最早Startと最遅Endの区間に基づきます.Rootのユーザー向けLatencyと一致するとは限らず,長い非同期Jobが同じTraceなら意味が変わります.AttemptのErrorを残す方式と,成功Operation中のRetry Eventだけを残す方式でも,Status Policyへの一致が変わります.[11]

8.Collectorの順序と欠落を観測する

Processor順序はComponentの依存で決めます.Memory Limiterを早い段階へ置き,元の接続Contextを使うk8sattributes等は,Spanを再Batch化するTail Samplerより前に置きます.Sampling条件に必要なAttributeの補完も先です.Batchは通常その後に置きます.「Samplingを常にEnrichmentより先にする」という一律の順序にはできません.[11]

共有Gatewayでdeployment.environment.name=productionを無条件upsertすると,StagingのDataまでProductionに見える可能性があります.信頼する収集元の識別,経路分離,矛盾時の拒否・隔離を設計します.Resource補完は単なる文字列の書換えではありません.

Health CheckのSpanをFilterする場合も,Rootだけを消してChildを残さないか,別用途の同じPathを落とさないかを確認します.削除対象がMetric,Log,Traceのどこまでかも明記します.

Collector自身について,受信・拒否,Sampling判断,Queue,Export失敗,Backendでの検索可能性を追います.受信数から送信数を引いた値を,そのままDrop Rateと呼ばないことが重要です.Batch,Fan-out,Retry,意図したSampling,観測窓の差があり,失敗Counterも再送成功前の試行を含み得ます.Metric名・単位・Suffixは利用版とExporterで確認します.[12]

Applicationが静かなのか,収集経路が壊れたのかを区別するため,同じ故障領域だけに依存しない観測点を用意します.Exporterの成功応答も,Backend UIで直ちに検索できることと同じではありません.

9.Signal Contractを受入確認へ落とす

契約の単位を重要なUser Journeyにします.本稿の例では,CheckoutのEntry,Dependency,最終Outcome,相関,許可したContextをまとめます.

{
  "id": "OBS-CHECKOUT-001",
  "status": "NOT_RUN",
  "journey": "checkout",
  "resource": {
    "required_by_this_contract": [
      "service.namespace",
      "service.name",
      "service.version",
      "deployment.environment.name"
    ],
    "conditional": ["service.instance.id", "corise.deployment.cell"],
    "authority": "runtime deployment identity; reject/quarantine conflicts before trusted enrichment"
  },
  "operations": {
    "entry": "HTTP POST /checkout using route-template naming",
    "dependencies": ["inventory.reserve", "payment.authorize", "db.create_order"],
    "retry": "failed attempt has ERROR and error.type; recovered parent uses final successful outcome",
    "error_conventions": "apply HTTP client/server and operation-specific semantics; exception recording is not automatic status assignment"
  }
}

標準のHTTP MetricやAttributeが答えを持っているなら,独自の同義Metricを重ねる必要はありません.Domain固有の意味だけを追加し,Instrumentの単位と各Labelの値域も記録します.

受入確認は三層に分けます.

層確認する内容それだけでは確認できないもの
計装In-memory Exporter等でSpan,Outcome,相関,機密Dataの不在を検査Collector以降の配送
Pipeline固定FixtureでResource保持,Policy判断,変換・削除を確認Backendの検索とUI導線
End-to-endSyntheticなJourneyをBackendまで追う未発生の全障害や常時無欠損

SDKのTest APIは言語と版で異なります.非同期Exportの完了やFlushも含めて設計し,概念的なTest Codeを実行済みと扱いません.同梱CSVは確認計画であり,Test Suiteではありません.[4]

10.Synthetic Requestと障害訓練で調査を試す

StagingでPayment Stubだけに遅延を入れ,担当者へ「Checkoutが遅い」と伝えます.実際の決済や通知を起こさない隔離された経路,対象,終了条件,復旧方法を先に決めます.今回の資料に実際の障害注入操作は含めていません.

調査では,Metricで影響を確認し,Exemplarまたは期間検索からTraceへ進み,Dependency,Version,Provider,Logを照合します.「Paymentが遅い」までで止めず,どこまで分かり,どこから仮説なのかを書きます.

Synthetic用HeaderがあるだけでSamplingを強制できる設計にはしません.公開Clientに濫用されない認証済みの仕組みとBudgetが必要です.Correlation IDはSignal間で追えるようにしますが,毎回違うRun IDを通常MetricのLabelへ入れません.少数のRequestだけで確率Sampling率を合否判定することも避けます.

時間を測るなら,障害注入,検知,根拠付きの理解,緩和を開始した時点を区別します.Clock差と訓練への慣れも記録します.「45分から7分へ改善」のような数値は実測前には置きません.同梱のEvidence Recordでは未測定値をnullにしています.

11.答えられなかった問いを変更へ戻す

「Provider別に比較できなかった」なら,単にSpan数を増やすのではなく,不足していた比較軸をIssueへ残します.

OBS-124
Question: Is only provider-a slow?
Current: payment.authorize is visible.
Gap: approved provider identity is absent.
Change: add corise.payment.provider from a bounded allowlist.
Acceptance: compare providers in retained traces and relevant metrics.
Status: proposed / NOT_RUN

不足の原因は計装漏れとは限りません.同じ概念の別名,BackendでIndexされないField,保持期間の不一致,Sampling,権限,Noiseも調べます.必要ならSpan削減や検索導線の変更が解決策です.

横にスクロールして図全体をご覧いただけます.

答えられなかった問いを次のInstrumentationへ戻す 障害や訓練の問いから,Evidence Gap,Contractと計装・Queryの変更,三層の受入確認へ進む.OwnerとVersionを結び,実測した結果だけを完了Evidenceとする.
Fig. 04 — 答えられなかった問いを次のInstrumentationへ戻す
図を文章で読む

障害や訓練の問いから,Evidence Gap,Contractと計装・Queryの変更,三層の受入確認へ進む.OwnerとVersionを結び,実測した結果だけを完了Evidenceとする.

SDK・Collector・Semantic ConventionのUpgradeもData Contractの変更です.例えば旧deployment.environmentからdeployment.environment.name,Database属性のdb.system.nameなど,参照版の名前と安定性を確認します.すべてのConventionが同じ成熟度ではありません.Query,Dashboard,Alert,旧版との併存期間を含めて移行します.[3][13]

Platformは収集経路と共通Schema,Application TeamはDomainの意味,Operationsは調査の問いと導線を担います.Owner未割当の項目を,合意済みの運用契約とは扱いません.

12.導入の完了条件を「説明できる」にする

Release Reviewでは,「Traceが出るか」に加えて,次のFeatureが遅くなったときにどのEvidenceを見るかを確認します.重要なDependencyが見え,Version・Outcome・相関が揃い,Samplingと欠落の限界を説明できる状態を目指します.

検知と説明は分けて設計できますが,MonitoringとObservabilityの間に厳密な二分法があるわけではありません.Metricsも原因調査に役立ち,Traceも異常の入口になります.User Impactに基づくPageと,詳しく調べるためのSignalの責任を分けることが実務上有用です.

完了条件は,Question Inventoryの重要項目について,担当者が実際の収集経路とBackendを使い,根拠と限界を記録して答えられることです.新しい問いを完全に予見するのではなく,問いを組み替えて調べ,不足を次のInstrumentationへ戻せるようにします.

Signalの量から,説明に使えるEvidenceへ. OpenTelemetry導入後に育てるのは,Resource,Context,意味,相関,保持方針を一緒に更新するこの開発ループです.

関連する可観測性基盤への刷新は担当範囲と設計判断の文脈です.本稿のCheckout,設定断片,受入計画,訓練結果を,その案件の実施済みEvidenceとして扱うものではありません.

監視系の共倒れと外部の通知経路は,監視基盤の停止を誰が知るかで扱います.

参考資料

公式資料のSource RevisionとCollector Contribの参照Releaseを固定しています.これは編集上の参照版であり,稼働中の構成や互換性を検証した版ではありません.

  1. Observability Primer
  2. Service Resource
  3. Deployment Environment (Deprecated deployment attributes)
  4. Instrumenting Libraries
  5. Recording Errors
  6. HTTP Spans
  7. Messaging Spans
  8. Baggage
  9. Logs Data Model
  10. Metrics Data Model / Exemplars
  11. Tail Sampling Processor v0.161.0
  12. Collector Internal Telemetry
  13. Database Spans
  14. tracing-opentelemetry 0.33.0 README

T. Asano

T. Asanoの記事を読む

Contact

技術的な課題を、お聞かせください。

設計や実装、運用の課題について、CoRISEにご相談いただけます。

相談する