注文は6件なのにダッシュボードは9件を描いた
目標
実際のOpenTelemetry Python SDKで、リーダーのtemporality、デフォルトのヒストグラムの境界、ビューで境界・属性・破棄を変える方法、非同期計測器の報告方式を順に計測し、3つのビューを1つのMeterProviderに組み立てます。
なぜ重要なのか
同じカウンターでも、累積(cumulative)で送るか、デルタ(delta)で送るかによって、バックエンドが解釈すべき意味が変わります。両者を混ぜて読むと、注文が二重に数えられ、秒単位の値をミリ秒用のデフォルトの境界に入れると、ヒストグラムが1つのバケットに集中して、分位数が無意味になります。顧客IDのような属性は、データポイントを増やしてコストを膨らませます。計装コードを変更せず、SDKの設定(リーダー・ビュー)でこれを正すのが、APIとSDKを分けた理由です。
用意されている環境
/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py initが、/root/otca-metrics/にshop.py(注文・カート・決済時間・デバッグのメトリクスを決まった順序で記録)とpipeline.py(埋める関数7個)を置きます。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show Nは、皆さんのpipeline.pyで、lab-devイメージのOpenTelemetry Python SDK 1.44.0(/opt/otel-lab)のMeterProviderを組み立て、shopが記録したあとに2回収集したデータポイントを出力します。ネットワーク・コレクター・APIキーは使いません。採点は、同じSDKで皆さんの関数を再実行し、動作と書かれた数字を照合します。必ず/opt/otel-lab/bin/pythonで実行してください。
ステップ
/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py initで材料を作成します。/root/otca-metrics/pipeline.pyのreader_cumulative()がデフォルトのInMemoryMetricReaderを返すように直してから、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1を実行してください。shop.pyは、注文を3件記録して収集し、さらに3件記録して、再び収集します。/root/otca-metrics/01-cumulative.txtにfirst=、second=(ordersの合計)を書いてください。reader_delta()がCounterだけをDELTAで要求するリーダーを返すように直し、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2を実行します。/root/otca-metrics/02-delta.txtに、first=、second=と、double_counted=(ステップ1の累積値2つをデルタと勘違いして足したときに、ダッシュボードが描く合計)を書いてください。reader_all_delta()が、Counter・UpDownCounter・Histogram・ObservableCounterをすべてDELTAで要求するように直し、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3を実行します。/root/otca-metrics/03-updown.txtに、cumulative_second=(reader_deltaで見たcart.itemsの2回目の値)とdelta_second=(reader_all_deltaで見た値)を書いてください。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4で、ビューなしで収集したcheckout.duration(単位s、値0.2・0.35・0.8・1.4)のヒストグラムを見ます。/root/otca-metrics/04-default-buckets.txtに、boundaries=(デフォルトの境界の個数)、nonzero_bucket_index=(値が入ったバケットの位置、0から)、nonzero_bucket_count=を書いてください。views_buckets()が、checkout.durationにだけ境界0.25、0.5、1、2を適用するViewのリストを返すように直します。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5の結果のバケットごとの件数を、/root/otca-metrics/05-view-buckets.txtにbucket_counts=(カンマ区切り、最後は2超過)として書いてください。ほかのメトリクスはそのまま残る必要があります。views_cardinality()が、ordersの属性キーをrouteだけ残すViewのリストを返すように直します。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6を見て、/root/otca-metrics/06-view-attributes.txtに、points_before=(ビューなしの最初の収集でのordersのポイント数)、points_after=、checkout_sum=(ビューを設定した最初の収集での/checkoutの値)を書いてください。register_async(meter, source)で、queue.processedはObservableCounterでsource.processed()を、queue.depthはObservableGaugeでsource.depth()を観測するようにします。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7(reader_all_deltaを使用)を見て、/root/otca-metrics/07-async.txtにprocessed_delta_second=、depth_second=を書いてください。sourceは、呼び出しごとにprocessedが10、25、depthが7、4を返します。provider(reader)が、受け取ったリーダーと3つのビュー(ステップ5のバケット、ステップ6の属性の絞り込み、そしてdebug.cache.lookupsを捨てるDropAggregation)を持つMeterProviderを返すように直してください。採点では、reader_all_delta()で2回収集して、orders(routeを基準にしたデルタ)、checkout.duration(新しい境界)、cart.items、破棄されたdebugメトリクスをあわせて確認します。まず/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8で確認してください。
参考
- データポイントのtemporalityは、リーダーが要求した値で決まります。計装コード(shop.py)は、1行も変わりません。
- よくある間違い:
preferred_temporalityにCounterだけを入れて、UpDownCounterも変わると期待すること、非同期カウンターのコールバックで増加分を返すこと、ビューの対象を絞らないことです。 - このラボは、InMemoryMetricReaderで、収集のタイミングを自分で決めます。周期的なリーダーとOTLPエクスポーターのデフォルトのtemporalityは、設定(OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE)によって異なります。
- Metrics data model・Metrics SDK
2回収集すると、3の次は6
/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py initで材料を作成します。/root/otca-metrics/pipeline.pyのreader_cumulative()がデフォルトのInMemoryMetricReaderを返すように直してから、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1を実行してください。shop.pyは、注文を3件記録して収集し、さらに3件記録して、再び収集します。/root/otca-metrics/01-cumulative.txtにfirst=、second=(ordersの合計)を書いてください。
リーダーがtemporalityを別途要求しなければ、SDKは開始時点からの累積値を送ります。
デルタで受け取ると、そして混ぜて読むと
reader_delta()がCounterだけをDELTAで要求するリーダーを返すように直し、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2を実行します。/root/otca-metrics/02-delta.txtに、first=、second=と、double_counted=(ステップ1の累積値2つをデルタと勘違いして足したときに、ダッシュボードが描く合計)を書いてください。
preferred_temporalityは、計測器クラスからtemporalityへの辞書です。累積値を足すと、前の区間が二重に数えられます。
UpDownCounterは別に要求する必要がある
reader_all_delta()が、Counter・UpDownCounter・Histogram・ObservableCounterをすべてDELTAで要求するように直し、/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3を実行します。/root/otca-metrics/03-updown.txtに、cumulative_second=(reader_deltaで見たcart.itemsの2回目の値)とdelta_second=(reader_all_deltaで見た値)を書いてください。
reader_deltaはCounterだけを変更しました。カートは、+5、-2のあとに+1が記録されます。
秒単位の値が1つのバケットに集中した
/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4で、ビューなしで収集したcheckout.duration(単位s、値0.2・0.35・0.8・1.4)のヒストグラムを見ます。/root/otca-metrics/04-default-buckets.txtに、boundaries=(デフォルトの境界の個数)、nonzero_bucket_index=(値が入ったバケットの位置、0から)、nonzero_bucket_count=を書いてください。
SDKのデフォルトの境界は、ミリ秒単位のレイテンシを想定した値です。最初の境界と2つ目の境界を見てください。
ビューで境界を変える
views_buckets()が、checkout.durationにだけ境界0.25、0.5、1、2を適用するViewのリストを返すように直します。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5の結果のバケットごとの件数を、/root/otca-metrics/05-view-buckets.txtにbucket_counts=(カンマ区切り、最後は2超過)として書いてください。ほかのメトリクスはそのまま残る必要があります。
Viewは、instrument_nameで対象を選び、aggregationで集計を変えます。対象を選ばないと、すべての計測器に適用されます。
顧客IDを捨てるとポイントが減る
views_cardinality()が、ordersの属性キーをrouteだけ残すViewのリストを返すように直します。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6を見て、/root/otca-metrics/06-view-attributes.txtに、points_before=(ビューなしの最初の収集でのordersのポイント数)、points_after=、checkout_sum=(ビューを設定した最初の収集での/checkoutの値)を書いてください。
データポイントは、属性の組み合わせごとに1つです。残すキーだけを選ぶと、残りのキーが異なる測定は統合され、合計は保持されます。
非同期カウンターは累積値を報告する
register_async(meter, source)で、queue.processedはObservableCounterでsource.processed()を、queue.depthはObservableGaugeでsource.depth()を観測するようにします。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7(reader_all_deltaを使用)を見て、/root/otca-metrics/07-async.txtにprocessed_delta_second=、depth_second=を書いてください。sourceは、呼び出しごとにprocessedが10、25、depthが7、4を返します。
非同期カウンターのコールバックは、これまでの累積の絶対値を返します。デルタは、SDKが直前の観測との差として計算します。ゲージは足し合わせません。
3つのビューを1つのプロバイダーに
provider(reader)が、受け取ったリーダーと3つのビュー(ステップ5のバケット、ステップ6の属性の絞り込み、そしてdebug.cache.lookupsを捨てるDropAggregation)を持つMeterProviderを返すように直してください。採点では、reader_all_delta()で2回収集して、orders(routeを基準にしたデルタ)、checkout.duration(新しい境界)、cart.items、破棄されたdebugメトリクスをあわせて確認します。まず/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8で確認してください。
ビューは、MeterProviderを作るときに渡します。1つの計測器に複数のビューが一致すると、ストリームが複数できるため、ビューごとに対象を絞ってください。