対数犬度関数

140字以上のことを書きます

(工事中)OpenTelemetryのTracingについてまとめる JavaScriptにおけるAuto Instrumentation編

これは何

OpenTelemetryのTracingについて理解するため,JavaScriptで実装されたアプリケーションに対するauto instrumentationにおいて以下について調査した結果をまとめる記事です.

  • Auto instrumentationの実行方法
  • Auto instrumentationの実装

まとめ

nodeコマンド実行 -> instrumentationまでの流れは以下のようになっています(ノードをクリックすることで実装リポジトリに遷移できます)

graph LR
    node["node --require @opentelemetry/auto-instrumentations-node/register app.js"]
    reg["register.ts(Auto instrumentationのエントリーポイント)"]
    contrib["https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node"]
    experimental["https://github.com/open-telemetry/opentelemetry-js/tree/v1.25.1/experimental/packages"]

    node --> reg
    reg --> contrib
    reg--> experimental

    click reg href "https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/metapackages/auto-instrumentations-node/src/register.ts"
    click contrib href "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node"
    click experimental href "https://github.com/open-telemetry/opentelemetry-js/tree/v1.25.1/experimental/packages"

Auto instrumentationの実行方法

OpenTelemetry公式のドキュメントを見てみると nodeコマンドの--require flagを用いています.

env OTEL_TRACES_EXPORTER=otlp OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=your-endpoint \
node --require @opentelemetry/auto-instrumentations-node/register app.js

opentelemetry.io

この--requireflagは アプリケーションの実行前に指定したmoduleを実行できる引数です.

実行順がわかりやすい例

このことからアプリケーションの実行前のinstrumentation処理を実装したmoduleを--requireflagで指定することによりアプリケーションのAuto instrumentationを行うことが可能と考えられます.

Auto instrumentationの実装

ここからは実際のAuto Instrumentationの実装について調査していきます.

@opentelemetry/auto-instrumentations-node Package

Auto Instrumentation実行時のコマンドを見ると,@opentelemetry/auto-instrumentations-nodePackage内のスクリプトを実行していることがわかります.

env OTEL_TRACES_EXPORTER=otlp OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=your-endpoint \
node --require @opentelemetry/auto-instrumentations-node/register app.js

opentelemetry.io

このPackageのREADME.mdを見ると,Auto Instrumentationのためのスクリプトなどを公開しているPackageであることがわかります.

依存するPackageの一覧を見てもJavaScript向けに提供されているAuto instrumentation用Packageがおおよそ含まれていること,また--requireflagで指定していたregister.tsの処理を追っていくとgetNodeAutoInstrumentations関数の定義元でこれらのPackageからClassをimportしているため,このPackageを起点に各Package毎のAuto Instrumentatin用の処理が呼び出されていそうです.

OpenTelemetryのTracingについてまとめる JavaにおけるAuto Instrumentation編

これは何

OpenTelemetryのTracingについて理解するため,GitHub - open-telemetry/opentelemetry-java-instrumentation at v2.6.0において以下について調査した結果をまとめる記事です.

  • Instrumentaionの種類について
  • JavaにおけるAuto Instrumentationの実装方法

まとめ

  • javaコマンドの-javaagentオプションでJava Agentを渡し,アプリケーションの実行前にInstrumentationを行っている
  • Java Agent内ではByte BuddyElementMatchersAdviceを用いてInstrumentationを行っている
    • ElementMatchersを用いてInstrumentationを行うClass, Methodを指定,実行前後に追加する処理を実装したClassと紐づけを行う
    • 紐づけられるClassでは@Advice.OnMethodEnter ,@Advice.OnMethodExitAnnotationが付与されたMethodsが実装されており,Spanの生成,Contextの新規生成を行う

Java Agentからの呼び出しは以下のようになっています.

Auto Instrumentationの構成図

Instrumentaionの種類について

JavaにおけるライブラリごとのInstrumentationには以下の2種類が公開されています.

Library instrumentation

対象のライブラリ固有の仕組みを用いたInstrumentationの実装です.

例としてservletの場合Filter機能と呼ばれるリクエストの前後で任意の処理を実行できる機能が提供されています.

web-dev.hatenablog.com

