OpenTracing helpers for the Lagom Framework

OpenTracing for the Lagom Framework

Maven Central

Note that this software comes without warranty. It is used in production at Delta Projects, but it may not be suited for your use case. Lightbend provides commercial OpenTracing support in the form of Lightbend Telemetry


Lagom is a microservices framework by Lightbend for Scala and Java based on Akka and Play. For more information, visit


OpenTracing is a vendor neutral specification for tracing distributed systems. For more information, visit

Lagom + OpenTracing

This package provides simple helper methods for dealing with the OpenTracing headers in Lagom service calls.


libraryDependencies += "com.deltaprojects" %% "lagom-opentracing" % "0.2.3"

When loading your services you should register a global tracer

val tracer: Tracer = ... // your favourite Tracer implementation


HTTP requests

Server Usage

class HelloServiceImpl extends HelloService {
  override def sayHello = ServiceCall { name =>
    Future.successful(s"Hello $name!")
  override def yourServiceHandler: ServerServiceCall[Request, Response] =
    trace("OPERATION_NAME") { scope =>
      ServerServiceCall { request =>
        scope.span.setBaggageItem("user", request.user)

Note that there is no need to close the scope manually, it will be closed automatically when the handler returns.

Client Usage

val scope = tracer.buildSpan("Handling your service").startActive(true)

.map(response => {
    scope.span.log("Received response")


You can also trace commands and domain events. Commands and events have the same API. The examples below are from the official Lagom documentation, sprinkled with some tracing.

Command and Event Usage

final case class AddPost(content: PostContent) extends BlogCommand with TracedCommand[BlogCommand] with ReplyType[AddPostDone]

sealed trait BlogEvent extends AggregateEvent[BlogEvent] with TracedEvent[BlogEvent] {
  override def aggregateTag: AggregateEventShards[BlogEvent] = BlogEvent.Tag

final case class PostAdded(postId: String, content: PostContent) extends BlogEvent

override def addPost(id: String) = ServiceCall { request =>
  val ref = persistentEntities.refFor[Post](id)
  ref.ask(request.withTracing).map(ack => "OK") // with tracing!

override def behavior: Behavior =
    .onCommand[AddPost, AddPostDone] {
      case (com@AddPost(content), ctx, state) if state.isEmpty =>
        val scope = com.extractScope("AddPost")
        ctx.thenPersist(PostAdded(entityId, content).withTracing) { evt => // with more tracing!
    .onEvent {
      case (ev@PostAdded(postId, content), state) =>
        val scope = ev.extractScope("PostAdded")
        scope.span.setBaggageItem("content", content)
        BlogState(Some(content), published = false)
    .onReadOnlyCommand[GetPost.type, PostContent] {
      case (com@GetPost, ctx, state) if !state.isEmpty =>
        val scope = com.extractScope("GetPost")


  • Support HTTP tracing
  • Support CQRS tracing
  • Implement Tests
  • Support adding arbitrary OpenTracing header Tags
  • Support the Java API

Pull requests welcome! :)