diff --git a/build.sbt b/build.sbt index 9bea91a..f03cfb8 100644 --- a/build.sbt +++ b/build.sbt @@ -63,13 +63,13 @@ lazy val metricsCommon = projectMatrix .settings(common :+ (name := "natchez-extras-metrics")) val log4catsVersion = "2.6.0" -val natchezVersion = "0.3.3" +val natchezVersion = "0.3.4" val http4sMilestoneVersion = "1.0.0-M40" val http4sStableVersion = "0.23.23" val circeVersion = "0.14.3" val slf4jVersion = "1.7.36" val fs2Version = "3.9.1" -val doobieVersion = "1.0.0-RC4" +val doobieVersion = "1.0.0-RC5" val doobieLegacyVersion = "1.0.0-RC2" lazy val natchezDatadog = projectMatrix diff --git a/natchez-extras-datadog/src/main/scala/com/ovoenergy/natchez/extras/datadog/Datadog.scala b/natchez-extras-datadog/src/main/scala/com/ovoenergy/natchez/extras/datadog/Datadog.scala index 761d400..e59c947 100644 --- a/natchez-extras-datadog/src/main/scala/com/ovoenergy/natchez/extras/datadog/Datadog.scala +++ b/natchez-extras-datadog/src/main/scala/com/ovoenergy/natchez/extras/datadog/Datadog.scala @@ -9,7 +9,7 @@ import cats.syntax.functor._ import com.ovoenergy.natchez.extras.datadog.DatadogSpan.SpanNames import fs2.Stream import io.circe.{Encoder, Printer} -import natchez.{EntryPoint, Kernel, Span} +import natchez.{EntryPoint, Kernel, Span, TraceValue} import org.http4s.Method.PUT import org.http4s.Uri.Path.unsafeFromString import org.http4s.circe.CirceInstances.builder @@ -119,7 +119,8 @@ object Datadog { client: Client[F], service: String, resource: String, - agentHost: Uri = uri"http://localhost:8126" + agentHost: Uri = uri"http://localhost:8126", + meta: Map[String, TraceValue] = Map.empty ): Resource[F, EntryPoint[F]] = for { queue <- spanQueue @@ -130,7 +131,7 @@ object Datadog { def root(name: String, options: Span.Options): Resource[F, Span[F]] = Resource .eval(SpanIdentifiers.create.flatMap(Ref.of[F, SpanIdentifiers])) - .flatMap(DatadogSpan.create(queue, names(name))) + .flatMap(DatadogSpan.create(queue, names(name), meta)) .widen def continue(name: String, kernel: Kernel, options: Span.Options): Resource[F, Span[F]] = diff --git a/natchez-extras-datadog/src/test/scala/com/ovoenergy/natchez/extras/datadog/DatadogTest.scala b/natchez-extras-datadog/src/test/scala/com/ovoenergy/natchez/extras/datadog/DatadogTest.scala index a70e5d4..a9b7c78 100644 --- a/natchez-extras-datadog/src/test/scala/com/ovoenergy/natchez/extras/datadog/DatadogTest.scala +++ b/natchez-extras-datadog/src/test/scala/com/ovoenergy/natchez/extras/datadog/DatadogTest.scala @@ -7,7 +7,7 @@ import com.ovoenergy.natchez.extras.datadog.Datadog.entryPoint import com.ovoenergy.natchez.extras.datadog.DatadogTags.SpanType.{Cache, Db, Web} import com.ovoenergy.natchez.extras.datadog.DatadogTags.spanType import munit.CatsEffectSuite -import natchez.EntryPoint +import natchez.{EntryPoint, TraceValue} import org.http4s.Request import org.http4s.circe.CirceEntityDecoder._ import org.http4s.syntax.literals._ @@ -21,8 +21,8 @@ import scala.concurrent.duration._ */ class DatadogTest extends CatsEffectSuite { - def run(f: EntryPoint[IO] => IO[Unit]): IO[List[Request[IO]]] = - TestClient[IO].flatMap(c => entryPoint(c.client, "test", "blah").use(f) >> c.requests) + def run(f: EntryPoint[IO] => IO[Unit], meta: Map[String, TraceValue] = Map.empty): IO[List[Request[IO]]] = + TestClient[IO].flatMap(c => entryPoint(c.client, "test", "blah", meta = meta).use(f) >> c.requests) test("Obtain the agent host from the parameter") { assertIO( @@ -126,6 +126,21 @@ class DatadogTest extends CatsEffectSuite { } } + test("Allow you to provide default tags") { + for { + res <- run( + _.root("bar").use(_.span("subspan").use(_ => IO.unit)), + Map("defaultTag1" -> "some-value", "defaultTag2" -> "some-other-value") + ) + spans <- res.flatTraverse(_.as[List[List[SubmittableSpan]]]).map(_.flatten) + } yield { + assertEquals(spans.head.meta.get("defaultTag1"), Some("some-value")) + assertEquals(spans.head.meta.get("defaultTag2"), Some("some-other-value")) + assertEquals(spans.tail.head.meta.get("defaultTag1"), Some("some-value")) + assertEquals(spans.tail.head.meta.get("defaultTag2"), Some("some-other-value")) + } + } + test("Inherit metadata into subspans but only at the time of creation") { run( _.root("bar:res").use { root => diff --git a/natchez-extras-doobie/src/main/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactor.scala b/natchez-extras-doobie/src/main/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactor.scala index e8bc9ed..6bde7aa 100644 --- a/natchez-extras-doobie/src/main/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactor.scala +++ b/natchez-extras-doobie/src/main/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactor.scala @@ -103,6 +103,20 @@ object TracedTransactor { new ConnectionInterpreter { override def prepareStatement(a: String): Kleisli[F, Connection, PreparedStatement] = super.prepareStatement(a).map(TracedStatement(_, a): PreparedStatement) + override def prepareStatement( + a: String, + b: Array[String] + ): Kleisli[F, Connection, PreparedStatement] = + super.prepareStatement(a, b).map(TracedStatement(_, a): PreparedStatement) + override def prepareStatement(a: String, b: Array[Int]): Kleisli[F, Connection, PreparedStatement] = + super.prepareStatement(a, b).map(TracedStatement(_, a): PreparedStatement) + override def prepareStatement(a: String, b: Int) = + super.prepareStatement(a, b).map(TracedStatement(_, a): PreparedStatement) + override def prepareStatement(a: String, b: Int, c: Int) = + super.prepareStatement(a, b, c).map(TracedStatement(_, a): PreparedStatement) + override def prepareStatement(a: String, b: Int, c: Int, d: Int) = + super.prepareStatement(a, b, c, d).map(TracedStatement(_, a): PreparedStatement) + override def getTypeMap: Nothing = super.getTypeMap.asInstanceOf // See: https://github.com/tpolecat/doobie/blob/v1.0.0-RC4/modules/core/src/test/scala/doobie/util/StrategySuite.scala#L47 override def commit: Kleisli[F, Connection, Unit] = diff --git a/natchez-extras-doobie/src/test/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactorTest.scala b/natchez-extras-doobie/src/test/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactorTest.scala index d326402..d942dd3 100644 --- a/natchez-extras-doobie/src/test/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactorTest.scala +++ b/natchez-extras-doobie/src/test/scala/com/ovoenergy/natchez/extras/doobie/TracedTransactorTest.scala @@ -65,7 +65,18 @@ class TracedTransactorTest extends CatsEffectSuite { database.test("Trace updates") { db => val create = sql"CREATE TABLE a (id INT, name VARCHAR)".update.run - val insert = sql"INSERT INTO a VALUES (${2: Int}, ${"abc": String})".update.run + val insert = + sql"INSERT INTO a VALUES (${2: Int}, ${"abc": String})".update.run + assertIO( + run((create >> insert).transact(db)).map(_.last), + SpanData("test-db:db.execute:INSERT INTO a VALUES (?, ?)", Map("span.type" -> "db")) + ) + } + + database.test("Trace updates withUniqueGeneratedKeys") { db => + val create = sql"CREATE TABLE a (id INT, name VARCHAR)".update.run + val insert = + sql"INSERT INTO a VALUES (${2: Int}, ${"abc": String})".update.withUniqueGeneratedKeys[String]("name") assertIO( run((create >> insert).transact(db)).map(_.init.last), SpanData("test-db:db.execute:INSERT INTO a VALUES (?, ?)", Map("span.type" -> "db"))