Check out the New Service Map! Check out the all-new Kamon APM Service Map!

Futures Instrumentation #

The kamon-futures module provides bytecode instrumentation for performing automatic Context Propagation with Scala Futures, as well as utilities to create Spans from a Future’s body and callbacks.

Context Propagation #

In the following piece of code, the body of the future will be executed asynchronously on a thread provided by the ExecutionContext available in implicit scope and when the code runs, Kamon will capture the current Context available when the future was created and make it available while executing the future’s body.

  Kamon.runWithContextEntry(userID, Some("1234")) {
    // The userID Context key is available here,

    Future {
      // is available here as well.
      "Hello Kamon"

    }.map(_.length)
      .flatMap(len => Future(len.toString))
      .map(s => Kamon.currentContext().get(userID))
      .map(println)
      // And through all async callbacks, even though
      // they are executed in different threads!
  }

Also, when you transform a future by using map/flatMap/filter and friends or you directly register a callback on a future (onComplete/onSuccess/onFailure), Kamon will capture the current Context available when transforming the future and make it available when executing the given callback. The code snippet above would print the same userID that was available when creating the future, during its body execution and during the execution of all the asynchronous operations scheduled on it.

Creating Spans #

It is possible to create Spans that represent an entire asynchronous computation, a Future’s body or asynchronous transformations applied to them by using these functions:

  • trace(operationName: String) { ... } which accepts a call-by-name block that produces a Future and creates a Span that will be automatically finished when the Future finishes.
  • traceBody(operationName: String) { ... } which accepts a call-by-name block that can be used to wrap the Future body and creates a Span that will be automatically finished when the Future’s body finishes executing.
  • traceFunc(operationName: String) { ... } which accepts a function that can be used to wrap any of the transformations than can be applied on a Future and creates a Span that will be automatically finished when the transformation finishes executing.

The traceBody and traceFunc functions work very similarly, the only reason for them not being the same is the mismatch between the types expected when creating a Future and the types expected when applying transformations to them. Let’s see this in a small example:

  import kamon.instrumentation.futures.scala.ScalaFutureInstrumentation.{traceBody, traceFunc}

  Future(traceBody("future-body") {

    // Here goes the actual future work, same as usual.
    "Hello Kamon"

  }).map(traceFunc("calculate-length")(_.length))
    .flatMap(traceFunc("to-string")(len => Future(len.toString)))
    .map(_ => Kamon.currentContext().get(userID))
    .map(println)

  // And through all async callbacks, even though
  // they are executed in different threads!

In the code example above, the instrumentation will automatically create a Span called future-body that measures how long did it take to execute the Future’s body, as well as additional Spans for the calculate-length and to-string steps of the computation. Note that even though the rest of the transformations in this example will not get dedicated Spans, they will still benefit from Context propagation, just as before!

Do not use these functions if you are not running your application without the instrumentation agent, since that will lead to threads not being properly cleaned up from previous request’s Contexts.

Manual Installation #

In case you are not using the Kamon Bundle, add the dependency below to your build.


libraryDependencies += "io.kamon" %% "kamon-scala-future" % "2.1.13"



    <dependency>
      <groupId>io.kamon</groupId>
      <artifactId>kamon-scala-future_2.12</artifactId>
      <version>2.1.13</version>
    </dependency>


implementation 'io.kamon:kamon-scala-future_2.12:2.1.13'

You must start your application with the instrumentation agent for this module to work properly.