OpenTelemetryのTracingについてまとめる JavaScriptにおけるAuto Instrumentation編
これは何
OpenTelemetryのTracingについて理解するため,JavaScriptで実装されたアプリケーションに対するauto instrumentationにおいて以下について調査した結果をまとめる記事です.
- Auto instrumentationの実行方法
- Auto instrumentationの実装
まとめ
nodeコマンドの--requireflagを用いてアプリケーションの実行前にInstrumentationを行っている- Instrumentationの実際の処理では最終的に
Object.definePropertyを用いてwrapされたメソッドと本来のメソッドを差し替えている- shimmerを用いている(他のメソッドをラップし,前後に処理を差し込めるライブラリ)
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
この--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
このPackageのREADME.mdを見ると,Auto Instrumentationのためのスクリプトなどを公開しているPackageであることがわかります.
依存するPackageの一覧を見てもJavaScript向けに提供されているAuto instrumentation用Packageがおおよそ含まれていること,また--requireflagで指定していたregister.tsの処理を追っていくとgetNodeAutoInstrumentations関数の定義元でこれらのPackageからClassをimportしているため,このPackageを起点に各Package毎のAuto Instrumentatin用の処理が呼び出されていそうです.
各Package毎のAuto Instrumentatin用の処理を追う
ここからはhttp moduleに対する計装の処理を追いながら具体的な計装の処理を追っていきます.
http moduleに対する計装の処理は以下のリポジトリで実装されています.
getNodeAutoInstrumentations関数でNodeSDKクラスに渡されているHttpInstrumentationクラスの実装について確認します.
ここでは InstrumentationBase クラスで定義された_wrapメソッドが呼ばれています.このメソッドの実装をみるとshimmermoduleのwrapメソッドが呼ばれています.
サンプルの通り,shimmermoduleのwrapメソッドはユーザーが第3引数で渡したラッパー関数を渡すことで本来の処理と差し替えるメソッドです.
実際の処理を見てみると,ラップされた処理(wraped変数の値)をObject.definePropertyを用いてwrap前のメソッドと差し替えていることがわかります.
まとめ
- Node.jsの自動計装では
Object.definePropertyを用いてwrapされたメソッドと本来のメソッドを差し替えている