Presented by Ivan Topolnjak (@ivantopo)
A set of libraries providing metrics collection, context propagation and
distributed tracing for applications on
the JVM
Traditional Threading
Servlets
"Reactive" Threading
Akka, Futures, RxJava
We had to have some AkKA MONitoring :P
// Creating Instruments
val histogram = Kamon.histogram("span.processing-time")
.refine("operation", "GET /users")
histogram.record(1000349L)
// Creating a Metrics Reporter
trait MetricReporter {
def start(): Unit
def stop(): Unit
def reconfigure(config: Config): Unit
def reportPeriodSnapshot(snapshot: PeriodSnapshot): Unit
}
// Adding Reporters in Runtime
Kamon.addReporter(new PrometheusReporter())
Kamon.addReporter(new KaminoReporter())
The Distribution snapshots contain a compact versions of all the HDR Histogram data.
Tracks behavior rather than point-in-time values
// Creating a Metrics Reporter
trait MetricReporter {
def start(): Unit
def stop(): Unit
def reconfigure(config: Config): Unit
def reportSpans(spans: Seq[Span.FinishedSpan]): Unit
}
// Adding Reporters in Runtime
Kamon.addReporter(new ZipkinReporter())
Kamon.addReporter(new JaegerReporter())
Kamon.addReporter(new KaminoReporter())
val span = Kamon.buildSpan("find-users")
.withTag("string-tag", "hello")
.withTag("number-tag", 42)
.withTag("boolean-tag", true)
.withMetricTag("early-tag", "value")
.start()
span
.tag("other-string-tag", "bye")
.tag("other-number-tag", 24)
.tag("other-boolean-tag", false)
span
.mark("message.dequeued")
.mark(at = Instant.now(), "This could be free text")
span
.tagMetric("tag", "value")
.disableMetrics()
.enableMetrics()
span.finish()
// Propagated in-process only
val UserID = Key.local[String]("userID", "undefined")
// Propagated in-process and across processes.
val SessionID = Key.broadcast[Option[Int]]("sessionID", None)
val RequestID = Key.broadcastString("requestID")
// Creating a Context with two keys
val context = Context()
.withKey(UserID, "1234")
.withKey(SessionID, Some(42))
// Reading values from a Context
val userID: String = context.get(UserID)
val sessionID: Option[Int] = context.get(SessionID)
// The default value is returned for non-existent keys
val requestID: Option[String] = context.get(RequestID)
A Context could be stored in any Storage implementation although only a ThreadLocal-based Storage is shipped with Kamon
// Propagated in-process only
trait ForEntry[T] {
def encode(context: Context): T
def decode(carrier: T, context: Context): Context
}
// Where T can be:
// - TextMap for HTTP Headers
// - ByteBuffer for Binary
// Add to the configuration file:
kamon.context.codecs {
string-keys {
l5d-ctx-dtab = "l5d-ctx-dtab"
l5d-ctx-deadline = "l5d-ctx-deadline"
l5d-ctx-trace = "l5d-ctx-trace"
}
}
// Add to the configuration file:
kamon.context.codecs.http-headers-keys {
span = "kamon.trace.W3CTraceParentCodec"
tracestate = "kamon.trace.W3CTraceStateCodec"
}
Codec available at https://github.com/kamon-io/kamon-tracecontext-codec
Planned:
More detailed writeup: http://kamon.io/teamblog/2018/04/27/kamon-forecast-april-2018/