作ったスパンはどこで消えたのか
目標
実際のOpenTelemetry Python SDKのコードを直して、スパンが消えた境界が、生成・サンプリング・終了・送信のどこなのかを、観測で区別します。接続関数7個と総合レポートを作ります。
なぜ重要なのか
trace IDがあり、flushがTrueでも、目的のスパンが受信されたという意味ではありません。このラボは、実際のSDK 1.44.0と公式のOTLP/HTTPエクスポーターを使います。エクスポーターは、ラボのコンテナ内のループバック受信器にprotobufを送信します。受信器は、一部の実行で、意図的にHTTP 400を返します。これは、エラーを再現するための条件です。
Collector・Jaeger・外部ストレージは使いません。実験用の受信器の受理を検証するものであり、永続保存や運用デプロイの成功にまで広げて解釈することはしません。SDKと依存関係は、専用環境にあらかじめインストールされているため、APIキーやネットワーク経由のインストールは必要ありません。
準備と実行
作業ディレクトリは/root/otca-sdkです。startersには、文法は正しいものの、動作が間違っているファイルが8個あります。各ステップのファイル形式の例も、同じ開始コードです。該当するファイルを作業ディレクトリへコピーして、直してください。たとえば、最初のファイルは、次のように始めます。
cd /root/otca-sdk
cp starters/wiring.py wiring.py
/opt/otel-lab/bin/python /opt/app/otca_sdk/runner.py run 1
runのあとの数字を変えると、該当するステップの実際のSDKの観測と失敗の条件を見られます。SDKの内部クラスや採点を変更せず、与えられた関数のコードを直してください。採点はコピーを実行し、現在の答案ファイルを変更しません。同じ意味のコードでも、実際の動作が合っていれば合格します。通常の採点は最大8秒、総合のコードは全体で50秒の予算に制限し、無限ループと出力の暴走は失敗として扱います。
ステップ
- /root/otca-sdk/wiring.py: wiring.pyのconfigure(provider, exporter)を直して、渡されたproviderで終了したcheckoutスパンがexporterに到着するようにしてください。グローバルなproviderは変更しません。
- /root/otca-sdk/decisions.py: decisions.pyのsampler(mode)は、SDKのSamplerを返します。dropはDROP、recordはRECORD_ONLY、sampleはRECORD_AND_SAMPLEの動作を満たすようにしてください。
- /root/otca-sdk/parents.py: parents.pyのparent_sampler()を直して、親のないrootは捨て、リモート・ローカルの子は、親のsampledの決定に従うようにしてください。親のtrace IDとspan IDの接続は維持します。
- /root/otca-sdk/errors.py: errors.pyのrecord_failure(span, error)は、すでに捕捉された注文検証の例外を受け取ります。元の例外のexceptionイベントを残し、スパンの状態もERRORに指定してください。
- /root/otca-sdk/lifecycle.py: lifecycle.pyのfinish(span, provider)を直して、スパンを終了し、そのあとでforce_flushを呼び出して、その返り値を返してください。関数が戻る前に、実験用の受信器がcheckoutスパンを1つ受理している必要があります。
- /root/otca-sdk/delivery.py: delivery.pyのdelivered(observation)は、ブール値を返します。flush、exporter_results、accepted_spansを合わせて見て、HTTP 200の受理だけをTrue、HTTP 400の拒否と未終了のスパンはFalseと判定してください。
- /root/otca-sdk/identity.py: identity.pyのresource(service_name)は、SDKのResourceを返します。受け取ったサービス名をservice.nameのリソース属性に設定してください。checkout-apiとreturns-apiの2つのケースで、実際に受信されたスパンを確認します。
- /root/otca-sdk/report.json: report.jsonの8つのブール値の仮説を、理論と実際の観測に合わせて判定してください。文字列や数値ではなくJSONのブール値を書き、前の7つのステップのコードもすべて動作する必要があります。
参考
- サンプリングのステップで、4つの数値は、記録されているか・sampled・processorの終了観測・exporterのスパン数です。
- 親ポリシーでは、root、リモートのsampled/unsampled、ローカルのsampled/unsampledをすべて試験します。
- deliveredに渡されるobservationのflushはSDKの返り値、exporter_resultsはエクスポーターの返り値のリスト、accepted_spansは実験用の受信器がHTTP 200で受理したスパン数です。
- レポートは、record_only_recording、record_only_exported、parentbased_respects_unsampled_parent、always_on_can_sample_child、exception_event_sets_status、flush_ends_open_span、http400_flush_can_be_true、receiver_acceptance_proves_storageの8つのキーを使います。
- 前のステップの準備は、存在しない以前の答案だけを埋めます。すでに書いた途中までの答案や、現在のステップの答えは上書きしません。
- Podは一時的な環境です。セッションが終了する前に、必要なコードと観測を別に保管してください。
スパンをエクスポーターまでつなぐ
/root/otca-sdk/wiring.py: wiring.pyのconfigure(provider, exporter)を直して、渡されたproviderで終了したcheckoutスパンがexporterに到着するようにしてください。グローバルなproviderは変更しません。
tracerを取得することと、送信経路を接続することは別です。providerに登録するprocessorを確認してください。
記録とサンプリングを分離する
/root/otca-sdk/decisions.py: decisions.pyのsampler(mode)は、SDKのSamplerを返します。dropはDROP、recordはRECORD_ONLY、sampleはRECORD_AND_SAMPLEの動作を満たすようにしてください。
記録されているか、sampledビット、プロセッサーの観測、エクスポーターの観測の4つの値を、一緒に比べてください。
親ポリシーの適用範囲を直す
/root/otca-sdk/parents.py: parents.pyのparent_sampler()を直して、親のないrootは捨て、リモート・ローカルの子は、親のsampledの決定に従うようにしてください。親のtrace IDとspan IDの接続は維持します。
AlwaysOff単体と、ParentBasedのroot=AlwaysOffは違います。親の4つのケースとrootを区別してください。
捕捉した例外をエラーとして分類する
/root/otca-sdk/errors.py: errors.pyのrecord_failure(span, error)は、すでに捕捉された注文検証の例外を受け取ります。元の例外のexceptionイベントを残し、スパンの状態もERRORに指定してください。
record_exceptionを呼び出したあとのstatusを見てください。イベントと最終的な業務状態は、同じフィールドではありません。
開いたスパンを終了して出力する
/root/otca-sdk/lifecycle.py: lifecycle.pyのfinish(span, provider)を直して、スパンを終了し、そのあとでforce_flushを呼び出して、その返り値を返してください。関数が戻る前に、実験用の受信器がcheckoutスパンを1つ受理している必要があります。
受信が0個なのにflushがTrueなら、スパンがまだ開いたままになっていないかを確認してください。採点側の片付けの動作は、受講者の成功として数えません。
返り値だけを信じていた判定を直す
/root/otca-sdk/delivery.py: delivery.pyのdelivered(observation)は、ブール値を返します。flush、exporter_results、accepted_spansを合わせて見て、HTTP 200の受理だけをTrue、HTTP 400の拒否と未終了のスパンはFalseと判定してください。
receivedに本文があるからといって、受理されたわけではありません。exporterの結果とaccepted_spansを確認してください。
サービスと現在のリクエストをつなぐ
/root/otca-sdk/identity.py: identity.pyのresource(service_name)は、SDKのResourceを返します。受け取ったサービス名をservice.nameのリソース属性に設定してください。checkout-apiとreturns-apiの2つのケースで、実際に受信されたスパンを確認します。
tracerの名前やスパンの一般属性と、Resourceを区別してください。例のサービス名を1つ、コードに固定しないでください。
消えた境界を総合的に判定する
/root/otca-sdk/report.json: report.jsonの8つのブール値の仮説を、理論と実際の観測に合わせて判定してください。文字列や数値ではなくJSONのブール値を書き、前の7つのステップのコードもすべて動作する必要があります。
記録・サンプリング・終了・送信・受理・保存のうち、どの境界を証明したのかを区別してください。レポートだけ合っていてコードが間違っていると、総合検証は失敗します。