aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/TracingDirectives.scala
blob: a172808c8d68ea2197aa90cfee37cdadeaabf605 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package xyz.driver.tracing

import java.util.UUID

import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._

import scala.collection.immutable.Seq

trait TracingDirectives {
  import TracingDirectives._

  def extractTraceHeaders: Directive1[Seq[HttpHeader]] =
    extractRequest.map { request =>
      request.headers.filter(h =>
        h.name == TraceHeaderName || h.name == SpanHeaderName)
    }

  def trace(tracer: Tracer,
            name: Option[String] = None,
            extraLabels: Map[String, String] = Map.empty): Directive0 =
    extractRequest.flatMap { request =>
      def getHeader(name: String): Option[String] =
        request.headers.find(_.name == name).map(_.value)

      // get existing trace or start a new one
      val traceId = getHeader(TraceHeaderName)
        .map(UUID.fromString)
        .getOrElse(UUID.randomUUID())

      val parentSpanId = getHeader(SpanHeaderName).map(UUID.fromString)

      val labels = Map(
        "/http/user_agent" -> "driver-tracer",
        "/http/method" -> request.method.name,
        "/http/url" -> request.uri.path.toString,
        "/http/host" -> request.uri.authority.host.toString
      ) ++ extraLabels

      val span = Span(
        name = name.getOrElse(request.uri.path.toString),
        traceId = traceId,
        parentSpanId = parentSpanId,
        labels = labels
      )

      val childHeaders = Seq(
        RawHeader(TraceHeaderName, span.traceId.toString),
        RawHeader(SpanHeaderName, span.spanId.toString)
      )

      mapRequest(childRequest => childRequest.withHeaders(childHeaders)) & mapRouteResult {
        result =>
          tracer.submit(span.end())
          result
      }
    }

}

object TracingDirectives extends TracingDirectives {
  val TraceHeaderName = "Tracing-Trace-Id"
  val SpanHeaderName = "Tracing-Span-Id"
}