From 012c595d14b4a9750c8cd37496b93f635b017100 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sun, 4 Dec 2022 23:01:02 +0000 Subject: [PATCH 01/12] Use case insensitive strings for `Kernel` headers --- build.sbt | 3 ++- modules/core/shared/src/main/scala/Kernel.scala | 15 ++++++++++++++- modules/datadog/src/main/scala/DDEntryPoint.scala | 3 +-- modules/datadog/src/main/scala/DDSpan.scala | 4 ++-- .../honeycomb/src/main/scala/HoneycombSpan.scala | 5 +++-- .../jaeger/src/main/scala/JaegerEntryPoint.scala | 3 +-- modules/jaeger/src/main/scala/JaegerSpan.scala | 4 ++-- .../src/main/scala/LightstepEntryPoint.scala | 4 +--- .../lightstep/src/main/scala/LightstepSpan.scala | 4 ++-- modules/log-odin/src/main/scala/LogSpan.scala | 5 +++-- modules/log/shared/src/main/scala/LogSpan.scala | 5 +++-- .../scala/natchez/newrelic/NewrelicSpan.scala | 5 +++-- .../src/main/scala/OpenCensusSpan.scala | 11 ++++++----- .../natchez/opentelemetry/OpenTelemetrySpan.scala | 14 ++++++++------ .../src/main/scala/natchez/xray/XRaySpan.scala | 3 ++- 15 files changed, 53 insertions(+), 35 deletions(-) diff --git a/build.sbt b/build.sbt index b26d9618..b8fdca15 100644 --- a/build.sbt +++ b/build.sbt @@ -100,7 +100,8 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform) "org.typelevel" %%% "cats-core" % catsVersion, "org.typelevel" %%% "cats-effect-kernel" % catsEffectVersion, "org.typelevel" %%% "cats-effect" % catsEffectVersion, - "co.fs2" %%% "fs2-io" % fs2Version + "co.fs2" %%% "fs2-io" % fs2Version, + "org.typelevel" %%% "case-insensitive" % "1.3.0" ) ) .nativeSettings(commonNativeSettings) diff --git a/modules/core/shared/src/main/scala/Kernel.scala b/modules/core/shared/src/main/scala/Kernel.scala index f69924f1..1e39c10f 100644 --- a/modules/core/shared/src/main/scala/Kernel.scala +++ b/modules/core/shared/src/main/scala/Kernel.scala @@ -4,8 +4,21 @@ package natchez +import org.typelevel.ci._ + +import java.util +import scala.jdk.CollectionConverters._ + /** An opaque hunk of data that we can hand off to another system (in the form of HTTP headers), * which can then create new spans as children of this one. By this mechanism we allow our trace * to span remote calls. */ -final case class Kernel(toHeaders: Map[String, String]) +final case class Kernel(toHeaders: Map[CIString, String]) { + private[natchez] def toJava: util.Map[String, String] = + toHeaders.map { case (k, v) => k.toString -> v }.asJava +} + +object Kernel { + private[natchez] def fromJava(headers: util.Map[String, String]): Kernel = + apply(headers.asScala.map { case (k, v) => CIString(k) -> v }.toMap) +} diff --git a/modules/datadog/src/main/scala/DDEntryPoint.scala b/modules/datadog/src/main/scala/DDEntryPoint.scala index 313bf651..d444feb4 100644 --- a/modules/datadog/src/main/scala/DDEntryPoint.scala +++ b/modules/datadog/src/main/scala/DDEntryPoint.scala @@ -11,7 +11,6 @@ import io.opentracing.propagation.{Format, TextMapAdapter} import io.{opentracing => ot} import java.net.URI -import scala.jdk.CollectionConverters._ final class DDEntryPoint[F[_]: Sync](tracer: ot.Tracer, uriPrefix: Option[URI]) extends EntryPoint[F] { @@ -26,7 +25,7 @@ final class DDEntryPoint[F[_]: Sync](tracer: ot.Tracer, uriPrefix: Option[URI]) Sync[F].delay { val spanContext = tracer.extract( Format.Builtin.HTTP_HEADERS, - new TextMapAdapter(kernel.toHeaders.asJava) + new TextMapAdapter(kernel.toJava) ) tracer.buildSpan(name).asChildOf(spanContext).start() } diff --git a/modules/datadog/src/main/scala/DDSpan.scala b/modules/datadog/src/main/scala/DDSpan.scala index 25075087..346b506e 100644 --- a/modules/datadog/src/main/scala/DDSpan.scala +++ b/modules/datadog/src/main/scala/DDSpan.scala @@ -35,7 +35,7 @@ final case class DDSpan[F[_]: Sync]( Format.Builtin.HTTP_HEADERS, new TextMapAdapter(m) ) - Kernel(m.asScala.toMap) + Kernel.fromJava(m) } def put(fields: (String, TraceValue)*): F[Unit] = @@ -55,7 +55,7 @@ final case class DDSpan[F[_]: Sync]( override def makeSpan(name: String, options: Span.Options): Resource[F, Span[F]] = { val parent = options.parentKernel.map(k => - tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(k.toHeaders.asJava)) + tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(k.toJava)) ) Span.putErrorFields( Resource diff --git a/modules/honeycomb/src/main/scala/HoneycombSpan.scala b/modules/honeycomb/src/main/scala/HoneycombSpan.scala index 401c6833..c83774af 100644 --- a/modules/honeycomb/src/main/scala/HoneycombSpan.scala +++ b/modules/honeycomb/src/main/scala/HoneycombSpan.scala @@ -14,6 +14,7 @@ import java.time.Instant import java.util.UUID import natchez._ import java.net.URI +import org.typelevel.ci._ private[honeycomb] final case class HoneycombSpan[F[_]: Sync]( client: HoneyClient, @@ -77,8 +78,8 @@ private[honeycomb] final case class HoneycombSpan[F[_]: Sync]( private[honeycomb] object HoneycombSpan { object Headers { - val TraceId = "X-Natchez-Trace-Id" - val SpanId = "X-Natchez-Parent-Span-Id" + val TraceId = ci"X-Natchez-Trace-Id" + val SpanId = ci"X-Natchez-Parent-Span-Id" } private def uuid[F[_]: Sync]: F[UUID] = diff --git a/modules/jaeger/src/main/scala/JaegerEntryPoint.scala b/modules/jaeger/src/main/scala/JaegerEntryPoint.scala index faaceaee..301c3c0b 100644 --- a/modules/jaeger/src/main/scala/JaegerEntryPoint.scala +++ b/modules/jaeger/src/main/scala/JaegerEntryPoint.scala @@ -11,7 +11,6 @@ import io.jaegertracing.internal.exceptions.UnsupportedFormatException import io.opentracing.propagation.{Format, TextMapAdapter} import io.{opentracing => ot} -import scala.jdk.CollectionConverters._ import java.net.URI final class JaegerEntryPoint[F[_]: Sync](tracer: ot.Tracer, uriPrefix: Option[URI]) @@ -22,7 +21,7 @@ final class JaegerEntryPoint[F[_]: Sync](tracer: ot.Tracer, uriPrefix: Option[UR Sync[F].delay { val p = tracer.extract( Format.Builtin.HTTP_HEADERS, - new TextMapAdapter(kernel.toHeaders.asJava) + new TextMapAdapter(kernel.toJava) ) tracer.buildSpan(name).asChildOf(p).start() } diff --git a/modules/jaeger/src/main/scala/JaegerSpan.scala b/modules/jaeger/src/main/scala/JaegerSpan.scala index a1a5800c..d7c2900e 100644 --- a/modules/jaeger/src/main/scala/JaegerSpan.scala +++ b/modules/jaeger/src/main/scala/JaegerSpan.scala @@ -35,7 +35,7 @@ private[jaeger] final case class JaegerSpan[F[_]: Sync]( Format.Builtin.HTTP_HEADERS, new TextMapAdapter(m) ) - Kernel(m.asScala.toMap) + Kernel.fromJava(m) } override def put(fields: (String, TraceValue)*): F[Unit] = @@ -75,7 +75,7 @@ private[jaeger] final case class JaegerSpan[F[_]: Sync]( val p = options.parentKernel.map(k => tracer.extract( Format.Builtin.HTTP_HEADERS, - new TextMapAdapter(k.toHeaders.asJava) + new TextMapAdapter(k.toJava) ) ) Sync[F] diff --git a/modules/lightstep/src/main/scala/LightstepEntryPoint.scala b/modules/lightstep/src/main/scala/LightstepEntryPoint.scala index a3c08af9..51bd2dc4 100644 --- a/modules/lightstep/src/main/scala/LightstepEntryPoint.scala +++ b/modules/lightstep/src/main/scala/LightstepEntryPoint.scala @@ -10,8 +10,6 @@ import cats.syntax.all._ import io.opentracing.Tracer import io.opentracing.propagation.{Format, TextMapAdapter} -import scala.jdk.CollectionConverters._ - final class LightstepEntryPoint[F[_]: Sync](tracer: Tracer) extends EntryPoint[F] { override def root(name: String): Resource[F, Span[F]] = Resource @@ -23,7 +21,7 @@ final class LightstepEntryPoint[F[_]: Sync](tracer: Tracer) extends EntryPoint[F .make( Sync[F].delay { val p = - tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(kernel.toHeaders.asJava)) + tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(kernel.toJava)) tracer.buildSpan(name).asChildOf(p).start() } )(s => Sync[F].delay(s.finish())) diff --git a/modules/lightstep/src/main/scala/LightstepSpan.scala b/modules/lightstep/src/main/scala/LightstepSpan.scala index a21dc590..ddcf03b0 100644 --- a/modules/lightstep/src/main/scala/LightstepSpan.scala +++ b/modules/lightstep/src/main/scala/LightstepSpan.scala @@ -27,7 +27,7 @@ private[lightstep] final case class LightstepSpan[F[_]: Sync]( Sync[F].delay { val m = new java.util.HashMap[String, String] tracer.inject(span.context, Format.Builtin.HTTP_HEADERS, new TextMapAdapter(m)) - Kernel(m.asScala.toMap) + Kernel.fromJava(m) } override def put(fields: (String, TraceValue)*): F[Unit] = @@ -63,7 +63,7 @@ private[lightstep] final case class LightstepSpan[F[_]: Sync]( override def makeSpan(name: String, options: Span.Options): Resource[F, Span[F]] = { val p = options.parentKernel.map(k => - tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(k.toHeaders.asJava)) + tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(k.toJava)) ) Span.putErrorFields( Resource diff --git a/modules/log-odin/src/main/scala/LogSpan.scala b/modules/log-odin/src/main/scala/LogSpan.scala index 935ce353..20f6e5f9 100644 --- a/modules/log-odin/src/main/scala/LogSpan.scala +++ b/modules/log-odin/src/main/scala/LogSpan.scala @@ -19,6 +19,7 @@ import io.circe.syntax._ import io.circe.JsonObject import io.odin.Logger import java.net.URI +import org.typelevel.ci._ private[logodin] final case class LogSpan[F[_]: Sync: Logger]( service: String, @@ -130,8 +131,8 @@ private[logodin] object LogSpan { } object Headers { - val TraceId = "X-Natchez-Trace-Id" - val SpanId = "X-Natchez-Parent-Span-Id" + val TraceId = ci"X-Natchez-Trace-Id" + val SpanId = ci"X-Natchez-Parent-Span-Id" } private def uuid[F[_]: Sync]: F[UUID] = diff --git a/modules/log/shared/src/main/scala/LogSpan.scala b/modules/log/shared/src/main/scala/LogSpan.scala index 4841ff76..b14e3411 100644 --- a/modules/log/shared/src/main/scala/LogSpan.scala +++ b/modules/log/shared/src/main/scala/LogSpan.scala @@ -20,6 +20,7 @@ import io.circe.Encoder import io.circe.syntax._ import io.circe.JsonObject import org.typelevel.log4cats.Logger +import org.typelevel.ci._ import java.net.URI @@ -125,8 +126,8 @@ private[log] object LogSpan { } object Headers { - val TraceId = "X-Natchez-Trace-Id" - val SpanId = "X-Natchez-Parent-Span-Id" + val TraceId = ci"X-Natchez-Trace-Id" + val SpanId = ci"X-Natchez-Parent-Span-Id" } private def uuid[F[_]: Sync]: F[UUID] = diff --git a/modules/newrelic/src/main/scala/natchez/newrelic/NewrelicSpan.scala b/modules/newrelic/src/main/scala/natchez/newrelic/NewrelicSpan.scala index 922b9494..eae9c08c 100644 --- a/modules/newrelic/src/main/scala/natchez/newrelic/NewrelicSpan.scala +++ b/modules/newrelic/src/main/scala/natchez/newrelic/NewrelicSpan.scala @@ -15,6 +15,7 @@ import com.newrelic.telemetry.spans.{Span, SpanBatch, SpanBatchSender} import natchez.TraceValue.{BooleanValue, NumberValue, StringValue} import natchez.newrelic.NewrelicSpan.Headers import natchez.{Kernel, TraceValue} +import org.typelevel.ci._ import scala.jdk.CollectionConverters._ @@ -70,8 +71,8 @@ private[newrelic] final case class NewrelicSpan[F[_]: Sync]( object NewrelicSpan { object Headers { - val TraceId = "X-Natchez-Trace-Id" - val SpanId = "X-Natchez-Parent-Span-Id" + val TraceId = ci"X-Natchez-Trace-Id" + val SpanId = ci"X-Natchez-Parent-Span-Id" } def fromKernel[F[_]: Sync]( diff --git a/modules/opencensus/src/main/scala/OpenCensusSpan.scala b/modules/opencensus/src/main/scala/OpenCensusSpan.scala index a4e28bed..381b0935 100644 --- a/modules/opencensus/src/main/scala/OpenCensusSpan.scala +++ b/modules/opencensus/src/main/scala/OpenCensusSpan.scala @@ -14,6 +14,7 @@ import io.opencensus.trace.{AttributeValue, Sampler, Tracer, Tracing} import io.opencensus.trace.propagation.SpanContextParseException import io.opencensus.trace.propagation.TextFormat.Getter import natchez.TraceValue.{BooleanValue, NumberValue, StringValue} +import org.typelevel.ci._ import scala.collection.mutable import java.net.URI @@ -51,7 +52,7 @@ private[opencensus] final case class OpenCensusSpan[F[_]: Sync]( Sync[F].delay(span.addAnnotation(event)).void override def kernel: F[Kernel] = Sync[F].delay { - val headers: mutable.Map[String, String] = mutable.Map.empty[String, String] + val headers: mutable.Map[CIString, String] = mutable.Map.empty[CIString, String] Tracing.getPropagationComponent.getB3Format .inject(span.getContext, headers, spanContextSetter) Kernel(headers.toMap) @@ -89,9 +90,9 @@ private[opencensus] final case class OpenCensusSpan[F[_]: Sync]( } private[opencensus] object OpenCensusSpan { - private val spanContextSetter = new Setter[mutable.Map[String, String]] { - override def put(carrier: mutable.Map[String, String], key: String, value: String): Unit = { - carrier.put(key, value) + private val spanContextSetter = new Setter[mutable.Map[CIString, String]] { + override def put(carrier: mutable.Map[CIString, String], key: String, value: String): Unit = { + carrier.put(CIString(key), value) () } } @@ -188,5 +189,5 @@ private[opencensus] object OpenCensusSpan { } private val spanContextGetter: Getter[Kernel] = (carrier: Kernel, key: String) => - carrier.toHeaders(key) + carrier.toHeaders(CIString(key)) } diff --git a/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala b/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala index fc3ecffd..ec2ac620 100644 --- a/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala +++ b/modules/opentelemetry/src/main/scala/natchez/opentelemetry/OpenTelemetrySpan.scala @@ -22,6 +22,7 @@ import TraceValue.{BooleanValue, NumberValue, StringValue} import java.net.URI import scala.collection.mutable import io.opentelemetry.api.common.Attributes +import org.typelevel.ci._ private[opentelemetry] final case class OpenTelemetrySpan[F[_]: Sync]( otel: OTel, @@ -64,7 +65,7 @@ private[opentelemetry] final case class OpenTelemetrySpan[F[_]: Sync]( override def kernel: F[Kernel] = Sync[F].delay { - val headers: mutable.Map[String, String] = mutable.Map.empty[String, String] + val headers: mutable.Map[CIString, String] = mutable.Map.empty[CIString, String] otel.getPropagators.getTextMapPropagator.inject( Context.current().`with`(span), headers, @@ -215,15 +216,16 @@ private[opentelemetry] object OpenTelemetrySpan { import scala.jdk.CollectionConverters._ - override def keys(carrier: Kernel): lang.Iterable[String] = carrier.toHeaders.keys.asJava + override def keys(carrier: Kernel): lang.Iterable[String] = + carrier.toHeaders.keys.map(_.toString).asJava override def get(carrier: Kernel, key: String): String = - carrier.toHeaders.getOrElse(key, null) + carrier.toHeaders.getOrElse(CIString(key), null) } - private val spanContextSetter = new TextMapSetter[mutable.Map[String, String]] { - override def set(carrier: mutable.Map[String, String], key: String, value: String): Unit = { - carrier.put(key, value) + private val spanContextSetter = new TextMapSetter[mutable.Map[CIString, String]] { + override def set(carrier: mutable.Map[CIString, String], key: String, value: String): Unit = { + carrier.put(CIString(key), value) () } } diff --git a/modules/xray/src/main/scala/natchez/xray/XRaySpan.scala b/modules/xray/src/main/scala/natchez/xray/XRaySpan.scala index 665b71e1..8f5a3f77 100644 --- a/modules/xray/src/main/scala/natchez/xray/XRaySpan.scala +++ b/modules/xray/src/main/scala/natchez/xray/XRaySpan.scala @@ -21,6 +21,7 @@ import io.circe.syntax._ import cats.effect.kernel.Resource.ExitCase.Canceled import cats.effect.kernel.Resource.ExitCase.Errored import cats.effect.kernel.Resource.ExitCase.Succeeded +import org.typelevel.ci._ import scala.concurrent.duration._ import scala.util.matching.Regex @@ -154,7 +155,7 @@ private[xray] object XRaySpan { case NumberValue(n) => n.doubleValue.asJson } - val Header = "X-Amzn-Trace-Id" + val Header = ci"X-Amzn-Trace-Id" private[xray] def encodeHeader( rootId: String, From 5276d60274dfcb7202395085e95d977cdffbd5d7 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sun, 4 Dec 2022 23:08:56 +0000 Subject: [PATCH 02/12] Move collection compat to core --- build.sbt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index b8fdca15..9a39efaa 100644 --- a/build.sbt +++ b/build.sbt @@ -101,7 +101,8 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform) "org.typelevel" %%% "cats-effect-kernel" % catsEffectVersion, "org.typelevel" %%% "cats-effect" % catsEffectVersion, "co.fs2" %%% "fs2-io" % fs2Version, - "org.typelevel" %%% "case-insensitive" % "1.3.0" + "org.typelevel" %%% "case-insensitive" % "1.3.0", + "org.scala-lang.modules" %%% "scala-collection-compat" % collectionCompatVersion ) ) .nativeSettings(commonNativeSettings) @@ -143,8 +144,7 @@ lazy val opencensus = project name := "natchez-opencensus", description := "Opencensus support for Natchez.", libraryDependencies ++= Seq( - "io.opencensus" % "opencensus-exporter-trace-ocagent" % "0.31.1", - "org.scala-lang.modules" %% "scala-collection-compat" % collectionCompatVersion + "io.opencensus" % "opencensus-exporter-trace-ocagent" % "0.31.1" ) ) @@ -157,8 +157,7 @@ lazy val lightstep = project name := "natchez-lightstep", description := "Lightstep support for Natchez.", libraryDependencies ++= Seq( - "com.lightstep.tracer" % "lightstep-tracer-jre" % "0.30.5", - "org.scala-lang.modules" %% "scala-collection-compat" % collectionCompatVersion + "com.lightstep.tracer" % "lightstep-tracer-jre" % "0.30.5" ) ) @@ -216,7 +215,6 @@ lazy val opentelemetry = project description := "Base OpenTelemetry Utilities for Natchez", tlVersionIntroduced := List("2.12", "2.13", "3").map(_ -> "0.1.7").toMap, libraryDependencies ++= Seq( - "org.scala-lang.modules" %% "scala-collection-compat" % collectionCompatVersion, "io.opentelemetry" % "opentelemetry-sdk" % "1.20.1" ) ) @@ -230,7 +228,6 @@ lazy val datadog = project name := "natchez-datadog", description := "Datadog bindings for Natchez.", libraryDependencies ++= Seq( - "org.scala-lang.modules" %% "scala-collection-compat" % collectionCompatVersion, "com.datadoghq" % "dd-trace-ot" % "1.0.1", "com.datadoghq" % "dd-trace-api" % "1.0.1" ) @@ -262,7 +259,6 @@ lazy val newrelic = project description := "Newrelic bindings for Natchez.", libraryDependencies ++= Seq( "io.circe" %% "circe-core" % "0.14.3", - "org.scala-lang.modules" %% "scala-collection-compat" % collectionCompatVersion, "com.newrelic.telemetry" % "telemetry" % "0.10.0", "com.newrelic.telemetry" % "telemetry-core" % "0.15.0", "com.newrelic.telemetry" % "telemetry-http-okhttp" % "0.15.0" From 6739420da76d03e317a76d57172a7d7df56fba9c Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sun, 4 Dec 2022 23:11:55 +0000 Subject: [PATCH 03/12] Fix docs --- modules/docs/src/main/scala/Junk.scala | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/docs/src/main/scala/Junk.scala b/modules/docs/src/main/scala/Junk.scala index 885589df..aeabee26 100644 --- a/modules/docs/src/main/scala/Junk.scala +++ b/modules/docs/src/main/scala/Junk.scala @@ -3,22 +3,21 @@ // For more information see LICENSE or https://opensource.org/licenses/MIT import cats.effect.IO -import natchez.{ Span } -import org.http4s.{ EntityDecoder, Uri, Header } +import natchez.Span +import org.http4s.{EntityDecoder, Uri, Header} import org.http4s.Method.GET import org.http4s.client.Client import org.http4s.client.dsl.io._ -import org.typelevel.ci.CIString object X { - def makeRequest[A](span: Span[IO], client: Client[IO], uri: Uri)( - implicit ev: EntityDecoder[IO, A] + def makeRequest[A](span: Span[IO], client: Client[IO], uri: Uri)(implicit + ev: EntityDecoder[IO, A] ): IO[A] = span.kernel.flatMap { k => // turn a Map[String, String] into List[Header] - val http4sHeaders = k.toHeaders.map { case (k, v) => Header.Raw(CIString(k), v) } .toSeq + val http4sHeaders = k.toHeaders.map { case (k, v) => Header.Raw(k, v) }.toSeq client.expect[A](GET(uri).withHeaders(http4sHeaders)) } -} \ No newline at end of file +} From 57124221459160d05535a613253f19c24c4c4d1e Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sun, 4 Dec 2022 23:19:39 +0000 Subject: [PATCH 04/12] Fix mdocs --- .../src/main/paradox/reference/entrypoints.md | 2 +- .../src/main/paradox/reference/kernels.md | 3 +-- modules/docs/src/main/scala/Junk.scala | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/modules/docs/src/main/paradox/reference/entrypoints.md b/modules/docs/src/main/paradox/reference/entrypoints.md index 4ec90bc3..eae5ec70 100644 --- a/modules/docs/src/main/paradox/reference/entrypoints.md +++ b/modules/docs/src/main/paradox/reference/entrypoints.md @@ -45,7 +45,7 @@ def continuedRoutes(ep: EntryPoint[IO]): HttpRoutes[IO] = case req@(GET -> Root / "hello" / name) => val k: Kernel = - Kernel(req.headers.headers.map { h => h.name.toString -> h.value }.toMap) + Kernel(req.headers.headers.map { h => h.name -> h.value }.toMap) ep.continueOrElseRoot("hello", k).use { span => span.put("the-name" -> name) *> diff --git a/modules/docs/src/main/paradox/reference/kernels.md b/modules/docs/src/main/paradox/reference/kernels.md index 3199a250..6ccbff06 100644 --- a/modules/docs/src/main/paradox/reference/kernels.md +++ b/modules/docs/src/main/paradox/reference/kernels.md @@ -16,7 +16,6 @@ import org.http4s.{ EntityDecoder, Uri, Header } import org.http4s.Method.GET import org.http4s.client.Client import org.http4s.client.dsl.io._ -import org.typelevel.ci.CIString ``` We can add a `Span`'s kernel to an outgoing `Client` request. If the remote server supports tracing via the same back end, it can extend the trace with child spans. @@ -27,7 +26,7 @@ def makeRequest[A](span: Span[IO], client: Client[IO], uri: Uri)( ): IO[A] = span.kernel.flatMap { k => // turn a Map[String, String] into List[Header] - val http4sHeaders = k.toHeaders.map { case (k, v) => Header.Raw(CIString(k), v) } .toSeq + val http4sHeaders = k.toHeaders.map { case (k, v) => Header.Raw(k, v) } .toSeq client.expect[A](GET(uri).withHeaders(http4sHeaders)) } ``` diff --git a/modules/docs/src/main/scala/Junk.scala b/modules/docs/src/main/scala/Junk.scala index aeabee26..9ce8cebf 100644 --- a/modules/docs/src/main/scala/Junk.scala +++ b/modules/docs/src/main/scala/Junk.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2022 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + // Copyright (c) 2019-2020 by Rob Norris and Contributors // This software is licensed under the MIT License (MIT). // For more information see LICENSE or https://opensource.org/licenses/MIT From e311494afaf1c606d4b747a71221a55b7450194e Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Thu, 8 Dec 2022 23:36:09 +0000 Subject: [PATCH 05/12] Update slf4j-simple to 2.0.5 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index b26d9618..3e8eb9bd 100644 --- a/build.sbt +++ b/build.sbt @@ -347,7 +347,7 @@ lazy val examples = project scalacOptions -= "-Xfatal-warnings", libraryDependencies ++= Seq( "org.typelevel" %% "log4cats-slf4j" % "2.5.0", - "org.slf4j" % "slf4j-simple" % "2.0.4", + "org.slf4j" % "slf4j-simple" % "2.0.5", "eu.timepit" %% "refined" % "0.10.1", "is.cir" %% "ciris" % "3.0.0", "io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.20.1", @@ -408,7 +408,7 @@ lazy val docs = project "org.http4s" %% "http4s-dsl" % "0.23.15", "org.http4s" %% "http4s-client" % "0.23.15", "org.typelevel" %% "log4cats-slf4j" % "2.4.0", - "org.slf4j" % "slf4j-simple" % "2.0.4", + "org.slf4j" % "slf4j-simple" % "2.0.5", "io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.20.1" // for the opentelemetry example ), excludeDependencies += "org.scala-lang.modules" % "scala-collection-compat_3" // pray this does more good than harm From c3c7df47856b3dbd27dab0a29f171745021ad45d Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Thu, 8 Dec 2022 23:36:20 +0000 Subject: [PATCH 06/12] Update cats-effect, cats-effect-kernel to 3.4.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index b26d9618..af924ee1 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,7 @@ val scala30Version = "3.2.1" val collectionCompatVersion = "2.8.1" val catsVersion = "2.9.0" -val catsEffectVersion = "3.4.1" +val catsEffectVersion = "3.4.2" val fs2Version = "3.4.0" // Publishing From e2e4ba8a86fda1ee46dc820e0c6690affc35d653 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 14 Dec 2022 12:11:17 +0000 Subject: [PATCH 07/12] Fix `spanR` for `IOLocal`-based `Trace` --- modules/core/shared/src/main/scala/Trace.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/core/shared/src/main/scala/Trace.scala b/modules/core/shared/src/main/scala/Trace.scala index 96b347e5..ed5488d2 100644 --- a/modules/core/shared/src/main/scala/Trace.scala +++ b/modules/core/shared/src/main/scala/Trace.scala @@ -79,9 +79,12 @@ object Trace { child <- parent.span(name, options) } yield new (IO ~> IO) { def apply[A](fa: IO[A]): IO[A] = - local - .set(child) - .bracket(_ => fa.onError(child.attachError(_)))(_ => local.set(parent)) + local.get.flatMap { old => + local + .set(child) + .bracket(_ => fa.onError(child.attachError(_)))(_ => local.set(old)) + } + } override def span[A](name: String, options: Span.Options)(k: IO[A]): IO[A] = From a7ffa4ee433db13f9c90469ca144ddf3b4a1da77 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 14 Dec 2022 14:04:00 +0000 Subject: [PATCH 08/12] Add test for `spanR` --- .../core/shared/src/test/scala/InMemory.scala | 8 +++--- .../src/test/scala/SpanCoalesceTest.scala | 6 +++-- .../src/test/scala/SpanPropagationTest.scala | 25 ++++++++++++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/modules/core/shared/src/test/scala/InMemory.scala b/modules/core/shared/src/test/scala/InMemory.scala index eecc8a13..a2f600a1 100644 --- a/modules/core/shared/src/test/scala/InMemory.scala +++ b/modules/core/shared/src/test/scala/InMemory.scala @@ -7,7 +7,7 @@ package natchez import java.net.URI import cats.data.{Chain, Kleisli} -import cats.effect.{IO, Ref, Resource} +import cats.effect.{IO, MonadCancelThrow, Ref, Resource} import natchez.Span.Options import munit.CatsEffectSuite @@ -118,15 +118,15 @@ trait InMemorySuite extends CatsEffectSuite { val NatchezCommand = InMemory.NatchezCommand trait TraceTest { - def program[F[_]: Trace]: F[Unit] + def program[F[_]: MonadCancelThrow: Trace]: F[Unit] def expectedHistory: List[(Lineage, NatchezCommand)] } def traceTest(name: String, tt: TraceTest) = { test(s"$name - Kleisli")( - testTraceKleisli(tt.program[Kleisli[IO, Span[IO], *]](_), tt.expectedHistory) + testTraceKleisli(tt.program[Kleisli[IO, Span[IO], *]](implicitly, _), tt.expectedHistory) ) - test(s"$name - IOLocal")(testTraceIoLocal(tt.program[IO](_), tt.expectedHistory)) + test(s"$name - IOLocal")(testTraceIoLocal(tt.program[IO](implicitly, _), tt.expectedHistory)) } def testTraceKleisli( diff --git a/modules/core/shared/src/test/scala/SpanCoalesceTest.scala b/modules/core/shared/src/test/scala/SpanCoalesceTest.scala index a4c693e9..ac44a0f0 100644 --- a/modules/core/shared/src/test/scala/SpanCoalesceTest.scala +++ b/modules/core/shared/src/test/scala/SpanCoalesceTest.scala @@ -4,12 +4,14 @@ package natchez +import cats.effect.MonadCancelThrow + class SpanCoalesceTest extends InMemorySuite { traceTest( "suppress - nominal", new TraceTest { - def program[F[_]: Trace] = { + def program[F[_]: MonadCancelThrow: Trace] = { def detailed = Trace[F].span("parent")(Trace[F].span("child")(Trace[F].put("answer" -> 42))) Trace[F].span("suppressed", Span.Options.Suppress)(detailed) @@ -27,7 +29,7 @@ class SpanCoalesceTest extends InMemorySuite { traceTest( "coaslesce - nominal", new TraceTest { - def program[F[_]: Trace] = { + def program[F[_]: MonadCancelThrow: Trace] = { def detailed = Trace[F].span("parent")(Trace[F].span("child")(Trace[F].put("answer" -> 42))) Trace[F].span("coalesced", Span.Options.Coalesce)(detailed) diff --git a/modules/core/shared/src/test/scala/SpanPropagationTest.scala b/modules/core/shared/src/test/scala/SpanPropagationTest.scala index 13893e74..0ae0c56d 100644 --- a/modules/core/shared/src/test/scala/SpanPropagationTest.scala +++ b/modules/core/shared/src/test/scala/SpanPropagationTest.scala @@ -4,12 +4,15 @@ package natchez +import cats.effect.MonadCancelThrow +import cats.syntax.all._ + class SpanPropagationTest extends InMemorySuite { traceTest( "propagation", new TraceTest { - def program[F[_]: Trace] = + def program[F[_]: MonadCancelThrow: Trace] = Trace[F].span("parent")(Trace[F].span("child")(Trace[F].put("answer" -> 42))) def expectedHistory = List( @@ -23,4 +26,24 @@ class SpanPropagationTest extends InMemorySuite { ) } ) + + traceTest( + "spanR", + new TraceTest { + def program[F[_]: MonadCancelThrow: Trace] = + Trace[F].spanR("parent").use { f => + Trace[F].span("child")(f(MonadCancelThrow[F].unit) *> Trace[F].put("answer" -> 42)) + } + + def expectedHistory = List( + (Lineage.Root, NatchezCommand.CreateRootSpan("root", Kernel(Map()))), + (Lineage.Root, NatchezCommand.CreateSpan("parent", None)), + (Lineage.Root, NatchezCommand.CreateSpan("child", None)), + (Lineage.Root / "child", NatchezCommand.Put(List("answer" -> 42))), + (Lineage.Root, NatchezCommand.ReleaseSpan("child")), + (Lineage.Root, NatchezCommand.ReleaseSpan("parent")), + (Lineage.Root, NatchezCommand.ReleaseRootSpan("root")) + ) + } + ) } From 2ed398fc9a82abf4682219a50f2d743d1c46fec0 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 14 Dec 2022 14:10:38 +0000 Subject: [PATCH 09/12] Make the test more interesting --- modules/core/shared/src/test/scala/SpanPropagationTest.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/core/shared/src/test/scala/SpanPropagationTest.scala b/modules/core/shared/src/test/scala/SpanPropagationTest.scala index 0ae0c56d..f7fd6dc2 100644 --- a/modules/core/shared/src/test/scala/SpanPropagationTest.scala +++ b/modules/core/shared/src/test/scala/SpanPropagationTest.scala @@ -32,13 +32,16 @@ class SpanPropagationTest extends InMemorySuite { new TraceTest { def program[F[_]: MonadCancelThrow: Trace] = Trace[F].spanR("parent").use { f => - Trace[F].span("child")(f(MonadCancelThrow[F].unit) *> Trace[F].put("answer" -> 42)) + Trace[F].span("child")( + f(Trace[F].put("question" -> "ultimate")) *> Trace[F].put("answer" -> 42) + ) } def expectedHistory = List( (Lineage.Root, NatchezCommand.CreateRootSpan("root", Kernel(Map()))), (Lineage.Root, NatchezCommand.CreateSpan("parent", None)), (Lineage.Root, NatchezCommand.CreateSpan("child", None)), + (Lineage.Root / "parent", NatchezCommand.Put(List("question" -> "ultimate"))), (Lineage.Root / "child", NatchezCommand.Put(List("answer" -> 42))), (Lineage.Root, NatchezCommand.ReleaseSpan("child")), (Lineage.Root, NatchezCommand.ReleaseSpan("parent")), From 0192f436e179e735436583887774fdce6d770722 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Wed, 14 Dec 2022 14:35:19 +0000 Subject: [PATCH 10/12] Clarify span names --- .../src/test/scala/SpanPropagationTest.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/core/shared/src/test/scala/SpanPropagationTest.scala b/modules/core/shared/src/test/scala/SpanPropagationTest.scala index f7fd6dc2..9d698121 100644 --- a/modules/core/shared/src/test/scala/SpanPropagationTest.scala +++ b/modules/core/shared/src/test/scala/SpanPropagationTest.scala @@ -31,20 +31,20 @@ class SpanPropagationTest extends InMemorySuite { "spanR", new TraceTest { def program[F[_]: MonadCancelThrow: Trace] = - Trace[F].spanR("parent").use { f => - Trace[F].span("child")( + Trace[F].spanR("spanR").use { f => + Trace[F].span("span")( f(Trace[F].put("question" -> "ultimate")) *> Trace[F].put("answer" -> 42) ) } def expectedHistory = List( (Lineage.Root, NatchezCommand.CreateRootSpan("root", Kernel(Map()))), - (Lineage.Root, NatchezCommand.CreateSpan("parent", None)), - (Lineage.Root, NatchezCommand.CreateSpan("child", None)), - (Lineage.Root / "parent", NatchezCommand.Put(List("question" -> "ultimate"))), - (Lineage.Root / "child", NatchezCommand.Put(List("answer" -> 42))), - (Lineage.Root, NatchezCommand.ReleaseSpan("child")), - (Lineage.Root, NatchezCommand.ReleaseSpan("parent")), + (Lineage.Root, NatchezCommand.CreateSpan("spanR", None)), + (Lineage.Root, NatchezCommand.CreateSpan("span", None)), + (Lineage.Root / "spanR", NatchezCommand.Put(List("question" -> "ultimate"))), + (Lineage.Root / "span", NatchezCommand.Put(List("answer" -> 42))), + (Lineage.Root, NatchezCommand.ReleaseSpan("span")), + (Lineage.Root, NatchezCommand.ReleaseSpan("spanR")), (Lineage.Root, NatchezCommand.ReleaseRootSpan("root")) ) } From 792ac7e9f28f98db28263b9ccfa25e99259cca37 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Wed, 14 Dec 2022 19:57:18 +0000 Subject: [PATCH 11/12] Update grpc-netty, grpc-okhttp to 1.51.1 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index bd1ffd8b..599a70a7 100644 --- a/build.sbt +++ b/build.sbt @@ -171,7 +171,7 @@ lazy val lightstepGrpc = project description := "Lightstep gRPC bindings for Natchez.", libraryDependencies ++= Seq( "com.lightstep.tracer" % "tracer-grpc" % "0.30.3", - "io.grpc" % "grpc-netty" % "1.51.0", + "io.grpc" % "grpc-netty" % "1.51.1", "io.netty" % "netty-tcnative-boringssl-static" % "2.0.54.Final" ), mimaPreviousArtifacts := Set() @@ -351,7 +351,7 @@ lazy val examples = project "eu.timepit" %% "refined" % "0.10.1", "is.cir" %% "ciris" % "3.0.0", "io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.20.1", - "io.grpc" % "grpc-okhttp" % "1.51.0" // required for the OpenTelemetry exporter + "io.grpc" % "grpc-okhttp" % "1.51.1" // required for the OpenTelemetry exporter ) ) From 209be32160e9be92ded9c521b161a3aeca7d3719 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Wed, 14 Dec 2022 19:57:31 +0000 Subject: [PATCH 12/12] Update slf4j-simple to 2.0.6 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index bd1ffd8b..fb52d410 100644 --- a/build.sbt +++ b/build.sbt @@ -347,7 +347,7 @@ lazy val examples = project scalacOptions -= "-Xfatal-warnings", libraryDependencies ++= Seq( "org.typelevel" %% "log4cats-slf4j" % "2.5.0", - "org.slf4j" % "slf4j-simple" % "2.0.5", + "org.slf4j" % "slf4j-simple" % "2.0.6", "eu.timepit" %% "refined" % "0.10.1", "is.cir" %% "ciris" % "3.0.0", "io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.20.1", @@ -408,7 +408,7 @@ lazy val docs = project "org.http4s" %% "http4s-dsl" % "0.23.15", "org.http4s" %% "http4s-client" % "0.23.15", "org.typelevel" %% "log4cats-slf4j" % "2.4.0", - "org.slf4j" % "slf4j-simple" % "2.0.5", + "org.slf4j" % "slf4j-simple" % "2.0.6", "io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.20.1" // for the opentelemetry example ), excludeDependencies += "org.scala-lang.modules" % "scala-collection-compat_3" // pray this does more good than harm