Last active
July 3, 2022 16:04
-
-
Save chadselph/65f21fc86f873d6569f4cfe4f96ce036 to your computer and use it in GitHub Desktop.
akka-http directive for opentracing.io
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util | |
import java.util.Map.Entry | |
import akka.http.scaladsl.model.HttpHeader | |
import io.opentracing.propagation.TextMap | |
import scala.collection.JavaConverters.asJavaIteratorConverter | |
/** | |
* Used to extract an iterator of Entry[String, String] to the | |
* io.opentracing API from akka-http request | |
*/ | |
class AkkaHttpHeaderExtractor(headers: Seq[HttpHeader]) extends TextMap { | |
val headersEntries: Seq[Entry[String, String]] = headers.map(header => new Entry[String, String] { | |
override def getValue: String = header.value() | |
override def getKey: String = header.name() | |
override def setValue(value: String): String = throw new UnsupportedOperationException("Cannot set a value") | |
}) | |
override def put(key: String, value: String): Unit = { | |
throw new UnsupportedOperationException("AkkaHttpHeaderExtractor should only be used with Tracer.extract()") | |
} | |
override def iterator(): util.Iterator[Entry[String, String]] = headersEntries.iterator.asJava | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import akka.http.scaladsl.server.{Directive1, Directives, Route} | |
import akka.http.scaladsl.server.Directives.{extractRequest, mapResponse, provide} | |
import io.opentracing.{Span, Tracer} | |
/** | |
* Directives for tracing requests | |
*/ | |
trait TracingDirectives { | |
def trace(tracer: Tracer)(operationName: String): Directive1[Span] = { | |
extractRequest.flatMap { req => | |
val parent = Try( | |
// This method will throw an IllegalArgumentException for a bad | |
// tracer header, or return null for no header. Handle both cases as None | |
tracer.extract(Format.Builtin.HTTP_HEADERS, new AkkaHttpHeaderExtractor(req.headers)) | |
).filter(_ != null).toOption | |
val span = parent.fold( | |
tracer.buildSpan(operationName).start())( | |
p => tracer.buildSpan(operationName).asChildOf(p).start() | |
) | |
mapResponse { resp => | |
span.setTag("http.status_code", resp.status.intValue()) | |
span.setTag("http.url", req.effectiveUri(securedConnection = false).toString()) | |
span.setTag("http.method", req.method.value) | |
span.finish() | |
resp | |
} & provide(span) | |
} | |
} | |
} | |
object TracingDirectives extends TracingDirectives | |
object Example extends Directives with TracingDirectives { | |
val mytrace: String => Directive1[Span] = trace( new TracerImpl ) // needs an actual impl | |
val routes: Route = path ("foo" / "bar") { | |
mytrace("get-foo-bar") { span => | |
span.setTag("key", "value") | |
complete("sweet") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment