From b48376e4c5690ea4d76f95c5e18e3cd50684e2b4 Mon Sep 17 00:00:00 2001 From: David van Geest Date: Mon, 9 Nov 2020 15:13:00 -0500 Subject: [PATCH 1/4] Replace play-json with nanojson, leave play-json tests for now. --- build.sbt | 3 +- .../kamon/datadog/DatadogSpanReporter.scala | 18 +++++--- .../src/main/scala/kamon/datadog/DdSpan.scala | 46 ++++++++++--------- .../main/scala/kamon/datadog/package.scala | 9 ++-- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/build.sbt b/build.sbt index 37f675bb9..5e81cb575 100644 --- a/build.sbt +++ b/build.sbt @@ -468,8 +468,9 @@ lazy val `kamon-datadog` = (project in file("reporters/kamon-datadog")) .settings( libraryDependencies ++= Seq( okHttp, - "com.typesafe.play" %% "play-json" % "2.7.4", + "com.grack" % "nanojson" % "1.1", + "com.typesafe.play" %% "play-json" % "2.7.4" % "test", scalatest % "test", slf4jApi % "test", slf4jnop % "test", diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala index 317e482f9..eea9fb6be 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala @@ -18,6 +18,7 @@ package kamon.datadog import java.time.Duration +import com.grack.nanojson.{JsonArray, JsonObject, JsonWriter} import com.typesafe.config.Config import kamon.trace.Span import kamon.{ ClassLoading, Kamon } @@ -26,7 +27,6 @@ import kamon.module.{ ModuleFactory, SpanReporter } import kamon.tag.{ Lookups, Tag, TagSet } import kamon.util.{ EnvironmentTags, Filter } import org.slf4j.LoggerFactory -import play.api.libs.json.{ JsObject, Json } import scala.util.{ Failure } @@ -101,12 +101,19 @@ class DatadogSpanReporter(@volatile private var configuration: Configuration) ex private val logger = LoggerFactory.getLogger(classOf[DatadogSpanReporter]) override def reportSpans(spans: Seq[Span.Finished]): Unit = if (spans.nonEmpty) { - val spanList: List[Seq[JsObject]] = spans + val spanLists: Array[Array[JsonObject]] = spans .map(span => configuration.translator.translate(span, configuration.envTags, configuration.tagFilter).toJson()) - .groupBy { _.\("trace_id").get.toString() } + .groupBy { jsonObj => Option(jsonObj.getNumber("trace_id")).get.toString() } + .mapValues(_.toArray) .values - .toList - configuration.httpClient.doJsonPut(Json.toJson(spanList)) match { + .toArray + + val jsonBuilder = JsonArray.builder + spanLists.foreach { span => + jsonBuilder.value(span) + } + + configuration.httpClient.doJsonPut(JsonWriter.string(jsonBuilder.done)) match { case Failure(exception) => throw exception case _ => () @@ -125,4 +132,3 @@ class DatadogSpanReporter(@volatile private var configuration: Configuration) ex } } - diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala index b09a8cbd0..e17e4a96e 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala @@ -18,7 +18,7 @@ package kamon.datadog import java.time.Duration -import play.api.libs.json._ +import com.grack.nanojson.JsonObject case class DdSpan( traceId: BigInt, @@ -33,31 +33,35 @@ case class DdSpan( meta: Map[String, String], error: Boolean) { - def toJson(): JsObject = { - val json = JsObject(Map( - "trace_id" -> JsNumber(BigDecimal(traceId)), - "span_id" -> JsNumber(BigDecimal(spanId)), - "name" -> JsString(name), - "type" -> JsString(spanType), - "resource" -> JsString(resource), - "service" -> JsString(service), - "start" -> JsNumber(BigDecimal(start)), - "duration" -> JsNumber(BigDecimal(duration.toNanos)), - "meta" -> JsObject( - meta.mapValues(JsString(_)).toSeq - ), - "error" -> JsNumber(if (error) 1 else 0), - "metrics" -> JsObject(Map( + def toJson(): JsonObject = { + val metaBuilder = JsonObject.builder + meta.foreach { case (k, v) => + metaBuilder.value(k, v) + } + val metaObj = metaBuilder.done + + val json = JsonObject.builder + .value("trace_id", BigDecimal(traceId)) + .value("span_id", BigDecimal(spanId)) + .value("name", name) + .value("type", spanType) + .value("resource", resource) + .value("service", service) + .value("start", BigDecimal(start)) + .value("duration", BigDecimal(duration.toNanos)) + .`object`("meta", metaObj) + .value("error", if (error) 1 else 0) + .`object`("metrics") // This tells the datadog agent to keep the trace. We've already determined sampling here or we wouldn't // be in this method. Keep in mind this DOES NOT respect sampling rates in the datadog agent // https://docs.datadoghq.com/tracing/guide/trace_sampling_and_storage/#client-implementation - "_sampling_priority_v1" -> JsNumber(1) - )) - ).toSeq) + .value("_sampling_priority_v1", 1) + .end + if (parentId.nonEmpty) { - json + ("parent_id", JsNumber(BigDecimal(parentId.get))) + json.value("parent_id", BigDecimal(parentId.get)).done } else { - json + json.done } } } diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala index 89dff5ae9..18cdb0c72 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala @@ -24,7 +24,6 @@ import com.typesafe.config.Config import kamon.metric.MeasurementUnit import kamon.metric.MeasurementUnit.{ information, time } import okhttp3._ -import play.api.libs.json.JsValue import scala.util.{ Failure, Success, Try } @@ -86,14 +85,14 @@ package object datadog { doMethodWithBody("PUT", contentType, contentBody) } - def doJsonPost(contentBody: JsValue): Try[String] = { + def doJsonPost(contentBody: String): Try[String] = { // Datadog Agent does not accept ";charset=UTF-8", using bytes to send Json posts - doPost("application/json", contentBody.toString().getBytes(StandardCharsets.UTF_8)) + doPost("application/json", contentBody.getBytes(StandardCharsets.UTF_8)) } - def doJsonPut(contentBody: JsValue): Try[String] = { + def doJsonPut(contentBody: String): Try[String] = { // Datadog Agent does not accept ";charset=UTF-8", using bytes to send Json posts - doPut("application/json", contentBody.toString().getBytes(StandardCharsets.UTF_8)) + doPut("application/json", contentBody.getBytes(StandardCharsets.UTF_8)) } // Apparently okhttp doesn't require explicit closing of the connection From 88443a36e6e7c4efaa99369b4ca580530d2d28d3 Mon Sep 17 00:00:00 2001 From: David van Geest Date: Wed, 11 Nov 2020 11:52:22 -0500 Subject: [PATCH 2/4] Update nanojson and shade dep for kamon-datadog. --- build.sbt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 5e81cb575..a31852a03 100644 --- a/build.sbt +++ b/build.sbt @@ -70,7 +70,7 @@ lazy val `kamon-status-page` = (project in file("core/kamon-status-page")) ShadeRule.rename("fi.iki.elonen.**" -> "kamon.lib.@0").inAll, ), libraryDependencies ++= Seq( - "com.grack" % "nanojson" % "1.1" % "provided,shaded", + "com.grack" % "nanojson" % "1.6" % "provided,shaded", "org.nanohttpd" % "nanohttpd" % "2.3.1" % "provided,shaded" ) ).dependsOn(`kamon-core`) @@ -464,11 +464,14 @@ lazy val reporters = (project in file("reporters")) lazy val `kamon-datadog` = (project in file("reporters/kamon-datadog")) - .disablePlugins(AssemblyPlugin) + .enablePlugins(AssemblyPlugin) .settings( + assemblyShadeRules in assembly := Seq( + ShadeRule.rename("com.grack.nanojson.**" -> "kamon.lib.@0").inAll, + ), libraryDependencies ++= Seq( okHttp, - "com.grack" % "nanojson" % "1.1", + "com.grack" % "nanojson" % "1.6" % "provided,shaded", "com.typesafe.play" %% "play-json" % "2.7.4" % "test", scalatest % "test", From 5ac3301dfa77fdc37e3b359d243db4f1c1525190 Mon Sep 17 00:00:00 2001 From: David van Geest Date: Thu, 12 Nov 2020 10:39:21 -0500 Subject: [PATCH 3/4] Don't shade nanojson. --- build.sbt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index a31852a03..851fac0d3 100644 --- a/build.sbt +++ b/build.sbt @@ -464,14 +464,11 @@ lazy val reporters = (project in file("reporters")) lazy val `kamon-datadog` = (project in file("reporters/kamon-datadog")) - .enablePlugins(AssemblyPlugin) + .disablePlugins(AssemblyPlugin) .settings( - assemblyShadeRules in assembly := Seq( - ShadeRule.rename("com.grack.nanojson.**" -> "kamon.lib.@0").inAll, - ), libraryDependencies ++= Seq( okHttp, - "com.grack" % "nanojson" % "1.6" % "provided,shaded", + "com.grack" % "nanojson" % "1.6", "com.typesafe.play" %% "play-json" % "2.7.4" % "test", scalatest % "test", From 7777833183d3cec06f91051a919b15a8623eac8d Mon Sep 17 00:00:00 2001 From: David van Geest Date: Thu, 12 Nov 2020 11:14:41 -0500 Subject: [PATCH 4/4] Re-run tests.