diff --git a/build.sbt b/build.sbt index 37f675bb9..851fac0d3 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`) @@ -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.6", + "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