ocaml-opentelemetry を使うと OCaml で OpenTelemetry によってトレース・メトリクス・ログを出力することができます。この記事ではこのうち、トレースとメトリクスを出力してみます。非同期処理のフレームワークとして Eio を使用します。なお ocaml-opentelemetry はバージョンによって API がかなり異なるため注意が必要です。ここでは執筆時点で最新の v0.91 を対象にします。おそらく v0.90 でも動作しますが v0.13[1] では動作しません。
#セットアップ
ocaml-opentelemetry を Eio と一緒に使用する場合、まず以下のようにセットアップします:
let setup_otel env f =
Opentelemetry.Globals.service_name := "your-system";
Ambient_context.set_current_storage Ambient_context_eio.storage;
Opentelemetry_client_cohttp_eio.with_setup env (fun () ->
Opentelemetry_trace.setup ();
Opentelemetry.Meter.(add_to_main_exporter default);
f ())
let () =
Eio_main.run (fun env ->
setup_otel env (main env)) (* main は別で定義されている想定 *)
|> exit
dune ファイルは次のようになります:
(executable
(name main)
(libraries
opentelemetry.trace
opentelemetry-client-cohttp-eio
ambient-context-eio))
Opentelemetry.Meter.add_to_main_exporter の呼び出しはメトリクスを使う場合に必要になります。トレースのみの使用なら不要です。逆にメトリクスを使う場合はこれを書いておかないと後述する Instrument などが動作しません[2]。
#メトリクス
ocaml-opentelemetry の README には Opentelemetry.Meter.emit1 を使用する例が書かれていますが、これを使うとメトリクスが一度しか出力されず持続しません(一敗)。ad hoc な確認ならこれでよいですが、本格的に使用するためには Instrument を介して使う必要があります。まず以下のようにメトリックを定義します:
let your_first_metric =
Opentelemetry.Instrument.Int_gauge.create
~name:"your_first_metric"
~description:"Your first metric description"
()
続いてコード中でこのメトリックを使います:
Opentelemetry.Instrument.Int_gauge.record your_first_metric 1;
どのような Instrument があるか、どのように使うかなどはリファレンスを参照してください。カスタムな定義もできるようです。
#トレース
続いてトレースの使用方法です。README には Opentelemetry.Tracer.with_ を使う方法が記載されていますが、面倒くさくて使う気になりません[3]。ocaml-trace で配布されている ppx_trace を使うとより簡単にトレースを採取できます。これは PPX なので dune ファイルの preprocess に追加した後で以下のように書きます:
let%trace f () = do_something ()
ただし本家の実装ではネストしたトレースがうまく扱われません。私のフォークを使うとネストも正しく扱えます。waq-external-repo に含まれているので良ければ使ってみてください[4]。
#動作確認
ocaml-opentelemetry に限った話ではないですが、OpenTelemetry を正しく取り扱えているか確認するには Docker で otel/opentelemetry-collector イメージを立ち上げて確認するのが簡単です。立ち上がっている先のエンドポイントは OTEL_EXPORTER_OTLP_ENDPOINT 環境変数で指定します。以下のような compose.yml を書き docker compose up で立ち上げます:
services:
web2:
image: your-system
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
otel-collector:
image: otel/opentelemetry-collector
volumes:
- otel-collector-config.yaml:/etc/otelcol/config.yaml
opentelemetry-collector の設定ファイルは以下のように書いておくとログで何を受け取ったかが表示されるので便利です:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
metrics:
receivers: [otlp]
exporters: [debug]
logs:
receivers: [otlp]
exporters: [debug]
なお OpenTelemetry の機能を無効にしたい場合は環境変数で OTEL_SDK_DISABLED=true と設定しておきます。