雑メモレベル。
OpenTelemetryの収集・エクスポートにOpenTelemetry Collectorを使うのがベストプラクティスと言われるが、複数パイプラインやtail-based sampling・transformなどの複雑なことをやらせていると、CPUやメモリの消費、あるいはシグナルのドロップのリスクが高まる。このCollector自体のオブザーバビリティも当然ほしい。
そのためのテレメトリーとしてInternal temeletryというのが用意されており、Collector自身のメトリック、ログ、トレースを出せるようになっている。
現時点ではservice:のtelemetry:下で設定する。スキーマ的にはまだdevelopmentで、将来変わる可能性は大いにあるらしい。
mackerelio-labs/apm-demoで試してみることにした(apm-demo自体については今後ちゃんと紹介したい)。
メトリック
メトリックはOTLPでどこか(たとえば自分自身)にexportするか、あるいはポート(デフォルト8888)を立ててPrometheusからスクレイプさせるかを選ぶ。Prometheusに集めたいわけでなければ、前者で自身にexportすればよいだろう。
ドキュメント例ではこうなっている。
service:
telemetry:
metrics:
readers:
- periodic:
exporter:
otlp:
protocol: http/protobuf
endpoint: https://backend:4318
apm-demoではコンテナとしてhttp 4319を待ち受けているようにしていて、docker composeではotel-collectorという名前にしているので、以下のようになる(すでに設定済み)。
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4319
service:
telemetry:
metrics:
readers:
- periodic:
inteval: 60000
exporter:
otlp:
protocol: http/protobuf
endpoint: http://otel-collector:4319
pipelines:
metrics:
receivers: [otlp, ...]
...
metrics/levelでnone(テレメトリー収集しない)、basic(essentialなサービスのみ)、normal(standardなインジケータ。デフォルト)、detailed(冗長。次元やビューも含む)を選択できる。
現時点で取得されるメトリック一覧は以下のとおり。
basicレベル
otelcol_exporter_enqueue_failed_log_records:exporterがエンキューに失敗したログ数otelcol_exporter_enqueue_failed_metric_points:exporterがエンキューに失敗したメトリックポイント数otelcol_exporter_enqueue_failed_spans:exporterがエンキューに失敗したスパン数otelcol_exporter_queue_capacity:バッチにおける送信キューキャパシティotelcol_exporter_queue_size:バッチにおける送信キューの現在のサイズotelcol_exporter_send_failed_log_records:exporterが送信先に送信失敗したログ数otelcol_exporter_send_failed_metric_points:exporterが送信先に送信失敗したメトリックポイント数otelcol_exporter_send_failed_spans:exporterが送信先に送信失敗したスパン数otelcol_exporter_sent_log_records:送信先に送信成功したログ数otelcol_exporter_sent_metric_points:送信先に送信成功したメトリックポイント数otelcol_exporter_sent_spans:送信先に送信成功したスパン数otelcol_process_cpu_seconds:秒間のCPU(user・system)合計時間otelcol_process_memory_rss:物理メモリバイトotelcol_process_runtime_heap_alloc_bytes:ヒープオブジェクト割り当てバイトotelcol_process_runtime_total_alloc_bytes:ヒープオブジェクト割り当ての累積バイトotelcol_process_runtime_total_sys_memory_bytes:OSから取得したメモリ合計バイトotelcol_process_uptime:プロセスの起動時間秒otelcol_processor_incoming_items:プロセッサに渡されたアイテム数otelcol_processor_outgoing_items:プロセッサから吐き出されたアイテム数otelcol_receiver_accepted_log_records:取り込まれパイプラインにpushされたログ数otelcol_receiver_accepted_metric_points:取り込まれパイプラインにpushされたメトリックポイント数otelcol_receiver_accepted_spans:取り込まれパイプラインにpushされたスパン数otelcol_receiver_refused_log_records:パイプラインにpushできなかったログ数otelcol_receiver_refused_metric_points:パイプラインにpushできなかったメトリックポイント数otelcol_receiver_refused_spans:パイプラインにpushできなかったスパン数otelcol_scraper_errored_metric_points:Collectorがスクレイプに失敗したメトリックポイント数otelcol_scraper_scraped_metric_points:Collectorがスクレイプしたメトリックポイント数
さらにnormalレベル
otelcol_processor_batch_batch_send_size:バッチで送られた単位数otelcol_processor_batch_batch_size_trigger_send:サイズトリガーによってバッチが送られた回数otelcol_processor_batch_metadata_cardinality:処理された各メタデータ値セットの数otelcol_processor_batch_timeout_trigger_send:タイムアウトトリガーによってバッチが送られた回数
さらにdetailedレベル
http_client_active_requests:HTTPクライアントのリクエスト数http_client_connection_duration:正常にアウトバウンドHTTP接続を確立するまでの期間http_client_open_connections:クライアントでアクティブまたはアイドルになっているアウトバウンドHTTP接続数http_client_request_size:HTTPクライアントリクエストボディのサイズhttp_client_duration:HTTPクライアントリクエストの期間http_client_response_size:HTTPクライアントレスポンスボディのサイズhttp_server_active_requests:アクティブなHTTPサーバーリクエスト数http_server_request_size:HTTPサーバーリクエストボディのサイズhttp_server_duration:HTTPサーバーリクエストの期間http_server_response_size:HTTPサーバーレスポンスボディのサイズotelcol_processor_batch_batch_send_size_bytes:バッチで送信したバイト数rpc_client_duration:アウトバウンドRPCの間隔rpc_client_request_size:RPCリクエストメッセージのサイズ(非圧縮)rpc_client_requests_per_rpc:RPCあたり受け取ったメッセージ数。非ストリーミングRPCでは常に1rpc_client_response_size:RPCレスポンスメッセージのサイズ(非圧縮)rpc_client_responses_per_rpc:RPCあたり送信したメッセージ数。非ストリーミングRPCでは常に1rpc_server_duration:インバウンドRPCの間隔rpc_server_request_size:RPCリクエストメッセージのサイズ(非圧縮)rpc_server_requests_per_rpc:RPCあたり受け取ったメッセージ数。非ストリーミングRPCでは常に1rpc_server_response_size:RPCレスポンスメッセージのサイズ(非圧縮)rpc_server_responses_per_rpc:RPCあたり送信したメッセージ数。非ストリーミングRPCでは常に1
メトリックをあまり増やすと、たとえばMackerelでは課金に影響してくる(ヒストグラムを送るとさらに増える)ので、normalかbasicあたりにしておくのがよさそうではある。
Mackerelではメトリック粒度が1分なので、無駄打ちにならないようにperiodicのintervalを60000(ミリ秒=1分)にしている(ここはintになっていて60sなどの表記は使えないっぽい)。これも課金に関わることなので、もっと間隔を広げてしまってもよいかもしれない。
otelcol-contribで出したところでは、サービス名はotelcol-contribになった。exporterの設定で変えることもできそうかな。
gaugeありsumありhistogramありで、全体を眺めようとするには見辛い。

