From ac4175c2d9830dbb08a23a25497062c41d266295 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Fri, 12 May 2023 12:09:34 -0400 Subject: [PATCH 01/25] Experimental IOLocalContextStorage --- .../otel4s/java/IOLocalContextStorage.scala | 36 ++++++++++++++++ .../otel4s/java/ContextStorageSuite.scala | 43 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala create mode 100644 java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala new file mode 100644 index 000000000..b4cf1f6b2 --- /dev/null +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -0,0 +1,36 @@ +package org.typelevel.otel4s.java + +import cats.effect.IOLocal +import cats.effect.LiftIO +import cats.effect.std.Dispatcher +import io.opentelemetry.context.Context +import io.opentelemetry.context.ContextStorage +import io.opentelemetry.context.Scope + +class IOLocalContextStorage[F[_]: LiftIO]( + dispatcher: Dispatcher[F], + ioLocal: IOLocal[Context] +) extends ContextStorage { + + override def attach(toAttach: Context): Scope = + dispatcher.unsafeRunSync( + currentOrRoot + .flatMap { old => + ioLocal + .set(toAttach) + .as(new Scope { + def close() = dispatcher.unsafeRunSync(ioLocal.set(old).to[F]) + }) + } + .to[F] + ) + + override def current(): Context = { + dispatcher.unsafeRunSync(currentOrRoot.to[F]) + } + + private def currentOrRoot = ioLocal.get.map { + case null => Context.root() + case ctx => ctx + } +} diff --git a/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala b/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala new file mode 100644 index 000000000..7c71b26e1 --- /dev/null +++ b/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala @@ -0,0 +1,43 @@ +package org.typelevel.otel4s.java + +import cats.effect.IO +import cats.effect.IOLocal +import cats.effect.Resource +import cats.effect.std.Dispatcher +import io.opentelemetry.context.Context +import io.opentelemetry.context.ContextKey +import io.opentelemetry.context.ContextStorage +import java.util.logging._ + +object Run extends cats.effect.IOApp.Simple { + + val key = ContextKey.named[String]("test") + + def run = + Dispatcher.parallel[IO].use { dispatcher => + for { + _ <- IO { + val rootLog = Logger.getLogger("") + rootLog.setLevel(Level.FINE) + rootLog.getHandlers().head.setLevel(Level.FINE) + } + ioLocal <- IOLocal(null: Context) + storage = new IOLocalContextStorage(dispatcher, ioLocal) + _ <- IO(ContextStorage.addWrapper(_ => storage)) + _ <- ioLocal.set(null) + _ <- IO.println(ContextStorage.get().getClass) + ctx = Context.root() + _ <- Resource + .make(IO(ctx.`with`(key, "hello").makeCurrent()))(scope => + IO(scope.close()) + ) + .surround { + for { + key <- IO(Context.current()) + _ <- IO.println(key) + } yield () + } + _ <- IO(Option(Context.current().get(key))).flatMap(v => IO.println(v)) + } yield () + } +} From 682abb65818c5a353fa1041429737e64d4458cee Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Wed, 17 May 2023 23:04:39 -0400 Subject: [PATCH 02/25] Try typelevel/cats-effect#3636 --- build.sbt | 5 ++- .../main/scala/ContextStorageExample.scala | 38 ++++++++++++++++ .../otel4s/java/IOLocalContextStorage.scala | 34 +++++---------- .../otel4s/java/ContextStorageSuite.scala | 43 ------------------- 4 files changed, 52 insertions(+), 68 deletions(-) create mode 100644 examples/src/main/scala/ContextStorageExample.scala delete mode 100644 java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala diff --git a/build.sbt b/build.sbt index f9c78feb2..f185752e1 100644 --- a/build.sbt +++ b/build.sbt @@ -26,7 +26,7 @@ ThisBuild / crossScalaVersions := Seq(Scala213, "3.2.2") ThisBuild / scalaVersion := Scala213 // the default Scala val CatsVersion = "2.9.0" -val CatsEffectVersion = "3.5.0" +val CatsEffectVersion = "3.5.0-30-0a69caf" val CatsMtlVersion = "1.3.1" val FS2Version = "3.6.1" val MUnitVersion = "1.0.0-M7" @@ -154,7 +154,7 @@ lazy val `java-common` = project .settings( name := "otel4s-java-common", libraryDependencies ++= Seq( - "org.typelevel" %%% "cats-effect-kernel" % CatsEffectVersion, + "org.typelevel" %%% "cats-effect" % CatsEffectVersion, "org.typelevel" %%% "cats-mtl" % CatsMtlVersion, "io.opentelemetry" % "opentelemetry-sdk" % OpenTelemetryVersion, "org.scalameta" %%% "munit" % MUnitVersion % Test @@ -241,6 +241,7 @@ lazy val examples = project ), run / fork := true, javaOptions += "-Dotel.java.global-autoconfigure.enabled=true", + javaOptions += "-Dcats.effect.tracing.dumpLocals", envVars ++= Map( "OTEL_PROPAGATORS" -> "b3multi", "OTEL_SERVICE_NAME" -> "Trace Example" diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala new file mode 100644 index 000000000..5f786edfc --- /dev/null +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -0,0 +1,38 @@ +import cats.effect.IO +import cats.effect.IOApp +import cats.effect.IOLocal +import cats.effect.Resource +import cats.effect.unsafe.IOLocals +import io.opentelemetry.context.Context +import io.opentelemetry.context.ContextKey +import io.opentelemetry.context.ContextStorage +import org.typelevel.otel4s.java.IOLocalContextStorage +import java.util.logging._ + +object ContextStorageExample extends IOApp.Simple { + + val key = ContextKey.named[String]("test") + + val printKey = + IO(Option(Context.current().get(key))).flatMap(v => IO.println(v)) + + def run = + for { + _ <- IO { + val rootLog = Logger.getLogger("") + rootLog.setLevel(Level.FINE) + rootLog.getHandlers().head.setLevel(Level.FINE) + } + ioLocal <- IOLocal(null: Context) + storage = new IOLocalContextStorage(ioLocal) + _ <- IO(ContextStorage.addWrapper(_ => storage)) + ctx = Context.root() + _ = IOLocals.set(ioLocal, Context.root()) + _ <- Resource + .make(IO(ctx.`with`(key, "hello").makeCurrent()))(scope => + IO(scope.close()) + ) + .surround(printKey) + _ <- printKey + } yield () +} diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index b4cf1f6b2..77adcf39a 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -1,36 +1,24 @@ package org.typelevel.otel4s.java import cats.effect.IOLocal -import cats.effect.LiftIO -import cats.effect.std.Dispatcher +import cats.effect.unsafe.IOLocals import io.opentelemetry.context.Context import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.Scope -class IOLocalContextStorage[F[_]: LiftIO]( - dispatcher: Dispatcher[F], +class IOLocalContextStorage( ioLocal: IOLocal[Context] ) extends ContextStorage { - override def attach(toAttach: Context): Scope = - dispatcher.unsafeRunSync( - currentOrRoot - .flatMap { old => - ioLocal - .set(toAttach) - .as(new Scope { - def close() = dispatcher.unsafeRunSync(ioLocal.set(old).to[F]) - }) - } - .to[F] - ) - - override def current(): Context = { - dispatcher.unsafeRunSync(currentOrRoot.to[F]) + override def attach(toAttach: Context): Scope = { + val previous = current() + IOLocals.set(ioLocal, toAttach) + new Scope { + def close() = IOLocals.set(ioLocal, previous) + } } - private def currentOrRoot = ioLocal.get.map { - case null => Context.root() - case ctx => ctx - } + override def current(): Context = + IOLocals.get(ioLocal) + } diff --git a/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala b/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala deleted file mode 100644 index 7c71b26e1..000000000 --- a/java/common/src/test/scala/org/typelevel/otel4s/java/ContextStorageSuite.scala +++ /dev/null @@ -1,43 +0,0 @@ -package org.typelevel.otel4s.java - -import cats.effect.IO -import cats.effect.IOLocal -import cats.effect.Resource -import cats.effect.std.Dispatcher -import io.opentelemetry.context.Context -import io.opentelemetry.context.ContextKey -import io.opentelemetry.context.ContextStorage -import java.util.logging._ - -object Run extends cats.effect.IOApp.Simple { - - val key = ContextKey.named[String]("test") - - def run = - Dispatcher.parallel[IO].use { dispatcher => - for { - _ <- IO { - val rootLog = Logger.getLogger("") - rootLog.setLevel(Level.FINE) - rootLog.getHandlers().head.setLevel(Level.FINE) - } - ioLocal <- IOLocal(null: Context) - storage = new IOLocalContextStorage(dispatcher, ioLocal) - _ <- IO(ContextStorage.addWrapper(_ => storage)) - _ <- ioLocal.set(null) - _ <- IO.println(ContextStorage.get().getClass) - ctx = Context.root() - _ <- Resource - .make(IO(ctx.`with`(key, "hello").makeCurrent()))(scope => - IO(scope.close()) - ) - .surround { - for { - key <- IO(Context.current()) - _ <- IO.println(key) - } yield () - } - _ <- IO(Option(Context.current().get(key))).flatMap(v => IO.println(v)) - } yield () - } -} From 5f460eec0f5c88f5ba552ef5a4b6ab19d25b8b24 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Thu, 18 May 2023 17:45:21 -0400 Subject: [PATCH 03/25] Apply suggestions from code review Co-authored-by: Arman Bilge --- build.sbt | 2 +- examples/src/main/scala/ContextStorageExample.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index f185752e1..b6ce8cbb6 100644 --- a/build.sbt +++ b/build.sbt @@ -241,7 +241,7 @@ lazy val examples = project ), run / fork := true, javaOptions += "-Dotel.java.global-autoconfigure.enabled=true", - javaOptions += "-Dcats.effect.tracing.dumpLocals", + javaOptions += "-Dcats.effect.tracing.dumpLocals=true", envVars ++= Map( "OTEL_PROPAGATORS" -> "b3multi", "OTEL_SERVICE_NAME" -> "Trace Example" diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index 5f786edfc..8967b49c8 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -27,7 +27,7 @@ object ContextStorageExample extends IOApp.Simple { storage = new IOLocalContextStorage(ioLocal) _ <- IO(ContextStorage.addWrapper(_ => storage)) ctx = Context.root() - _ = IOLocals.set(ioLocal, Context.root()) + _ <- ioLocal.set(Context.root()) _ <- Resource .make(IO(ctx.`with`(key, "hello").makeCurrent()))(scope => IO(scope.close()) From e522ac8117230cc909c7b24d51c984f29557d811 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Thu, 18 May 2023 17:46:48 -0400 Subject: [PATCH 04/25] Get latest cats-effect branch --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index b6ce8cbb6..f3222e416 100644 --- a/build.sbt +++ b/build.sbt @@ -26,7 +26,7 @@ ThisBuild / crossScalaVersions := Seq(Scala213, "3.2.2") ThisBuild / scalaVersion := Scala213 // the default Scala val CatsVersion = "2.9.0" -val CatsEffectVersion = "3.5.0-30-0a69caf" +val CatsEffectVersion = "3.5.0-31-2775064" val CatsMtlVersion = "1.3.1" val FS2Version = "3.6.1" val MUnitVersion = "1.0.0-M7" From d9a1079206b82ba6f8c4ae8a8072cbfb2776d49c Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Thu, 18 May 2023 17:49:17 -0400 Subject: [PATCH 05/25] Fine, have your headers --- .../src/main/scala/ContextStorageExample.scala | 16 ++++++++++++++++ .../otel4s/java/IOLocalContextStorage.scala | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index 8967b49c8..f141ed0f0 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import cats.effect.IO import cats.effect.IOApp import cats.effect.IOLocal diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index 77adcf39a..a2c46f9cf 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.typelevel.otel4s.java import cats.effect.IOLocal From c4410ab7a53c98c7fb53e42f9c346eab2f44398b Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Thu, 18 May 2023 23:33:51 -0400 Subject: [PATCH 06/25] Unused import --- examples/src/main/scala/ContextStorageExample.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index f141ed0f0..3e6ab0ff9 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -18,7 +18,6 @@ import cats.effect.IO import cats.effect.IOApp import cats.effect.IOLocal import cats.effect.Resource -import cats.effect.unsafe.IOLocals import io.opentelemetry.context.Context import io.opentelemetry.context.ContextKey import io.opentelemetry.context.ContextStorage From 6b542aaeecae0e7fb49af7fbe303c933d96c774d Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Fri, 19 May 2023 00:09:01 -0400 Subject: [PATCH 07/25] Get testkit out of main dependenecies --- build.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index f3222e416..2f79c0f78 100644 --- a/build.sbt +++ b/build.sbt @@ -150,7 +150,7 @@ lazy val testkit = crossProject(JVMPlatform) lazy val `java-common` = project .in(file("java/common")) .enablePlugins(BuildInfoPlugin) - .dependsOn(`core-common`.jvm, `testkit-common`.jvm) + .dependsOn(`core-common`.jvm, `testkit-common`.jvm % Test) .settings( name := "otel4s-java-common", libraryDependencies ++= Seq( @@ -168,7 +168,7 @@ lazy val `java-common` = project lazy val `java-metrics` = project .in(file("java/metrics")) - .dependsOn(`java-common`, `core-metrics`.jvm, `testkit-metrics`.jvm) + .dependsOn(`java-common`, `core-metrics`.jvm, `testkit-metrics`.jvm % Test) .settings(munitDependencies) .settings( name := "otel4s-java-metrics", @@ -222,7 +222,7 @@ lazy val benchmarks = project .enablePlugins(NoPublishPlugin) .enablePlugins(JmhPlugin) .in(file("benchmarks")) - .dependsOn(core.jvm, java) + .dependsOn(core.jvm, java, `testkit-metrics`.jvm) .settings( name := "otel4s-benchmarks" ) From b6a75a010de68e1218d2b03fa513e9e7349eb2f3 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Fri, 19 May 2023 00:09:22 -0400 Subject: [PATCH 08/25] Attmept at a ContextStorageProvider SPI --- .../main/scala/ContextStorageExample.scala | 13 +++---- ...entelemetry.context.ContextStorageProvider | 1 + .../otel4s/java/IOLocalContextStorage.scala | 9 ++--- .../java/IOLocalContextStorageProvider.scala | 36 +++++++++++++++++++ 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider create mode 100644 java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index 3e6ab0ff9..5c905dca4 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -16,12 +16,12 @@ import cats.effect.IO import cats.effect.IOApp -import cats.effect.IOLocal import cats.effect.Resource import io.opentelemetry.context.Context import io.opentelemetry.context.ContextKey import io.opentelemetry.context.ContextStorage -import org.typelevel.otel4s.java.IOLocalContextStorage +import org.typelevel.otel4s.java.IOLocalContextStorageProvider + import java.util.logging._ object ContextStorageExample extends IOApp.Simple { @@ -38,13 +38,10 @@ object ContextStorageExample extends IOApp.Simple { rootLog.setLevel(Level.FINE) rootLog.getHandlers().head.setLevel(Level.FINE) } - ioLocal <- IOLocal(null: Context) - storage = new IOLocalContextStorage(ioLocal) - _ <- IO(ContextStorage.addWrapper(_ => storage)) - ctx = Context.root() - _ <- ioLocal.set(Context.root()) + _ <- IOLocalContextStorageProvider.localContext.set(Context.root()) + _ <- IO.println(ContextStorage.get.getClass()) _ <- Resource - .make(IO(ctx.`with`(key, "hello").makeCurrent()))(scope => + .make(IO(Context.root().`with`(key, "hello").makeCurrent()))(scope => IO(scope.close()) ) .surround(printKey) diff --git a/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider new file mode 100644 index 000000000..aeea4e705 --- /dev/null +++ b/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider @@ -0,0 +1 @@ +org.typelevel.otel4s.java.IOLocalContextStorageProvider \ No newline at end of file diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index a2c46f9cf..0096ae32a 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -16,6 +16,7 @@ package org.typelevel.otel4s.java +import cats.Eval import cats.effect.IOLocal import cats.effect.unsafe.IOLocals import io.opentelemetry.context.Context @@ -23,18 +24,18 @@ import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.Scope class IOLocalContextStorage( - ioLocal: IOLocal[Context] + ioLocal: Eval[IOLocal[Context]] ) extends ContextStorage { override def attach(toAttach: Context): Scope = { val previous = current() - IOLocals.set(ioLocal, toAttach) + IOLocals.set(ioLocal.value, toAttach) new Scope { - def close() = IOLocals.set(ioLocal, previous) + def close() = IOLocals.set(ioLocal.value, previous) } } override def current(): Context = - IOLocals.get(ioLocal) + IOLocals.get(ioLocal.value) } diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala new file mode 100644 index 000000000..6d1ecf678 --- /dev/null +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala @@ -0,0 +1,36 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.typelevel.otel4s.java + +import cats.Eval +import cats.effect.IOLocal +import cats.effect.unsafe.implicits.global +import io.opentelemetry.context.Context +import io.opentelemetry.context.ContextStorage +import io.opentelemetry.context.ContextStorageProvider + +object IOLocalContextStorageProvider { + val localContext: IOLocal[Context] = + IOLocal[Context](Context.root()).unsafeRunSync() +} + +class IOLocalContextStorageProvider extends ContextStorageProvider { + def get(): ContextStorage = + new IOLocalContextStorage( + Eval.later(IOLocalContextStorageProvider.localContext) + ) +} From 978ccefc2a6a10a681a22cb57f35694bc5eaba6c Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Fri, 19 May 2023 09:20:37 -0400 Subject: [PATCH 09/25] Use syncStep to initialize the local context --- .../java/IOLocalContextStorageProvider.scala | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala index 6d1ecf678..062b2e116 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala @@ -18,14 +18,24 @@ package org.typelevel.otel4s.java import cats.Eval import cats.effect.IOLocal -import cats.effect.unsafe.implicits.global +import cats.effect.SyncIO +import cats.syntax.all._ import io.opentelemetry.context.Context import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.ContextStorageProvider object IOLocalContextStorageProvider { val localContext: IOLocal[Context] = - IOLocal[Context](Context.root()).unsafeRunSync() + IOLocal[Context](Context.root()) + .syncStep(100) + .flatMap( + _.leftMap(_ => + new Error( + "Failed to initialize the local context of the IOLocalContextStorageProvider." + ) + ).liftTo[SyncIO] + ) + .unsafeRunSync() } class IOLocalContextStorageProvider extends ContextStorageProvider { From 99137043b59ea1febca24f2058b0344481b9fde1 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Mon, 22 May 2023 12:02:25 -0400 Subject: [PATCH 10/25] Update Cats Effect snapshot --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 2f79c0f78..560756117 100644 --- a/build.sbt +++ b/build.sbt @@ -26,7 +26,7 @@ ThisBuild / crossScalaVersions := Seq(Scala213, "3.2.2") ThisBuild / scalaVersion := Scala213 // the default Scala val CatsVersion = "2.9.0" -val CatsEffectVersion = "3.5.0-31-2775064" +val CatsEffectVersion = "3.5.0-34-2cf72a5" val CatsMtlVersion = "1.3.1" val FS2Version = "3.6.1" val MUnitVersion = "1.0.0-M7" From b6c2b0ff31727e530b3f4675376964f12b7e04a3 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Mon, 22 May 2023 12:03:20 -0400 Subject: [PATCH 11/25] Remove direct reference to IOLocalContextStorageProvider --- examples/src/main/scala/ContextStorageExample.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index 5c905dca4..de155209f 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -20,7 +20,6 @@ import cats.effect.Resource import io.opentelemetry.context.Context import io.opentelemetry.context.ContextKey import io.opentelemetry.context.ContextStorage -import org.typelevel.otel4s.java.IOLocalContextStorageProvider import java.util.logging._ @@ -38,7 +37,6 @@ object ContextStorageExample extends IOApp.Simple { rootLog.setLevel(Level.FINE) rootLog.getHandlers().head.setLevel(Level.FINE) } - _ <- IOLocalContextStorageProvider.localContext.set(Context.root()) _ <- IO.println(ContextStorage.get.getClass()) _ <- Resource .make(IO(Context.root().`with`(key, "hello").makeCurrent()))(scope => From 8c311369895f7e674444418b76ab23ada46d0cb0 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Mon, 22 May 2023 23:29:22 -0400 Subject: [PATCH 12/25] Unbox IOLocal Co-authored-by: Arman Bilge --- .../org/typelevel/otel4s/java/IOLocalContextStorage.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index 0096ae32a..ea346bf7d 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -24,9 +24,9 @@ import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.Scope class IOLocalContextStorage( - ioLocal: Eval[IOLocal[Context]] + _ioLocal: => IOLocal[Context] ) extends ContextStorage { - + private[this] lazy val ioLocal = _ioLocal override def attach(toAttach: Context): Scope = { val previous = current() IOLocals.set(ioLocal.value, toAttach) From fe7259e6dc3f2af3019912b8d786ba484b052692 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 28 Jun 2023 22:28:32 +0000 Subject: [PATCH 13/25] Fix compile, update to CE snapshot --- build.sbt | 4 ++-- .../org/typelevel/otel4s/java/IOLocalContextStorage.scala | 7 +++---- .../otel4s/java/IOLocalContextStorageProvider.scala | 5 +---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index c4954329c..07ef6dec3 100644 --- a/build.sbt +++ b/build.sbt @@ -26,7 +26,7 @@ ThisBuild / crossScalaVersions := Seq(Scala213, "3.3.0") ThisBuild / scalaVersion := Scala213 // the default Scala val CatsVersion = "2.9.0" -val CatsEffectVersion = "3.5.0-34-2cf72a5" +val CatsEffectVersion = "3.6-02a43a6" val CatsMtlVersion = "1.3.1" val DisciplineMUnitVersion = "2.0.0-M3" val FS2Version = "3.7.0" @@ -265,7 +265,7 @@ lazy val examples = project ), run / fork := true, javaOptions += "-Dotel.java.global-autoconfigure.enabled=true", - javaOptions += "-Dcats.effect.tracing.dumpLocals=true", + javaOptions += "-Dcats.effect.ioLocalPropagation=true", envVars ++= Map( "OTEL_PROPAGATORS" -> "b3multi", "OTEL_SERVICE_NAME" -> "Trace Example" diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index ea346bf7d..e18a80b38 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -16,7 +16,6 @@ package org.typelevel.otel4s.java -import cats.Eval import cats.effect.IOLocal import cats.effect.unsafe.IOLocals import io.opentelemetry.context.Context @@ -29,13 +28,13 @@ class IOLocalContextStorage( private[this] lazy val ioLocal = _ioLocal override def attach(toAttach: Context): Scope = { val previous = current() - IOLocals.set(ioLocal.value, toAttach) + IOLocals.set(ioLocal, toAttach) new Scope { - def close() = IOLocals.set(ioLocal.value, previous) + def close() = IOLocals.set(ioLocal, previous) } } override def current(): Context = - IOLocals.get(ioLocal.value) + IOLocals.get(ioLocal) } diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala index 062b2e116..d328674d2 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala @@ -16,7 +16,6 @@ package org.typelevel.otel4s.java -import cats.Eval import cats.effect.IOLocal import cats.effect.SyncIO import cats.syntax.all._ @@ -40,7 +39,5 @@ object IOLocalContextStorageProvider { class IOLocalContextStorageProvider extends ContextStorageProvider { def get(): ContextStorage = - new IOLocalContextStorage( - Eval.later(IOLocalContextStorageProvider.localContext) - ) + new IOLocalContextStorage(IOLocalContextStorageProvider.localContext) } From e60f79316b3afa46378b83cc15e4d933439f494f Mon Sep 17 00:00:00 2001 From: Marissa Date: Thu, 31 Aug 2023 06:17:51 -0400 Subject: [PATCH 14/25] Finish implementing `IOLocalContextStorage` Finish implementing `IOLocalContextStorage` and `IOLocalContextStorageProvider` for sharing context modifications between Java and Scala instrumentation. --- .github/workflows/ci.yml | 4 +- build.sbt | 21 +- ...entelemetry.context.ContextStorageProvider | 1 - .../otel4s/java/IOLocalContextStorage.scala | 40 --- .../otel4s/java/context/Context.scala | 2 +- ...entelemetry.context.ContextStorageProvider | 1 + .../otel4s/java/IOLocalContextStorage.scala | 92 ++++++ .../java/IOLocalContextStorageProvider.scala | 9 +- .../java/IOLocalContextStorageSuite.scala | 264 ++++++++++++++++++ 9 files changed, 385 insertions(+), 49 deletions(-) delete mode 100644 java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider delete mode 100644 java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala create mode 100644 java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider create mode 100644 java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala rename java/{common => context-storage}/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala (81%) create mode 100644 java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14b53176b..4113c48f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,11 +84,11 @@ jobs: - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: mkdir -p testkit/metrics/jvm/target java/metrics/target testkit/common/jvm/target core/trace/.js/target semconv/.jvm/target core/common/.jvm/target java/trace/target unidocs/target core/metrics/.native/target core/all/.native/target core/metrics/.jvm/target core/all/.js/target java/all/target java/common/target core/metrics/.js/target core/all/.jvm/target core/trace/.native/target semconv/.js/target core/trace/.jvm/target core/common/.native/target core/common/.js/target semconv/.native/target testkit/all/jvm/target project/target + run: mkdir -p testkit/metrics/jvm/target java/metrics/target testkit/common/jvm/target core/trace/.js/target semconv/.jvm/target core/common/.jvm/target java/trace/target unidocs/target core/metrics/.native/target core/all/.native/target core/metrics/.jvm/target java/context-storage/target core/all/.js/target java/all/target java/common/target core/metrics/.js/target core/all/.jvm/target core/trace/.native/target semconv/.js/target core/trace/.jvm/target core/common/.native/target core/common/.js/target semconv/.native/target testkit/all/jvm/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: tar cf targets.tar testkit/metrics/jvm/target java/metrics/target testkit/common/jvm/target core/trace/.js/target semconv/.jvm/target core/common/.jvm/target java/trace/target unidocs/target core/metrics/.native/target core/all/.native/target core/metrics/.jvm/target core/all/.js/target java/all/target java/common/target core/metrics/.js/target core/all/.jvm/target core/trace/.native/target semconv/.js/target core/trace/.jvm/target core/common/.native/target core/common/.js/target semconv/.native/target testkit/all/jvm/target project/target + run: tar cf targets.tar testkit/metrics/jvm/target java/metrics/target testkit/common/jvm/target core/trace/.js/target semconv/.jvm/target core/common/.jvm/target java/trace/target unidocs/target core/metrics/.native/target core/all/.native/target core/metrics/.jvm/target java/context-storage/target core/all/.js/target java/all/target java/common/target core/metrics/.js/target core/all/.jvm/target core/trace/.native/target semconv/.js/target core/trace/.jvm/target core/common/.native/target core/common/.js/target semconv/.native/target testkit/all/jvm/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') diff --git a/build.sbt b/build.sbt index 547448ab7..a08b8887a 100644 --- a/build.sbt +++ b/build.sbt @@ -67,6 +67,7 @@ lazy val root = tlCrossRootProject `testkit-metrics`, testkit, `java-common`, + `java-context-storage`, `java-metrics`, `java-trace`, java, @@ -288,9 +289,27 @@ lazy val `java-trace` = project ) .settings(scalafixSettings) +lazy val `java-context-storage` = project + .in(file("java/context-storage")) + .dependsOn(`java-common`) + .settings(munitDependencies) + .settings( + name := "otel4s-java-context-storage", + libraryDependencies ++= Seq( + "org.typelevel" %%% "cats-effect" % CatsEffectVersion, + "org.typelevel" %%% "cats-effect-testkit" % CatsEffectVersion % Test, + ), + Test / javaOptions ++= Seq( + "-Dotel.java.global-autoconfigure.enabled=true", + "-Dcats.effect.ioLocalPropagation=true", + ), + Test / fork := true, + ) + .settings(scalafixSettings) + lazy val java = project .in(file("java/all")) - .dependsOn(core.jvm, `java-metrics`, `java-trace`) + .dependsOn(core.jvm, `java-metrics`, `java-trace`, `java-context-storage`) .settings( name := "otel4s-java", libraryDependencies ++= Seq( diff --git a/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider deleted file mode 100644 index aeea4e705..000000000 --- a/java/common/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider +++ /dev/null @@ -1 +0,0 @@ -org.typelevel.otel4s.java.IOLocalContextStorageProvider \ No newline at end of file diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala deleted file mode 100644 index e18a80b38..000000000 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 Typelevel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.typelevel.otel4s.java - -import cats.effect.IOLocal -import cats.effect.unsafe.IOLocals -import io.opentelemetry.context.Context -import io.opentelemetry.context.ContextStorage -import io.opentelemetry.context.Scope - -class IOLocalContextStorage( - _ioLocal: => IOLocal[Context] -) extends ContextStorage { - private[this] lazy val ioLocal = _ioLocal - override def attach(toAttach: Context): Scope = { - val previous = current() - IOLocals.set(ioLocal, toAttach) - new Scope { - def close() = IOLocals.set(ioLocal, previous) - } - } - - override def current(): Context = - IOLocals.get(ioLocal) - -} diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/context/Context.scala b/java/common/src/main/scala/org/typelevel/otel4s/java/context/Context.scala index 6c224b1f2..d3996fb76 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/context/Context.scala +++ b/java/common/src/main/scala/org/typelevel/otel4s/java/context/Context.scala @@ -95,7 +95,7 @@ object Context { } /** The root [[`Context`]], from which all other contexts are derived. */ - val root: Context = wrap(JContext.root()) + lazy val root: Context = wrap(JContext.root()) implicit object Contextual extends context.Contextual[Context] { type Key[A] = Context.Key[A] diff --git a/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider new file mode 100644 index 000000000..6b56f5271 --- /dev/null +++ b/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider @@ -0,0 +1 @@ +org.typelevel.otel4s.java.IOLocalContextStorageProvider diff --git a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala new file mode 100644 index 000000000..ed767622e --- /dev/null +++ b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.typelevel.otel4s.java + +import cats.effect.IOLocal +import cats.effect.LiftIO +import cats.effect.MonadCancelThrow +import cats.effect.unsafe.IOLocals +import io.opentelemetry.context.{Context => JContext} +import io.opentelemetry.context.ContextStorage +import io.opentelemetry.context.Scope +import org.typelevel.otel4s.java.context.Context +import org.typelevel.otel4s.java.context.LocalContext +import org.typelevel.otel4s.java.instances._ + +/** A `ContextStorage` backed by an [[cats.effect.IOLocal `IOLocal`]] of a + * [[`Context`]] that also provides [[cats.mtl.Local `Local`]] instances that + * reflect the state of the backing `IOLocal`. Usage of `Local` and + * `ContextStorage` methods will be consistent and stay in sync as long as + * effects are threaded properly. + */ +class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) + extends ContextStorage { + private[this] implicit lazy val ioLocal: IOLocal[Context] = _ioLocal() + + @inline private[this] def unsafeCurrent: Context = + IOLocals.get(ioLocal) + + override def attach(toAttach: JContext): Scope = { + val previous = unsafeCurrent + IOLocals.set(ioLocal, Context.wrap(toAttach)) + () => IOLocals.set(ioLocal, previous) + } + + override def current(): JContext = + unsafeCurrent.underlying + + /** @return + * a [[cats.mtl.Local `Local`]] of a [[`Context`]] that reflects the state + * of the backing `IOLocal` + */ + def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = implicitly +} + +object IOLocalContextStorage { + + /** Returns a [[cats.mtl.Local `Local`]] of a [[`Context`]] if an + * [[`IOLocalContextStorage`]] is configured to be used as the + * `ContextStorage` for the Java otel library. + * + * Raises an exception if an [[`IOLocalContextStorage`]] is __not__ + * configured to be used as the `ContextStorage` for the Java otel library, + * or if [[cats.effect.IOLocal `IOLocal`]] propagation is not enabled. + */ + def providedLocal[F[_]: LiftIO](implicit + F: MonadCancelThrow[F] + ): F[LocalContext[F]] = + ContextStorage.get() match { + case storage: IOLocalContextStorage => + // TODO: check `IOLocals.arePropagating` instead once our dependencies + // are updated + if (java.lang.Boolean.getBoolean("cats.effect.ioLocalPropagation")) { + F.pure(storage.local) + } else { + F.raiseError( + new IllegalStateException( + "IOLocal propagation must be enabled with: -Dcats.effect.ioLocalPropagation=true" + ) + ) + } + case _ => + F.raiseError( + new IllegalStateException( + "IOLocalContextStorage is not configured for use as the ContextStorageProvider" + ) + ) + } +} diff --git a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala similarity index 81% rename from java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala rename to java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala index d328674d2..0c578051b 100644 --- a/java/common/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala +++ b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala @@ -19,13 +19,13 @@ package org.typelevel.otel4s.java import cats.effect.IOLocal import cats.effect.SyncIO import cats.syntax.all._ -import io.opentelemetry.context.Context import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.ContextStorageProvider +import org.typelevel.otel4s.java.context.Context object IOLocalContextStorageProvider { - val localContext: IOLocal[Context] = - IOLocal[Context](Context.root()) + private lazy val localContext: IOLocal[Context] = + IOLocal[Context](Context.root) .syncStep(100) .flatMap( _.leftMap(_ => @@ -37,7 +37,8 @@ object IOLocalContextStorageProvider { .unsafeRunSync() } +/** SPI implementation for [[`IOLocalContextStorage`]]. */ class IOLocalContextStorageProvider extends ContextStorageProvider { def get(): ContextStorage = - new IOLocalContextStorage(IOLocalContextStorageProvider.localContext) + new IOLocalContextStorage(() => IOLocalContextStorageProvider.localContext) } diff --git a/java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala b/java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala new file mode 100644 index 000000000..b7611887e --- /dev/null +++ b/java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala @@ -0,0 +1,264 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.typelevel.otel4s.java + +import cats.effect.IO +import cats.effect.SyncIO +import io.opentelemetry.context.{Context => JContext} +import io.opentelemetry.context.ContextStorage +import munit.CatsEffectSuite +import munit.Location +import org.typelevel.otel4s.context.Key +import org.typelevel.otel4s.java.context.Context +import org.typelevel.otel4s.java.context.LocalContext + +import scala.util.Using + +class IOLocalContextStorageSuite extends CatsEffectSuite { + import IOLocalContextStorageSuite._ + + private val localF: IO[LocalContext[IO]] = + IOLocalContextStorage.providedLocal + + private def sCurrent[F[_]](implicit L: LocalContext[F]): F[Context] = + L.ask[Context] + private def jCurrent: JContext = JContext.current() + + private def usingModifiedCtx[A](f: JContext => JContext)(body: => A): A = + Using.resource(f(jCurrent).makeCurrent())(_ => body) + + private def localTest( + name: String + )(body: LocalContext[IO] => IO[Any])(implicit loc: Location): Unit = + test(name) { + for { + local <- localF + _ <- body(local) + } yield () + } + + // if this fails, the rest will almost certainly fail, + // and will be meaningless regardless + localTest("correctly configured") { implicit L => + for { + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + // correct ContextStorage is configured + assertEquals( + ContextStorage.get().getClass: Any, + classOf[IOLocalContextStorage]: Any + ) + + // current is root + assertEquals(JContext.root(), Context.root.underlying) + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx, Context.root) + assertEquals(jCtx, JContext.root()) + + // root is empty + assertEquals(sCtx.get(key1), None) + assertEquals(sCtx.get(key2), None) + assertEquals(Option(jCtx.get(key1)), None) + assertEquals(Option(jCtx.get(key2)), None) + } + } + + test("works as a Java-only ContextStorage") { + usingModifiedCtx(_.`with`(key1, "1")) { + assertEquals(Option(jCurrent.get(key1)), Some("1")) + assertEquals(Option(jCurrent.get(key2)), None) + + usingModifiedCtx(_.`with`(key2, 2)) { + assertEquals(Option(jCurrent.get(key1)), Some("1")) + assertEquals(Option(jCurrent.get(key2)), Some(2)) + + usingModifiedCtx(_ => JContext.root()) { + assertEquals(Option(jCurrent.get(key1)), None) + assertEquals(Option(jCurrent.get(key2)), None) + } + } + } + } + + localTest("works as a Scala-only Local") { implicit L => + doLocally(_.updated(key1, "1")) { + for { + _ <- doLocally(_.updated(key2, 2)) { + for { + _ <- doScoped(Context.root) { + for (ctx <- sCurrent) + yield { + assertEquals(ctx.get(key1), None) + assertEquals(ctx.get(key2), None) + } + } + ctx <- sCurrent + } yield { + assertEquals(ctx.get(key1), Some("1")) + assertEquals(ctx.get(key2), Some(2)) + } + } + ctx <- sCurrent + } yield { + assertEquals(ctx.get(key1), Some("1")) + assertEquals(ctx.get(key2), None) + } + } + } + + localTest("Scala with Java nested inside it") { implicit L => + doLocally(_.updated(key1, "1")) { + for { + _ <- IO { + usingModifiedCtx(_.`with`(key2, 2)) { + val sCtx = sCurrent.unsafeRunSync() + val jCtx = jCurrent + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), Some(2)) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), Some(2)) + } + } + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), None) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), None) + } + } + } + + localTest("Java with Scala nested inside it") { implicit L => + IO { + usingModifiedCtx(_.`with`(key1, "1")) { + val sCtx = locally { + for { + _ <- doLocally(_.updated(key2, 2)) { + for { + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), Some(2)) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), Some(2)) + } + } + ctx <- sCurrent + } yield ctx + }.unsafeRunSync() + val jCtx = jCurrent + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), None) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), None) + } + } + } + + localTest("lots of nesting") { implicit L => + doLocally(_.updated(key1, "1")) { + for { + _ <- IO { + usingModifiedCtx(_.`with`(key2, 2)) { + usingModifiedCtx(_.`with`(key1, "3")) { + val sCtx = locally { + for { + _ <- doLocally(_.updated(key2, 4)) { + for { + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("3")) + assertEquals(sCtx.get(key2), Some(4)) + assertEquals(Option(jCtx.get(key1)), Some("3")) + assertEquals(Option(jCtx.get(key2)), Some(4)) + } + } + ctx <- sCurrent + } yield ctx + }.unsafeRunSync() + val jCtx = jCurrent + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("3")) + assertEquals(sCtx.get(key2), Some(2)) + assertEquals(Option(jCtx.get(key1)), Some("3")) + assertEquals(Option(jCtx.get(key2)), Some(2)) + } + val sCtx = locally { + for { + _ <- doScoped(Context.root) { + for { + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), None) + assertEquals(sCtx.get(key2), None) + assertEquals(Option(jCtx.get(key1)), None) + assertEquals(Option(jCtx.get(key2)), None) + } + } + ctx <- sCurrent + } yield ctx + }.unsafeRunSync() + val jCtx = jCurrent + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), Some(2)) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), Some(2)) + } + } + sCtx <- sCurrent + jCtx <- IO(jCurrent) + } yield { + assertEquals(jCtx, sCtx.underlying) + assertEquals(sCtx.get(key1), Some("1")) + assertEquals(sCtx.get(key2), None) + assertEquals(Option(jCtx.get(key1)), Some("1")) + assertEquals(Option(jCtx.get(key2)), None) + } + } + } +} + +object IOLocalContextStorageSuite { + private val keyProvider = Key.Provider[SyncIO, Context.Key] + val key1: Context.Key[String] = + keyProvider.uniqueKey[String]("key1").unsafeRunSync() + val key2: Context.Key[Int] = + keyProvider.uniqueKey[Int]("key2").unsafeRunSync() + + // `Local`'s methods have their argument lists in the an annoying order + def doLocally[F[_], A](f: Context => Context)(fa: F[A])(implicit + L: LocalContext[F] + ): F[A] = + L.local(fa)(f) + def doScoped[F[_], A](e: Context)(fa: F[A])(implicit + L: LocalContext[F] + ): F[A] = + L.scope(fa)(e) +} From 39ba75452b89226b6e07f655a84b3d81ee258ff0 Mon Sep 17 00:00:00 2001 From: Marissa Date: Wed, 4 Oct 2023 15:00:23 -0400 Subject: [PATCH 15/25] fixup! Finish implementing `IOLocalContextStorage` fix docs --- .../otel4s/java/IOLocalContextStorage.scala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala index ed767622e..3e0edc1c6 100644 --- a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala @@ -28,10 +28,10 @@ import org.typelevel.otel4s.java.context.LocalContext import org.typelevel.otel4s.java.instances._ /** A `ContextStorage` backed by an [[cats.effect.IOLocal `IOLocal`]] of a - * [[`Context`]] that also provides [[cats.mtl.Local `Local`]] instances that - * reflect the state of the backing `IOLocal`. Usage of `Local` and - * `ContextStorage` methods will be consistent and stay in sync as long as - * effects are threaded properly. + * [[org.typelevel.otel4s.java.context.Context `Context`]] that also provides + * [[cats.mtl.Local `Local`]] instances that reflect the state of the backing + * `IOLocal`. Usage of `Local` and `ContextStorage` methods will be consistent + * and stay in sync as long as effects are threaded properly. */ class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) extends ContextStorage { @@ -50,15 +50,17 @@ class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) unsafeCurrent.underlying /** @return - * a [[cats.mtl.Local `Local`]] of a [[`Context`]] that reflects the state - * of the backing `IOLocal` + * a [[cats.mtl.Local `Local`]] of a + * [[org.typelevel.otel4s.java.context.Context `Context`]] that reflects + * the state of the backing `IOLocal` */ def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = implicitly } object IOLocalContextStorage { - /** Returns a [[cats.mtl.Local `Local`]] of a [[`Context`]] if an + /** Returns a [[cats.mtl.Local `Local`]] of a + * [[org.typelevel.otel4s.java.context.Context `Context`]] if an * [[`IOLocalContextStorage`]] is configured to be used as the * `ContextStorage` for the Java otel library. * From 713736ba0bf80bed2579c8aec9b8bd50b8eee9bc Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Fri, 13 Dec 2024 19:14:12 +0200 Subject: [PATCH 16/25] Update cats-effect, fix implementation --- build.sbt | 6 +- .../main/scala/ContextStorageExample.scala | 41 +++----- ...entelemetry.context.ContextStorageProvider | 1 - .../otel4s/java/IOLocalContextStorage.scala | 94 ------------------ ...entelemetry.context.ContextStorageProvider | 1 + .../oteljava/IOLocalContextStorage.scala | 98 +++++++++++++++++++ .../IOLocalContextStorageProvider.scala | 4 +- .../IOLocalContextStorageSuite.scala | 15 +-- .../oteljava/trace/SpanBuilderImpl.scala | 2 +- .../sdk/autoconfigure/AutoConfigure.scala | 4 +- .../ExemplarFilterAutoConfigure.scala | 6 +- .../MetricExportersAutoConfigure.scala | 8 +- .../ContextPropagatorsAutoConfigure.scala | 8 +- .../autoconfigure/SamplerAutoConfigure.scala | 6 +- .../SpanExportersAutoConfigure.scala | 8 +- .../SpanLimitsAutoConfigure.scala | 8 +- 16 files changed, 153 insertions(+), 157 deletions(-) delete mode 100644 java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider delete mode 100644 java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala create mode 100644 oteljava/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider create mode 100644 oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala rename {java/context-storage/src/main/scala/org/typelevel/otel4s/java => oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava}/IOLocalContextStorageProvider.scala (93%) rename {java/context-storage/src/test/scala/org/typelevel/otel4s/java => oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava}/IOLocalContextStorageSuite.scala (95%) diff --git a/build.sbt b/build.sbt index 397639855..208550fbb 100644 --- a/build.sbt +++ b/build.sbt @@ -705,12 +705,11 @@ lazy val `oteljava-testkit` = project lazy val `oteljava-context-storage` = project .in(file("oteljava/context-storage")) - .dependsOn(`java-common`) + .dependsOn(`oteljava-common`) .settings(munitDependencies) .settings( - name := "otel4s-java-context-storage", + name := "otel4s-oteljava-context-storage", libraryDependencies ++= Seq( - "org.typelevel" %%% "cats-effect" % CatsEffectVersion, "org.typelevel" %%% "cats-effect-testkit" % CatsEffectVersion % Test, ), Test / javaOptions ++= Seq( @@ -974,6 +973,7 @@ lazy val unidocs = project `oteljava-trace`, `oteljava-trace-testkit`, `oteljava-testkit`, + `oteljava-context-storage`, oteljava, `semconv-stable`.jvm, `semconv-experimental`.jvm, diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index de155209f..f86c1731f 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -16,33 +16,24 @@ import cats.effect.IO import cats.effect.IOApp -import cats.effect.Resource -import io.opentelemetry.context.Context -import io.opentelemetry.context.ContextKey -import io.opentelemetry.context.ContextStorage - -import java.util.logging._ +import io.opentelemetry.api.trace.{Span => JSpan} +import org.typelevel.otel4s.context.LocalProvider +import org.typelevel.otel4s.oteljava.IOLocalContextStorage +import org.typelevel.otel4s.oteljava.OtelJava +import org.typelevel.otel4s.oteljava.context.Context object ContextStorageExample extends IOApp.Simple { - val key = ContextKey.named[String]("test") - - val printKey = - IO(Option(Context.current().get(key))).flatMap(v => IO.println(v)) - - def run = - for { - _ <- IO { - val rootLog = Logger.getLogger("") - rootLog.setLevel(Level.FINE) - rootLog.getHandlers().head.setLevel(Level.FINE) + def run: IO[Unit] = { + implicit val provider: LocalProvider[IO, Context] = IOLocalContextStorage.localProvider[IO] + OtelJava.autoConfigured[IO]().use { otelJava => + otelJava.tracerProvider.tracer("").get.flatMap { tracer => + tracer.span("test").use { span => // start 'test' span using otel4s + val jSpanContext = JSpan.current().getSpanContext // get a span from a ThreadLocal var + IO.println(s"jCtx: ${jSpanContext}, Otel4s ctx: ${span.context}") + } } - _ <- IO.println(ContextStorage.get.getClass()) - _ <- Resource - .make(IO(Context.root().`with`(key, "hello").makeCurrent()))(scope => - IO(scope.close()) - ) - .surround(printKey) - _ <- printKey - } yield () + } + } + } diff --git a/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider deleted file mode 100644 index 6b56f5271..000000000 --- a/java/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider +++ /dev/null @@ -1 +0,0 @@ -org.typelevel.otel4s.java.IOLocalContextStorageProvider diff --git a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala b/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala deleted file mode 100644 index 3e0edc1c6..000000000 --- a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorage.scala +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2022 Typelevel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.typelevel.otel4s.java - -import cats.effect.IOLocal -import cats.effect.LiftIO -import cats.effect.MonadCancelThrow -import cats.effect.unsafe.IOLocals -import io.opentelemetry.context.{Context => JContext} -import io.opentelemetry.context.ContextStorage -import io.opentelemetry.context.Scope -import org.typelevel.otel4s.java.context.Context -import org.typelevel.otel4s.java.context.LocalContext -import org.typelevel.otel4s.java.instances._ - -/** A `ContextStorage` backed by an [[cats.effect.IOLocal `IOLocal`]] of a - * [[org.typelevel.otel4s.java.context.Context `Context`]] that also provides - * [[cats.mtl.Local `Local`]] instances that reflect the state of the backing - * `IOLocal`. Usage of `Local` and `ContextStorage` methods will be consistent - * and stay in sync as long as effects are threaded properly. - */ -class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) - extends ContextStorage { - private[this] implicit lazy val ioLocal: IOLocal[Context] = _ioLocal() - - @inline private[this] def unsafeCurrent: Context = - IOLocals.get(ioLocal) - - override def attach(toAttach: JContext): Scope = { - val previous = unsafeCurrent - IOLocals.set(ioLocal, Context.wrap(toAttach)) - () => IOLocals.set(ioLocal, previous) - } - - override def current(): JContext = - unsafeCurrent.underlying - - /** @return - * a [[cats.mtl.Local `Local`]] of a - * [[org.typelevel.otel4s.java.context.Context `Context`]] that reflects - * the state of the backing `IOLocal` - */ - def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = implicitly -} - -object IOLocalContextStorage { - - /** Returns a [[cats.mtl.Local `Local`]] of a - * [[org.typelevel.otel4s.java.context.Context `Context`]] if an - * [[`IOLocalContextStorage`]] is configured to be used as the - * `ContextStorage` for the Java otel library. - * - * Raises an exception if an [[`IOLocalContextStorage`]] is __not__ - * configured to be used as the `ContextStorage` for the Java otel library, - * or if [[cats.effect.IOLocal `IOLocal`]] propagation is not enabled. - */ - def providedLocal[F[_]: LiftIO](implicit - F: MonadCancelThrow[F] - ): F[LocalContext[F]] = - ContextStorage.get() match { - case storage: IOLocalContextStorage => - // TODO: check `IOLocals.arePropagating` instead once our dependencies - // are updated - if (java.lang.Boolean.getBoolean("cats.effect.ioLocalPropagation")) { - F.pure(storage.local) - } else { - F.raiseError( - new IllegalStateException( - "IOLocal propagation must be enabled with: -Dcats.effect.ioLocalPropagation=true" - ) - ) - } - case _ => - F.raiseError( - new IllegalStateException( - "IOLocalContextStorage is not configured for use as the ContextStorageProvider" - ) - ) - } -} diff --git a/oteljava/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/oteljava/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider new file mode 100644 index 000000000..f8eaf8bae --- /dev/null +++ b/oteljava/context-storage/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider @@ -0,0 +1 @@ +org.typelevel.otel4s.oteljava.IOLocalContextStorageProvider diff --git a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala new file mode 100644 index 000000000..493dc26ad --- /dev/null +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala @@ -0,0 +1,98 @@ +/* + * Copyright 2022 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.typelevel.otel4s.oteljava + +import cats.effect.IOLocal +import cats.effect.LiftIO +import cats.effect.MonadCancelThrow +import cats.mtl.Local +import io.opentelemetry.context.{Context => JContext} +import io.opentelemetry.context.ContextStorage +import io.opentelemetry.context.Scope +import org.typelevel.otel4s.context.LocalProvider +import org.typelevel.otel4s.instances.local._ +import org.typelevel.otel4s.oteljava.context.Context +import org.typelevel.otel4s.oteljava.context.LocalContext + +/** A `ContextStorage` backed by an [[cats.effect.IOLocal `IOLocal`]] of a + * [[org.typelevel.otel4s.oteljava.context.Context `Context`]] that also provides [[cats.mtl.Local `Local`]] instances + * that reflect the state of the backing `IOLocal`. Usage of `Local` and `ContextStorage` methods will be consistent + * and stay in sync as long as effects are threaded properly. + */ +class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) extends ContextStorage { + private[this] implicit lazy val ioLocal: IOLocal[Context] = _ioLocal() + private[this] lazy val unsafeThreadLocal = ioLocal.unsafeThreadLocal() + + @inline private[this] def unsafeCurrent: Context = + unsafeThreadLocal.get() + + override def attach(toAttach: JContext): Scope = { + val previous = unsafeCurrent + unsafeThreadLocal.set(Context.wrap(toAttach)) + () => unsafeThreadLocal.set(previous) + } + + override def current(): JContext = + unsafeCurrent.underlying + + /** @return + * a [[cats.mtl.Local `Local`]] of a [[org.typelevel.otel4s.oteljava.context.Context `Context`]] that reflects the + * state of the backing `IOLocal` + */ + def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = implicitly +} + +object IOLocalContextStorage { + + /** Returns a [[cats.mtl.Local `Local`]] of a [[org.typelevel.otel4s.oteljava.context.Context `Context`]] if an + * [[`IOLocalContextStorage`]] is configured to be used as the `ContextStorage` for the Java otel library. + * + * Raises an exception if an [[`IOLocalContextStorage`]] is __not__ configured to be used as the `ContextStorage` for + * the Java otel library, or if [[cats.effect.IOLocal `IOLocal`]] propagation is not enabled. + * + * @example + * {{{ + * implicit val localProvider: LocalProvider[IO, Context] = IOLocalContextStorage.localProvider + * OtelJava.autoConfigured[IO].use { otel4s => + * ... + * } + * }}} + */ + def localProvider[F[_]: LiftIO](implicit F: MonadCancelThrow[F]): LocalProvider[F, Context] = + new LocalProvider[F, Context] { + def local: F[Local[F, Context]] = + ContextStorage.get() match { + case storage: IOLocalContextStorage => + if (IOLocal.isPropagating) { + F.pure(storage.local) + } else { + F.raiseError( + new IllegalStateException( + "IOLocal propagation must be enabled with: -Dcats.effect.ioLocalPropagation=true" + ) + ) + } + case _ => + F.raiseError( + new IllegalStateException( + "IOLocalContextStorage is not configured for use as the ContextStorageProvider" + ) + ) + } + } + +} diff --git a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageProvider.scala similarity index 93% rename from java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala rename to oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageProvider.scala index 0c578051b..49e9eeb2f 100644 --- a/java/context-storage/src/main/scala/org/typelevel/otel4s/java/IOLocalContextStorageProvider.scala +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageProvider.scala @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.typelevel.otel4s.java +package org.typelevel.otel4s.oteljava import cats.effect.IOLocal import cats.effect.SyncIO import cats.syntax.all._ import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.ContextStorageProvider -import org.typelevel.otel4s.java.context.Context +import org.typelevel.otel4s.oteljava.context.Context object IOLocalContextStorageProvider { private lazy val localContext: IOLocal[Context] = diff --git a/java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala b/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala similarity index 95% rename from java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala rename to oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala index b7611887e..550d6b1fb 100644 --- a/java/context-storage/src/test/scala/org/typelevel/otel4s/java/IOLocalContextStorageSuite.scala +++ b/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.typelevel.otel4s.java +package org.typelevel.otel4s.oteljava import cats.effect.IO import cats.effect.SyncIO @@ -23,16 +23,16 @@ import io.opentelemetry.context.ContextStorage import munit.CatsEffectSuite import munit.Location import org.typelevel.otel4s.context.Key -import org.typelevel.otel4s.java.context.Context -import org.typelevel.otel4s.java.context.LocalContext +import org.typelevel.otel4s.oteljava.context.Context +import org.typelevel.otel4s.oteljava.context.LocalContext import scala.util.Using class IOLocalContextStorageSuite extends CatsEffectSuite { import IOLocalContextStorageSuite._ - private val localF: IO[LocalContext[IO]] = - IOLocalContextStorage.providedLocal + private val localProvider: IO[LocalContext[IO]] = + IOLocalContextStorage.localProvider[IO].local private def sCurrent[F[_]](implicit L: LocalContext[F]): F[Context] = L.ask[Context] @@ -46,7 +46,7 @@ class IOLocalContextStorageSuite extends CatsEffectSuite { )(body: LocalContext[IO] => IO[Any])(implicit loc: Location): Unit = test(name) { for { - local <- localF + local <- localProvider _ <- body(local) } yield () } @@ -78,7 +78,8 @@ class IOLocalContextStorageSuite extends CatsEffectSuite { } } - test("works as a Java-only ContextStorage") { + // see https://discord.com/channels/632277896739946517/839263556754472990/1317163027451088926 + test("works as a Java-only ContextStorage".ignore) { usingModifiedCtx(_.`with`(key1, "1")) { assertEquals(Option(jCurrent.get(key1)), Some("1")) assertEquals(Option(jCurrent.get(key2)), None) diff --git a/oteljava/trace/src/main/scala/org/typelevel/otel4s/oteljava/trace/SpanBuilderImpl.scala b/oteljava/trace/src/main/scala/org/typelevel/otel4s/oteljava/trace/SpanBuilderImpl.scala index 3208cec7d..719913d7d 100644 --- a/oteljava/trace/src/main/scala/org/typelevel/otel4s/oteljava/trace/SpanBuilderImpl.scala +++ b/oteljava/trace/src/main/scala/org/typelevel/otel4s/oteljava/trace/SpanBuilderImpl.scala @@ -59,7 +59,7 @@ private[oteljava] final case class SpanBuilderImpl[F[_]: Sync] private ( Resource.eval(runnerContext).flatMap(ctx => runner.start(ctx)) override def use[A](f: Span[F] => F[A]): F[A] = - resource.use { res => res.trace(f(res.span)) } + resource.use(res => res.trace(Sync[F].defer(f(res.span)))) override def use_ : F[Unit] = use(_ => Sync[F].unit) } diff --git a/sdk/common/shared/src/main/scala/org/typelevel/otel4s/sdk/autoconfigure/AutoConfigure.scala b/sdk/common/shared/src/main/scala/org/typelevel/otel4s/sdk/autoconfigure/AutoConfigure.scala index 093a95099..4ff0c1eb3 100644 --- a/sdk/common/shared/src/main/scala/org/typelevel/otel4s/sdk/autoconfigure/AutoConfigure.scala +++ b/sdk/common/shared/src/main/scala/org/typelevel/otel4s/sdk/autoconfigure/AutoConfigure.scala @@ -16,7 +16,7 @@ package org.typelevel.otel4s.sdk.autoconfigure -import cats.MonadThrow +import cats.effect.MonadCancelThrow import cats.effect.Resource import cats.syntax.monadError._ @@ -89,7 +89,7 @@ object AutoConfigure { * @tparam A * the type of the component */ - abstract class WithHint[F[_]: MonadThrow, A]( + abstract class WithHint[F[_]: MonadCancelThrow, A]( hint: String, configKeys: Set[Config.Key[_]] ) extends AutoConfigure[F, A] { diff --git a/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/ExemplarFilterAutoConfigure.scala b/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/ExemplarFilterAutoConfigure.scala index 2c0eda1c6..4f4e91684 100644 --- a/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/ExemplarFilterAutoConfigure.scala +++ b/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/ExemplarFilterAutoConfigure.scala @@ -16,7 +16,7 @@ package org.typelevel.otel4s.sdk.metrics.autoconfigure -import cats.MonadThrow +import cats.effect.MonadCancelThrow import cats.effect.Resource import org.typelevel.otel4s.sdk.autoconfigure.AutoConfigure import org.typelevel.otel4s.sdk.autoconfigure.Config @@ -41,7 +41,7 @@ import org.typelevel.otel4s.sdk.metrics.exemplar.TraceContextLookup * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#exemplars]] */ -private final class ExemplarFilterAutoConfigure[F[_]: MonadThrow]( +private final class ExemplarFilterAutoConfigure[F[_]: MonadCancelThrow]( lookup: TraceContextLookup ) extends AutoConfigure.WithHint[F, ExemplarFilter]( "ExemplarFilter", @@ -118,7 +118,7 @@ private[sdk] object ExemplarFilterAutoConfigure { * @param traceContextLookup * used by the exemplar reservoir to extract tracing information from the context */ - def apply[F[_]: MonadThrow]( + def apply[F[_]: MonadCancelThrow]( traceContextLookup: TraceContextLookup ): AutoConfigure[F, ExemplarFilter] = new ExemplarFilterAutoConfigure[F](traceContextLookup) diff --git a/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/MetricExportersAutoConfigure.scala b/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/MetricExportersAutoConfigure.scala index 26283d522..e83f34dc8 100644 --- a/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/MetricExportersAutoConfigure.scala +++ b/sdk/metrics/src/main/scala/org/typelevel/otel4s/sdk/metrics/autoconfigure/MetricExportersAutoConfigure.scala @@ -16,8 +16,8 @@ package org.typelevel.otel4s.sdk.metrics.autoconfigure -import cats.MonadThrow import cats.data.NonEmptyList +import cats.effect.MonadCancelThrow import cats.effect.Resource import cats.effect.std.Console import cats.syntax.applicative._ @@ -41,7 +41,7 @@ import org.typelevel.otel4s.sdk.metrics.exporter.MetricExporter * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#metric-exporters]] */ -private final class MetricExportersAutoConfigure[F[_]: MonadThrow: Console]( +private final class MetricExportersAutoConfigure[F[_]: MonadCancelThrow: Console]( extra: Set[AutoConfigure.Named[F, MetricExporter[F]]] ) extends AutoConfigure.WithHint[F, Map[String, MetricExporter[F]]]( "MetricExporters", @@ -64,7 +64,7 @@ private final class MetricExportersAutoConfigure[F[_]: MonadThrow: Console]( config: Config ): Resource[F, Map[String, MetricExporter[F]]] = { val values = config.getOrElse(ConfigKeys.Exporter, Set.empty[String]) - Resource.eval(MonadThrow[F].fromEither(values)).flatMap { + Resource.eval(MonadCancelThrow[F].fromEither(values)).flatMap { case names if names.contains(Const.NoneExporter) && names.sizeIs > 1 => Resource.raiseError( ConfigurationError( @@ -162,7 +162,7 @@ private[sdk] object MetricExportersAutoConfigure { * @param configurers * the configurers to use */ - def apply[F[_]: MonadThrow: Console]( + def apply[F[_]: MonadCancelThrow: Console]( configurers: Set[AutoConfigure.Named[F, MetricExporter[F]]] ): AutoConfigure[F, Map[String, MetricExporter[F]]] = new MetricExportersAutoConfigure[F](configurers) diff --git a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/ContextPropagatorsAutoConfigure.scala b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/ContextPropagatorsAutoConfigure.scala index 86238592a..75a6a5534 100644 --- a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/ContextPropagatorsAutoConfigure.scala +++ b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/ContextPropagatorsAutoConfigure.scala @@ -16,8 +16,8 @@ package org.typelevel.otel4s.sdk.trace.autoconfigure -import cats.MonadThrow import cats.data.NonEmptyList +import cats.effect.MonadCancelThrow import cats.effect.Resource import org.typelevel.otel4s.context.propagation.ContextPropagators import org.typelevel.otel4s.context.propagation.TextMapPropagator @@ -43,7 +43,7 @@ import org.typelevel.otel4s.sdk.trace.context.propagation.W3CTraceContextPropaga * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#propagators]] */ -private final class ContextPropagatorsAutoConfigure[F[_]: MonadThrow]( +private final class ContextPropagatorsAutoConfigure[F[_]: MonadCancelThrow]( extra: Set[AutoConfigure.Named[F, TextMapPropagator[Context]]] ) extends AutoConfigure.WithHint[F, ContextPropagators[Context]]( "ContextPropagators", @@ -73,7 +73,7 @@ private final class ContextPropagatorsAutoConfigure[F[_]: MonadThrow]( def fromConfig(config: Config): Resource[F, ContextPropagators[Context]] = { val values = config.getOrElse(ConfigKeys.Propagators, Set.empty[String]) - Resource.eval(MonadThrow[F].fromEither(values)).flatMap { + Resource.eval(MonadCancelThrow[F].fromEither(values)).flatMap { case names if names.contains(Const.NonePropagator) && names.sizeIs > 1 => Resource.raiseError( ConfigurationError( @@ -149,7 +149,7 @@ private[sdk] object ContextPropagatorsAutoConfigure { * @param extra * extra configurers to use */ - def apply[F[_]: MonadThrow]( + def apply[F[_]: MonadCancelThrow]( extra: Set[AutoConfigure.Named[F, TextMapPropagator[Context]]] ): AutoConfigure[F, ContextPropagators[Context]] = new ContextPropagatorsAutoConfigure[F](extra) diff --git a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SamplerAutoConfigure.scala b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SamplerAutoConfigure.scala index 4ffbe822b..0da582cd9 100644 --- a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SamplerAutoConfigure.scala +++ b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SamplerAutoConfigure.scala @@ -16,7 +16,7 @@ package org.typelevel.otel4s.sdk.trace.autoconfigure -import cats.MonadThrow +import cats.effect.MonadCancelThrow import cats.effect.Resource import cats.syntax.either._ import org.typelevel.otel4s.sdk.autoconfigure.AutoConfigure @@ -37,7 +37,7 @@ import org.typelevel.otel4s.sdk.trace.samplers.Sampler * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#sampler]] */ -private final class SamplerAutoConfigure[F[_]: MonadThrow]( +private final class SamplerAutoConfigure[F[_]: MonadCancelThrow]( extra: Set[AutoConfigure.Named[F, Sampler[F]]] ) extends AutoConfigure.WithHint[F, Sampler[F]]("Sampler", SamplerAutoConfigure.ConfigKeys.All) { @@ -154,7 +154,7 @@ private[sdk] object SamplerAutoConfigure { * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#sampler]] */ - def apply[F[_]: MonadThrow](extra: Set[AutoConfigure.Named[F, Sampler[F]]]): AutoConfigure[F, Sampler[F]] = + def apply[F[_]: MonadCancelThrow](extra: Set[AutoConfigure.Named[F, Sampler[F]]]): AutoConfigure[F, Sampler[F]] = new SamplerAutoConfigure[F](extra) } diff --git a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanExportersAutoConfigure.scala b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanExportersAutoConfigure.scala index 6f8d60267..5d83f019d 100644 --- a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanExportersAutoConfigure.scala +++ b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanExportersAutoConfigure.scala @@ -16,8 +16,8 @@ package org.typelevel.otel4s.sdk.trace.autoconfigure -import cats.MonadThrow import cats.data.NonEmptyList +import cats.effect.MonadCancelThrow import cats.effect.Resource import cats.effect.std.Console import cats.syntax.applicative._ @@ -41,7 +41,7 @@ import org.typelevel.otel4s.sdk.trace.exporter.SpanExporter * @see * [[https://opentelemetry.io/docs/languages/java/configuration/#span-exporters]] */ -private final class SpanExportersAutoConfigure[F[_]: MonadThrow: Console]( +private final class SpanExportersAutoConfigure[F[_]: MonadCancelThrow: Console]( extra: Set[AutoConfigure.Named[F, SpanExporter[F]]] ) extends AutoConfigure.WithHint[F, Map[String, SpanExporter[F]]]( "SpanExporters", @@ -62,7 +62,7 @@ private final class SpanExportersAutoConfigure[F[_]: MonadThrow: Console]( def fromConfig(config: Config): Resource[F, Map[String, SpanExporter[F]]] = { val values = config.getOrElse(ConfigKeys.Exporter, Set.empty[String]) - Resource.eval(MonadThrow[F].fromEither(values)).flatMap { + Resource.eval(MonadCancelThrow[F].fromEither(values)).flatMap { case names if names.contains(Const.NoneExporter) && names.sizeIs > 1 => Resource.raiseError( ConfigurationError( @@ -157,7 +157,7 @@ private[sdk] object SpanExportersAutoConfigure { * @param configurers * the configurers to use */ - def apply[F[_]: MonadThrow: Console]( + def apply[F[_]: MonadCancelThrow: Console]( configurers: Set[AutoConfigure.Named[F, SpanExporter[F]]] ): AutoConfigure[F, Map[String, SpanExporter[F]]] = new SpanExportersAutoConfigure[F](configurers) diff --git a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanLimitsAutoConfigure.scala b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanLimitsAutoConfigure.scala index a73da2b6a..304e7c44f 100644 --- a/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanLimitsAutoConfigure.scala +++ b/sdk/trace/src/main/scala/org/typelevel/otel4s/sdk/trace/autoconfigure/SpanLimitsAutoConfigure.scala @@ -16,7 +16,7 @@ package org.typelevel.otel4s.sdk.trace.autoconfigure -import cats.MonadThrow +import cats.effect.MonadCancelThrow import cats.effect.Resource import org.typelevel.otel4s.sdk.autoconfigure.AutoConfigure import org.typelevel.otel4s.sdk.autoconfigure.Config @@ -39,7 +39,7 @@ import org.typelevel.otel4s.sdk.trace.SpanLimits * @see * [[https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits]] */ -private final class SpanLimitsAutoConfigure[F[_]: MonadThrow] +private final class SpanLimitsAutoConfigure[F[_]: MonadCancelThrow] extends AutoConfigure.WithHint[F, SpanLimits]( "SpanLimits", SpanLimitsAutoConfigure.ConfigKeys.All @@ -100,7 +100,7 @@ private final class SpanLimitsAutoConfigure[F[_]: MonadThrow] withMaxAttributeValueLength.build } - Resource.eval(MonadThrow[F].fromEither(configure)) + Resource.eval(MonadCancelThrow[F].fromEither(configure)) } } @@ -153,7 +153,7 @@ private[sdk] object SpanLimitsAutoConfigure { * @see * [[https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#span-limits]] */ - def apply[F[_]: MonadThrow]: AutoConfigure[F, SpanLimits] = + def apply[F[_]: MonadCancelThrow]: AutoConfigure[F, SpanLimits] = new SpanLimitsAutoConfigure[F] } From b9b8fd9d62e75410e69f1f2b0ab0cce6b3e274f3 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Fri, 13 Dec 2024 19:21:14 +0200 Subject: [PATCH 17/25] Fix CI workflow --- .github/workflows/ci.yml | 4 ++-- examples/src/main/scala/ContextStorageExample.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80fb37f50..c3e7faf58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,11 +91,11 @@ jobs: - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') diff --git a/examples/src/main/scala/ContextStorageExample.scala b/examples/src/main/scala/ContextStorageExample.scala index f86c1731f..b60e01d1a 100644 --- a/examples/src/main/scala/ContextStorageExample.scala +++ b/examples/src/main/scala/ContextStorageExample.scala @@ -27,7 +27,7 @@ object ContextStorageExample extends IOApp.Simple { def run: IO[Unit] = { implicit val provider: LocalProvider[IO, Context] = IOLocalContextStorage.localProvider[IO] OtelJava.autoConfigured[IO]().use { otelJava => - otelJava.tracerProvider.tracer("").get.flatMap { tracer => + otelJava.tracerProvider.tracer("com.service").get.flatMap { tracer => tracer.span("test").use { span => // start 'test' span using otel4s val jSpanContext = JSpan.current().getSpanContext // get a span from a ThreadLocal var IO.println(s"jCtx: ${jSpanContext}, Otel4s ctx: ${span.context}") From 653ebf08575b3c89cf3acf9d383ce7d499b26b4c Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Sat, 28 Dec 2024 10:05:19 +0200 Subject: [PATCH 18/25] Use cats-effect 3.6.0-RC1 --- build.sbt | 11 +++++------ .../oteljava/IOLocalContextStorage.scala | 18 ++++++++++++++++-- .../oteljava/IOLocalContextStorageSuite.scala | 3 +-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 208550fbb..61a4dd22e 100644 --- a/build.sbt +++ b/build.sbt @@ -76,7 +76,7 @@ ThisBuild / mergifyPrRules ++= Seq( ) val CatsVersion = "2.11.0" -val CatsEffectVersion = "3.6-28f8f29" +val CatsEffectVersion = "3.6.0-RC1" val CatsMtlVersion = "1.4.0" val FS2Version = "3.11.0" val MUnitVersion = "1.0.0" @@ -713,8 +713,7 @@ lazy val `oteljava-context-storage` = project "org.typelevel" %%% "cats-effect-testkit" % CatsEffectVersion % Test, ), Test / javaOptions ++= Seq( - "-Dotel.java.global-autoconfigure.enabled=true", - "-Dcats.effect.ioLocalPropagation=true", + "-Dcats.effect.trackFiberContext=true", ), Test / fork := true, ) @@ -728,7 +727,6 @@ lazy val oteljava = project `oteljava-metrics-testkit` % Test, `oteljava-trace` % "compile->compile;test->test", `oteljava-trace-testkit` % Test, - `oteljava-context-storage` ) .settings( name := "otel4s-oteljava", @@ -853,7 +851,7 @@ lazy val benchmarks = project lazy val examples = project .enablePlugins(NoPublishPlugin, JavaAgent) .in(file("examples")) - .dependsOn(core.jvm, oteljava, sdk.jvm, `sdk-exporter`.jvm, `sdk-exporter-prometheus`.jvm) + .dependsOn(core.jvm, oteljava, `oteljava-context-storage`, sdk.jvm, `sdk-exporter`.jvm, `sdk-exporter-prometheus`.jvm) .settings( name := "otel4s-examples", libraryDependencies ++= Seq( @@ -868,7 +866,7 @@ lazy val examples = project javaAgents += "io.opentelemetry.javaagent" % "opentelemetry-javaagent" % OpenTelemetryInstrumentationVersion % Runtime, run / fork := true, javaOptions += "-Dotel.java.global-autoconfigure.enabled=true", - javaOptions += "-Dcats.effect.ioLocalPropagation=true", + javaOptions += "-Dcats.effect.trackFiberContext=true", envVars ++= Map( "OTEL_PROPAGATORS" -> "b3multi", "OTEL_SERVICE_NAME" -> "Trace Example" @@ -881,6 +879,7 @@ lazy val docs = project .enablePlugins(TypelevelSitePlugin) .dependsOn( oteljava, + `oteljava-context-storage`, `oteljava-testkit`, sdk.jvm, `sdk-exporter`.jvm, diff --git a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala index 493dc26ad..f44af666a 100644 --- a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala @@ -19,6 +19,7 @@ package org.typelevel.otel4s.oteljava import cats.effect.IOLocal import cats.effect.LiftIO import cats.effect.MonadCancelThrow +import cats.effect.unsafe.IORuntime import cats.mtl.Local import io.opentelemetry.context.{Context => JContext} import io.opentelemetry.context.ContextStorage @@ -35,7 +36,20 @@ import org.typelevel.otel4s.oteljava.context.LocalContext */ class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) extends ContextStorage { private[this] implicit lazy val ioLocal: IOLocal[Context] = _ioLocal() - private[this] lazy val unsafeThreadLocal = ioLocal.unsafeThreadLocal() + private[this] lazy val unsafeThreadLocal: ThreadLocal[Context] = { + val fiberLocal = ioLocal.unsafeThreadLocal() + + new ThreadLocal[Context] { + override def initialValue(): Context = + Context.root + + override def get(): Context = + if (IORuntime.isUnderFiberContext()) fiberLocal.get() else super.get() + + override def set(value: Context): Unit = + if (IORuntime.isUnderFiberContext()) fiberLocal.set(value) else super.set(value) + } + } @inline private[this] def unsafeCurrent: Context = unsafeThreadLocal.get() @@ -82,7 +96,7 @@ object IOLocalContextStorage { } else { F.raiseError( new IllegalStateException( - "IOLocal propagation must be enabled with: -Dcats.effect.ioLocalPropagation=true" + "IOLocal propagation must be enabled with: -Dcats.effect.trackFiberContext=true" ) ) } diff --git a/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala b/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala index 550d6b1fb..a6f6a913f 100644 --- a/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala +++ b/oteljava/context-storage/src/test/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorageSuite.scala @@ -78,8 +78,7 @@ class IOLocalContextStorageSuite extends CatsEffectSuite { } } - // see https://discord.com/channels/632277896739946517/839263556754472990/1317163027451088926 - test("works as a Java-only ContextStorage".ignore) { + test("works as a Java-only ContextStorage") { usingModifiedCtx(_.`with`(key1, "1")) { assertEquals(Option(jCurrent.get(key1)), Some("1")) assertEquals(Option(jCurrent.get(key2)), None) From 5cf5a4e45178b510aeeb92520535a448791d5d1c Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Sat, 28 Dec 2024 10:31:17 +0200 Subject: [PATCH 19/25] Fix docs --- build.sbt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.sbt b/build.sbt index 61a4dd22e..072cd3686 100644 --- a/build.sbt +++ b/build.sbt @@ -903,6 +903,8 @@ lazy val docs = project "OPEN_TELEMETRY_VERSION" -> OpenTelemetryVersion, "OPEN_TELEMETRY_INSTRUMENTATION_ALPHA_VERSION" -> OpenTelemetryInstrumentationAlphaVersion ), + run / fork := true, + javaOptions += "-Dcats.effect.trackFiberContext=true", laikaConfig := { import laika.config.{ChoiceConfig, Selections, SelectionConfig} From 44ddc9aed3654c03035cd762fc5cabf9b0831d87 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 12:53:05 +0200 Subject: [PATCH 20/25] Add minimal documentation --- build.sbt | 2 +- docs/oteljava/directory.conf | 1 + docs/oteljava/tracing-context-propagation.md | 85 +++++++++++++++++++ .../oteljava/IOLocalContextStorage.scala | 5 +- 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 docs/oteljava/tracing-context-propagation.md diff --git a/build.sbt b/build.sbt index ba4254d27..d70e26486 100644 --- a/build.sbt +++ b/build.sbt @@ -726,7 +726,7 @@ lazy val oteljava = project `oteljava-metrics` % "compile->compile;test->test", `oteljava-metrics-testkit` % Test, `oteljava-trace` % "compile->compile;test->test", - `oteljava-trace-testkit` % Test, + `oteljava-trace-testkit` % Test ) .settings( name := "otel4s-oteljava", diff --git a/docs/oteljava/directory.conf b/docs/oteljava/directory.conf index a4fdce20e..b09a16267 100644 --- a/docs/oteljava/directory.conf +++ b/docs/oteljava/directory.conf @@ -3,6 +3,7 @@ laika.title = OtelJava laika.navigationOrder = [ overview.md metrics-jvm-runtime.md + tracing-context-propagation.md tracing-java-interop.md testkit.md ] diff --git a/docs/oteljava/tracing-context-propagation.md b/docs/oteljava/tracing-context-propagation.md new file mode 100644 index 000000000..7eb29f126 --- /dev/null +++ b/docs/oteljava/tracing-context-propagation.md @@ -0,0 +1,85 @@ +# Tracing | Context propagation + +[OpenTelemetry Java SDK][opentelemetry-java] and otel4s rely on different context manipulation approaches, +which aren't interoperable out of the box. +Java SDK utilizes ThreadLocal variables to share tracing information, +otel4s, on the other hand, uses [Local][cats-mtl-local]. + +Cats Effect 3.6.0 introduced a new method of fiber context tracking, +which can be integrated almost seamlessly with the OpenTelemetry Java SDK. + +## Getting started + +@:select(build-tool) + +@:choice(sbt) + +Add settings to the `build.sbt`: + +```scala +libraryDependencies ++= Seq( + "org.typelevel" %% "otel4s-oteljava" % "@VERSION@", // <1> + "org.typelevel" %% "otel4s-oteljava-context-storage" % "@VERSION@", // <2> +) +javaOptions += "-Dcats.effect.trackFiberContext=true" // <3> +``` + +@:choice(scala-cli) + +Add directives to the `*.scala` file: + +```scala +//> using dep "org.typelevel::otel4s-oteljava:@VERSION@" // <1> +//> using dep "org.typelevel::otel4s-oteljava-context-storage:@VERSION@" // <2> +//> using `java-opt` "-Dcats.effect.trackFiberContext=true" // <3> +``` + +@:@ + +1. Add the `otel4s-oteljava` library +2. Add the `otel4s-oteljava-context-storage` library +3. Enable Cats Effect fiber context tracking + +## Configuration + +You need to use `IOLocalContextStorage.localProvider[IO]` to provide the global context storage, backed by `IOLocal`: +```scala mdoc:silent +import cats.effect.IO +import io.opentelemetry.api.trace.{Span => JSpan} +import org.typelevel.otel4s.context.LocalProvider +import org.typelevel.otel4s.oteljava.IOLocalContextStorage +import org.typelevel.otel4s.oteljava.OtelJava +import org.typelevel.otel4s.oteljava.context.Context +import org.typelevel.otel4s.trace.Tracer + +def program(tracer: Tracer[IO]): IO[Unit] = + tracer.span("test").use { span => // start 'test' span using otel4s + val jSpanContext = JSpan.current().getSpanContext // get a span from a ThreadLocal var + IO.println(s"jctx: ${jSpanContext}") >> IO.println(s"otel4s: ${span.context}") + } + +def run: IO[Unit] = { + implicit val provider: LocalProvider[IO, Context] = + IOLocalContextStorage.localProvider[IO] + + OtelJava.autoConfigured[IO]().use { otelJava => + otelJava.tracerProvider.tracer("com.service").get.flatMap { tracer => + program(tracer) + } + } +} +``` + +According to the output, the context is the same: +``` +jctx : SpanContext{traceId=58b8ed50a558ca53fcc64a0d80b5e662, spanId=fc25fe2c9fb41905, ...} +otel4s: SpanContext{traceId=58b8ed50a558ca53fcc64a0d80b5e662, spanId=fc25fe2c9fb41905, ...} +``` + +## Limitations + +The `IOLocalContextStorageProvider` doesn't work with [OpenTelemetry Java Agent][opentelemetry-java-agent]. + +[opentelemetry-java]: https://github.com/open-telemetry/opentelemetry-java +[opentelemetry-java-agent]: https://opentelemetry.io/docs/zero-code/java/agent/ +[cats-mtl-local]: https://typelevel.org/cats-mtl/mtl-classes/local.html diff --git a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala index f44af666a..6f85ead71 100644 --- a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala @@ -100,10 +100,11 @@ object IOLocalContextStorage { ) ) } - case _ => + case other => F.raiseError( new IllegalStateException( - "IOLocalContextStorage is not configured for use as the ContextStorageProvider" + s"IOLocalContextStorage is not configured for use as the ContextStorageProvider. " + + s"The current storage: ${other.getClass.getName}." ) ) } From 05b886d40f2c318b622ea5bd47bcd2d74033d571 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 13:01:46 +0200 Subject: [PATCH 21/25] Run scalafix --- .../org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala index 6f85ead71..375be21c6 100644 --- a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala @@ -103,7 +103,7 @@ object IOLocalContextStorage { case other => F.raiseError( new IllegalStateException( - s"IOLocalContextStorage is not configured for use as the ContextStorageProvider. " + + "IOLocalContextStorage is not configured for use as the ContextStorageProvider. " + s"The current storage: ${other.getClass.getName}." ) ) From 45c08f6b514cb49efc3fea3ed492338c08f88ea6 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 13:06:45 +0200 Subject: [PATCH 22/25] Update doc example --- docs/oteljava/tracing-context-propagation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/oteljava/tracing-context-propagation.md b/docs/oteljava/tracing-context-propagation.md index 7eb29f126..ed34313f1 100644 --- a/docs/oteljava/tracing-context-propagation.md +++ b/docs/oteljava/tracing-context-propagation.md @@ -54,8 +54,8 @@ import org.typelevel.otel4s.trace.Tracer def program(tracer: Tracer[IO]): IO[Unit] = tracer.span("test").use { span => // start 'test' span using otel4s - val jSpanContext = JSpan.current().getSpanContext // get a span from a ThreadLocal var - IO.println(s"jctx: ${jSpanContext}") >> IO.println(s"otel4s: ${span.context}") + println(s"jctx : ${JSpan.current().getSpanContext}") // get a span from a ThreadLocal var + IO.println(s"otel4s: ${span.context}") } def run: IO[Unit] = { From b54341a3ba0be00a944177a6d0eed0e174234142 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 13:18:53 +0200 Subject: [PATCH 23/25] Regenerate ci.yml --- .github/workflows/ci.yml | 4 ++-- build.sbt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 470c300a3..5cfda504e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,11 +91,11 @@ jobs: - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk/common/native/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target sdk/common/native/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') diff --git a/build.sbt b/build.sbt index d70e26486..20ee3fa72 100644 --- a/build.sbt +++ b/build.sbt @@ -28,7 +28,9 @@ lazy val scalaJSLinkerSettings = Def.settings( scalaJSLinkerConfig ~= (_.withESFeatures( _.withESVersion(org.scalajs.linker.interface.ESVersion.ES2018) )), - Test / scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)) + Test / scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), + // the JS artifacts could be quite large and exceed the CI disk space limit + githubWorkflowArtifactUpload := false ) lazy val scalaNativeSettings = Def.settings( From f1f0925ddd9020bbfe2ee883547f9eafbbe65074 Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 13:19:54 +0200 Subject: [PATCH 24/25] Regenerate ci.yml --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b29f7a909..d2a6b0cc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,11 +91,11 @@ jobs: - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target instrumentation/metrics/js/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target instrumentation/metrics/jvm/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target instrumentation/metrics/native/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: mkdir -p semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target instrumentation/metrics/js/target sdk/common/native/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target instrumentation/metrics/jvm/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target instrumentation/metrics/native/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target instrumentation/metrics/js/target sdk-exporter/common/.js/target sdk/common/native/target sdk/common/js/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target sdk-exporter/prometheus/.js/target semconv/experimental/.js/target sdk/trace/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target sdk-contrib/aws/resource/.js/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target sdk-exporter/metrics/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target instrumentation/metrics/jvm/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target sdk/metrics/.js/target sdk-exporter/trace/.js/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target sdk-contrib/aws/xray/.js/target sdk-contrib/aws/xray-propagator/.js/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target instrumentation/metrics/native/target sdk/all/.js/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target + run: tar cf targets.tar semconv/stable/.jvm/target oteljava/metrics/target oteljava/context-storage/target instrumentation/metrics/js/target sdk/common/native/target core/trace/.js/target semconv/metrics/stable/.jvm/target semconv/metrics/experimental/.jvm/target semconv/metrics/stable/.native/target sdk-exporter/all/.jvm/target semconv/experimental/.js/target core/common/.jvm/target oteljava/common-testkit/target sdk/metrics/.native/target sdk-exporter/metrics/.jvm/target sdk-exporter/trace/.jvm/target unidocs/target sdk-contrib/aws/resource/.jvm/target oteljava/trace-testkit/target core/metrics/.native/target core/all/.native/target sdk/trace-testkit/.jvm/target sdk/trace-testkit/.native/target sdk/testkit/.native/target sdk-exporter/prometheus/.jvm/target semconv/experimental/.native/target core/metrics/.jvm/target core/all/.js/target sdk-exporter/proto/.jvm/target sdk-exporter/proto/.js/target semconv/stable/.native/target sdk/all/.native/target sdk/metrics-testkit/.js/target sdk-contrib/aws/xray-propagator/.native/target core/metrics/.js/target sdk/testkit/.js/target core/all/.jvm/target sdk/common/jvm/target core/trace/.native/target oteljava/metrics-testkit/target instrumentation/metrics/jvm/target sdk/trace/.native/target semconv/experimental/.jvm/target sdk/metrics-testkit/.native/target sdk/metrics/.jvm/target oteljava/common/target scalafix/rules/target sdk-exporter/proto/.native/target core/trace/.jvm/target sdk-exporter/common/.jvm/target sdk/metrics-testkit/.jvm/target core/common/.native/target sdk/trace-testkit/.js/target core/common/.js/target oteljava/trace/target semconv/metrics/experimental/.native/target oteljava/testkit/target sdk/testkit/.jvm/target sdk-exporter/all/.js/target sdk-contrib/aws/xray/.native/target semconv/metrics/experimental/.js/target semconv/metrics/stable/.js/target instrumentation/metrics/native/target sdk/all/.jvm/target sdk-exporter/all/.native/target oteljava/all/target sdk/trace/.jvm/target sdk-contrib/aws/xray-propagator/.jvm/target semconv/stable/.js/target sdk-contrib/aws/xray/.jvm/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') From 5cd592f79474688713feb93c6bbc7172bbe97b2f Mon Sep 17 00:00:00 2001 From: Maksym Ochenashko Date: Tue, 31 Dec 2024 14:30:38 +0200 Subject: [PATCH 25/25] Fix compilation issue --- .../scala/org/typelevel/otel4s/context/LocalProvider.scala | 2 +- .../typelevel/otel4s/oteljava/IOLocalContextStorage.scala | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/common/src/main/scala/org/typelevel/otel4s/context/LocalProvider.scala b/core/common/src/main/scala/org/typelevel/otel4s/context/LocalProvider.scala index 5749c36c8..635b543c7 100644 --- a/core/common/src/main/scala/org/typelevel/otel4s/context/LocalProvider.scala +++ b/core/common/src/main/scala/org/typelevel/otel4s/context/LocalProvider.scala @@ -130,7 +130,7 @@ object LocalProvider extends LocalProviderLowPriority { /** Cats Effect 3.6 introduced `IOLocal#asLocal`. However, we need a variation for a polymorphic type. */ - private def localForIOLocal[F[_]: MonadCancelThrow: LiftIO, Ctx](ioLocal: IOLocal[Ctx]): Local[F, Ctx] = + private[otel4s] def localForIOLocal[F[_]: MonadCancelThrow: LiftIO, Ctx](ioLocal: IOLocal[Ctx]): Local[F, Ctx] = new Local[F, Ctx] { def applicative: Applicative[F] = Applicative[F] diff --git a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala index 375be21c6..6dab114e5 100644 --- a/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala +++ b/oteljava/context-storage/src/main/scala/org/typelevel/otel4s/oteljava/IOLocalContextStorage.scala @@ -25,7 +25,6 @@ import io.opentelemetry.context.{Context => JContext} import io.opentelemetry.context.ContextStorage import io.opentelemetry.context.Scope import org.typelevel.otel4s.context.LocalProvider -import org.typelevel.otel4s.instances.local._ import org.typelevel.otel4s.oteljava.context.Context import org.typelevel.otel4s.oteljava.context.LocalContext @@ -35,7 +34,7 @@ import org.typelevel.otel4s.oteljava.context.LocalContext * and stay in sync as long as effects are threaded properly. */ class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) extends ContextStorage { - private[this] implicit lazy val ioLocal: IOLocal[Context] = _ioLocal() + private[this] lazy val ioLocal: IOLocal[Context] = _ioLocal() private[this] lazy val unsafeThreadLocal: ThreadLocal[Context] = { val fiberLocal = ioLocal.unsafeThreadLocal() @@ -67,7 +66,7 @@ class IOLocalContextStorage(_ioLocal: () => IOLocal[Context]) extends ContextSto * a [[cats.mtl.Local `Local`]] of a [[org.typelevel.otel4s.oteljava.context.Context `Context`]] that reflects the * state of the backing `IOLocal` */ - def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = implicitly + def local[F[_]: MonadCancelThrow: LiftIO]: LocalContext[F] = LocalProvider.localForIOLocal(ioLocal) } object IOLocalContextStorage {