OpenTelemetryのTracingについてまとめる NettyなどにおけるContext管理編
これは何
以前の記事において,OTelのJava向け実装ではTheadLocalValueを用いてスレッドごとのContext管理を行っていることがわかりました.
しかし,JavaのModuleでは1スレッドにおいて複数のリクエストを処理するものがあり(Nettyなど),これらの場合はスレッド単位でのContext分離が実現できないと考えられます.
今回は,これらのModuleの計装を調査しどのようにContextを管理しているのかを調査します.
本ブログの内容は GitHub - open-telemetry/opentelemetry-java-instrumentation at release/v2.13.x の内容に基づきます.
まとめ
わかったこと
ChannelInboundHandlerのchannelReadメソッド内でContextを作成し,ChannelのAttributeに紐づけている
わからなかったこと
- このContext管理では,ユーザーはOTelのAPI経由でリクエスト内で対応するSpanを参照できないのでは?
- ChannelのAttributeに紐づくため,OTel Contextからの参照でなくChannnelのAttribureからContextを参照しないと対応するContextが安全に取得できない
調査
Auto-Instrumentationの実装を見る
Netty 4.1向けの計装処理を見ていきます.
libraryディレクトリ以下はライブラリ特有の拡張機能を用いた計装処理の実装が記載されているため,こちらを見ていきます.
serverディレクトリ以下にサーバー向けの実装が配置されています.
リクエスト受信時の処理と考えられるopentelemetry-java-instrumentation/instrumentation/netty/netty-4.1/library/src/main/java/io/opentelemetry/instrumentation/netty/v4_1/internal/server/HttpServerRequestTracingHandler.java at release/v2.13.x · open-telemetry/opentelemetry-java-instrumentation · GitHub を見ていきましょう.
ここで,io.netty.channel.ChannelInboundHandlerAdapterインターフェースを継承した HttpServerRequestTracingHandlerが定義されています.
io.netty.channel.ChannelInboundHandlerAdapterはソケットからアプリケーションまでのデータの流れの中で実行する処理をまとめたクラスであり,channelReadメソッドはChannelがリクエストを受け取った際に実行される処理です.
HTTPリクエストを受信した際の処理に注目して追っていくと,
- ServerContextsクラスの
getOrCreateを呼び出し(36行目) - 新たなContextクラスのインスタンスを生成(57行目)
- ServerContextsクラスのインスタンスの
addListを実行(58行目) - Contextクラスの
makeCurrentを実行(60~70行目)
となっています.
このうち2行目のServerContextsクラスの実装を見てみると,引数に与えたChannelのattributeにServerContexts自身を追加していることがわかります.
ServerContextsクラスがDequeで管理しているServerContextはOTelのContextクラスのWrapperクラスと考えられます.
これらのことから,Netty用の計装の実装ではリクエスト受信時に実行されるハンドラーを使いChannelにOTelのContextを紐づけてContextの管理を行っていると考えられます.