スパンを送り漏らしていないかを見るには、otelcol_exporter_enqueue_failed_spans(これはapm-demoでは出ないが)、otelcol_exporter_send_failed_spans、otelcol_receiver_refused_spansあたり。いずれもCounter(Mackerel表示上はsum)なので、クエリ監視としてはたとえばirate(otelcol_exporter_send_failed_spans{service.name="otelcol-contrib"}[5m])、凡例exporter、閾値Warning > 0、Critical > 10、監視ルール名「otel-collectorのexporter {{exporter}} で送信失敗」などとすることになるのではないか。
ドキュメントにはotelcol_exporter_queue_capacityとotelcol_export_queue_sizeでバッチのキューが耐えられるかを確認することも提案されている。

ログ
ログは普通に起動するときにも出ているので、それほど変わりばえのする感じではない。OTel形式で属性などが付いているくらいか。ドキュメントではこうなっている。
service:
telemetry:
logs:
processors:
- batch:
exporter:
otlp:
protocol: http/protobuf
endpoint: https://backend:4318
Mackerelはログに対応していないので、otel-tuiに出してみる(otlphttp定義せずに直接エンドポイント指定してしまってもよかった気はするが)。
exporters:
otlphttp/oteltui:
endpoint: http://ローカルマシンIP:4318
service:
telemetry:
metrics:
...
logs:
processors:
- batch:
exporter:
otlp:
protocol: http/protobuf
endpoint: http://otel-collector:4319
pipelines:
logs:
receivers: [otlp]
exporters: [otlphttp/oteltui]

パラメータがいくつかある。デフォルトのlevelの値がINFOでかなり多いので、WARNやERRORにするといいのかな。
処理落ちを見るにはDropping data because sending_queue is full.といったログを気にするとよいようだ。
トレース
トレースは実験的な扱いとされている。
ドキュメントでの例。
service:
telemetry:
traces:
processors:
- batch:
exporter:
otlp:
protocol: http/protobuf
endpoint: https://backend:4318
apm-demo向けにはendpoint: http://otel-collector:4319として実験してみる。

入っているのはOTLP受け取り、scraperでの取得、exporterへの投稿といったもので、スパンとしてすごく有用というほどではなさそうに見える。そのわりに量が多くなって費用につながるので、デバッグ専用という印象。
感想
現時点ではメトリックについては常用で出しておいてもよさそうに思えた。コスト要因にはなるので、取得頻度を下げたり、結果をフィルタリングして必要なものだけを出したりといった対策は必要そう。