@@ -19,7 +19,10 @@ package org.typelevel.otel4s.oteljava.context
19
19
import cats .effect .IOLocal
20
20
import cats .effect .LiftIO
21
21
import cats .effect .MonadCancelThrow
22
+ import cats .effect .std .Console
22
23
import cats .mtl .Local
24
+ import cats .syntax .flatMap ._
25
+ import cats .syntax .functor ._
23
26
import io .opentelemetry .context .{Context => JContext }
24
27
import io .opentelemetry .context .ContextStorage
25
28
import io .opentelemetry .context .Scope
@@ -30,7 +33,7 @@ import org.typelevel.otel4s.context.LocalProvider
30
33
* that reflect the state of the backing `IOLocal`. Usage of `Local` and `ContextStorage` methods will be consistent
31
34
* and stay in sync as long as effects are threaded properly.
32
35
*/
33
- class IOLocalContextStorage (
36
+ private class IOLocalContextStorage (
34
37
_ioLocal : () => IOLocal [Context ],
35
38
_unsafeThreadLocal : () => ThreadLocal [Context ]
36
39
) extends ContextStorage {
@@ -58,9 +61,6 @@ class IOLocalContextStorage(
58
61
59
62
object IOLocalContextStorage {
60
63
61
- private val AgentContextStorageClass =
62
- " io.opentelemetry.javaagent.instrumentation.opentelemetryapi.context.AgentContextStorage"
63
-
64
64
/** Returns a [[cats.mtl.Local `Local` ]] of a [[org.typelevel.otel4s.oteljava.context.Context `Context` ]] if an
65
65
* [[`IOLocalContextStorage` ]] is configured to be used as the `ContextStorage` for the Java otel library.
66
66
*
@@ -75,34 +75,34 @@ object IOLocalContextStorage {
75
75
* }
76
76
* }}}
77
77
*/
78
- def localProvider [F [_]: LiftIO ](implicit F : MonadCancelThrow [F ]): LocalProvider [F , Context ] =
78
+ def localProvider [F [_]: Console : LiftIO ](implicit F : MonadCancelThrow [F ]): LocalProvider [F , Context ] =
79
79
new LocalProvider [F , Context ] {
80
80
def local : F [Local [F , Context ]] =
81
81
ContextStorage .get() match {
82
82
case storage : IOLocalContextStorage =>
83
83
whenPropagationEnabled(storage.local)
84
84
85
- case other if other.getClass.getName == AgentContextStorageClass =>
86
- whenPropagationEnabled(agentLocal)
87
-
88
85
case other =>
89
- F .raiseError(
90
- new IllegalStateException (
91
- " IOLocalContextStorage is not configured for use as the ContextStorageProvider. " +
92
- s " The current storage: ${other.getClass.getName}. "
93
- )
94
- )
86
+ getAgentLocalContext() match {
87
+ case Some (ioLocalJContext) =>
88
+ val ioLocal = ioLocalJContext.lens(ctx => Context .wrap(ctx))(_ => c => c.underlying)
89
+ val local = LocalProvider .localForIOLocal(ioLocal)
90
+
91
+ for {
92
+ _ <- Console [F ].println(" IOLocalContextStorage: agent-provided IOLocal is detected" )
93
+ r <- whenPropagationEnabled(local)
94
+ } yield r
95
+
96
+ case None =>
97
+ F .raiseError(
98
+ new IllegalStateException (
99
+ " IOLocalContextStorage is not configured for use as the ContextStorageProvider. " +
100
+ s " The current ContextStorage is: ${other.getClass.getName}"
101
+ )
102
+ )
103
+ }
95
104
}
96
105
97
- private def agentLocal : Local [F , Context ] = {
98
- val ioLocal = IOLocalContextStorageProvider .localContext
99
- val threadLocal = IOLocalContextStorageProvider .threadLocalJContext
100
-
101
- registerFiberThreadLocalContext(threadLocal)
102
-
103
- LocalProvider .localForIOLocal(ioLocal)
104
- }
105
-
106
106
private def whenPropagationEnabled [A ](whenEnabled : => A ): F [A ] =
107
107
if (IOLocal .isPropagating) {
108
108
F .pure(whenEnabled)
@@ -115,8 +115,8 @@ object IOLocalContextStorage {
115
115
}
116
116
}
117
117
118
- /** The method is instrumented by the OTeL Java agent to capture the provided thread local. It must be public .
118
+ /** The method is instrumented by the OTeL Java agent to provide the IOLocal managed by agent .
119
119
*/
120
- def registerFiberThreadLocalContext ( threadLocal : ThreadLocal [ JContext ]) : Unit = ()
120
+ private [context] def getAgentLocalContext () : Option [ IOLocal [ JContext ]] = None
121
121
122
122
}
0 commit comments