このFilter内でSpanの生成などを行うことでInstrumentationを実現しています.

この方式のInstrumentationを行う場合はユーザーはlibrary instrumentationで提供されるClassの初期化を行うため,アプリケーションのコードを変更する必要があります.

Java agent instrumentation

Java agent instrumentationではユーザーによるアプリケーションのコードの変更を行わず,自動的にinstrumentationを行えます.

README.md記載の通りアプリケーション実行時にJava Agentを指定するのみで自動的にinstrumentationが行われます.

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -jar myapp.jar

JavaにおけるAuto Instrumentationの実装方法

上記のリポジトリでは instrumentation 配下にライブラリごとのinstrumentationの実装が配置されています.

github.com

ここからはJava標準ライブラリの一つであるjava.net.httpModuleに対するinstrumentationを見ながら実装を追っていきます.

docs.oracle.com

java.net.httpModuleの使用方法

instrumentationの実装を追う前に対象のライブラリがどのように使われているかを知っておく必要があるため,サンプルコードを確認します.

docs.oracle.com

HttpClient client = HttpClient.newBuilder()
     .version(Version.HTTP_1_1)
     .followRedirects(Redirect.NORMAL)
     .connectTimeout(Duration.ofSeconds(20))
     .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
     .authenticator(Authenticator.getDefault())
     .build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());

サンプルコードよりHttpClientClassのsendMethodを実行することでHTTPリクエストを送信しています.このことからHttpClientClassのsendMethodの前後にSpanの生成処理を追加することでinstrumentationが行えると考えられます.(sendAsyncMethodについては一旦割愛します)

Java agent instrumentationの実装について

ここから実際のinstrumentationの実装を見ていきます.

Java Agent instrumentation実装時の作法については以下のドキュメントにて解説されているので,こちらに沿って確認していきます.

github.com

InstrumentationModule ClassとTypeInstrumentationInterfaceについて

Java Agent InstrumentationはTypeInstrumentationInterfaceとInstrumentationModule Class で構成されています.

TypeInstrumentationInterface

TypeInstrumentationInterfaceはライブラリ内の個々のClassに対するInstrumentation処理を実装しているClassが実装するInterfaceです.

github.com

typeMatcherMethodで対象とするClassを指定し,transformMethodでClassに対して行うInstrumentation処理を実装しています.

実際にjava.net.http.HttpClientClassへの処理を見てみると,bytebuddyElementMatcherを用いてClassを指定しsendMethodに対してSendAdviceClassとの紐づけを行っています.

github.com

この処理により SenAdviceClassのmethodEnterMethod, methodEnterMethodがそれぞれ sendMethodの実行前後に実行されます. これらのMethod内ではInstrumenter API(OpentelemetryのAPIのラッパー)を実行しており,Spanの開始~終了やContextの生成を行っています.

InstrumentationModule Class

InstrumentationModule Classは前述の TypeInstrumentationInterfaceを実装したClassをライブラリごとに集約しJava Agent実行時に読み込まれるようにするためのClassです.

github.com

@AutoServiceAnotationでServiceLoader API経由でJava Agentから読み込まれ,typeInstrumentationsMethodで TypeInstrumentationInterfaceを実装したClassのインスタンスを返すことでJava AgentにInstrumentationを実行させます.

実際にjava.net.http.HttpClientClassへの処理を見てみると,java.net.http.HttpClientClassへのInstrumentationを実装したClassのインスタンスtypeInstrumentationsMethodで返されていることがわかります.(HttpHeadersInstrumentationClassはTrace Context伝搬のためのInstrumentationを実装したClassです)

github.com

感想

  • 以下について掘り下げないと自力でInstrumentationを実装するのは厳しそう😭
    • Byte Buddy
      • AdviceやElement Matcherなど
    • Service(Javaにおける)

参考資料

instrumentationの作法について書かれたドキュメント

instrumentation実装時の作法について記載されているため,まずはここを読むのがよさそうです.

github.com

Java agent instrumentation実装時の作法について書かれたドキュメント

Java agentから利用されるClassを実装する際の手順について書かれています.

github.com

Instrumenter APIについて解説されたドキュメント

instrumentation実装時に利用される Instrumenter APIについて解説されているドキュメントです.

github.com