aboutsummaryrefslogblamecommitdiff
path: root/src/main/scala/TracingDirectives.scala
blob: a172808c8d68ea2197aa90cfee37cdadeaabf605 (plain) (tree)
1
2
3
4
5
6
7
8
9

                          

                     


                                             

                                  




                                     



                                                              

     
                           
                                        
                                                                       
                                       









                                                                       






                                                           
                      
                                                         













                                                                                           
       

     
 
 
                                                    

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