Skip to content

Commit

Permalink
Merge branch 'main' into update/dd-trace-api-1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mpilquist authored Dec 17, 2022
2 parents c63af30 + b84d7c0 commit 65ec049
Show file tree
Hide file tree
Showing 22 changed files with 131 additions and 67 deletions.
23 changes: 10 additions & 13 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -100,7 +100,9 @@ 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",
"org.scala-lang.modules" %%% "scala-collection-compat" % collectionCompatVersion
)
)
.nativeSettings(commonNativeSettings)
Expand Down Expand Up @@ -142,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"
)
)

Expand All @@ -156,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"
)
)

Expand All @@ -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()
Expand Down Expand Up @@ -215,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"
)
)
Expand All @@ -229,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.2.0",
"com.datadoghq" % "dd-trace-api" % "1.2.0"
)
Expand Down Expand Up @@ -261,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"
Expand Down Expand Up @@ -347,11 +344,11 @@ 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.6",
"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
)
)

Expand Down Expand Up @@ -408,7 +405,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.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
Expand Down
15 changes: 14 additions & 1 deletion modules/core/shared/src/main/scala/Kernel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
9 changes: 6 additions & 3 deletions modules/core/shared/src/main/scala/Trace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Expand Down
8 changes: 4 additions & 4 deletions modules/core/shared/src/test/scala/InMemory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
6 changes: 4 additions & 2 deletions modules/core/shared/src/test/scala/SpanCoalesceTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
28 changes: 27 additions & 1 deletion modules/core/shared/src/test/scala/SpanPropagationTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -23,4 +26,27 @@ class SpanPropagationTest extends InMemorySuite {
)
}
)

traceTest(
"spanR",
new TraceTest {
def program[F[_]: MonadCancelThrow: Trace] =
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("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"))
)
}
)
}
3 changes: 1 addition & 2 deletions modules/datadog/src/main/scala/DDEntryPoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand All @@ -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()
}
Expand Down
4 changes: 2 additions & 2 deletions modules/datadog/src/main/scala/DDSpan.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion modules/docs/src/main/paradox/reference/entrypoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) *>
Expand Down
3 changes: 1 addition & 2 deletions modules/docs/src/main/paradox/reference/kernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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))
}
```
Expand Down
34 changes: 27 additions & 7 deletions modules/docs/src/main/scala/Junk.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
/*
* 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

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))
}

}
}
5 changes: 3 additions & 2 deletions modules/honeycomb/src/main/scala/HoneycombSpan.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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] =
Expand Down
3 changes: 1 addition & 2 deletions modules/jaeger/src/main/scala/JaegerEntryPoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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()
}
Expand Down
Loading

0 comments on commit 65ec049

Please sign in to comment.