Kamon provides five instrument types that can be used for recording metrics:
You can find more details in the Metric Instruments section.
To record metrics you need to request the appropriate instrument from the Kamon
companion object (or static members, if
on Java), tag it (or run it withoutTags()
) and then you are ready to record metrics. Let’s look at a example:
// Simple metrics can be one-liners, without refining (tagging)
Kamon.counter("app.orders.sent").withoutTags().increment() // (1)
// If refining (tagging) is needed, define a metric first;
// here is a metric called "app.error" with a counter instrument.
val errors = Kamon.counter("app.error") // (2
// Refine the metric with a specific set of tags
val invalidUserErrors = errors.withTag("class", "InvalidUser") // (3)
val invalidPassErrors = errors.withTag("class", "InvalidPassword") // (4)
invalidPassErrors.increment() // (5)
// Removing a metric from Kamon
errors.remove(TagSet.of("class", "InvalidUser")) // (6)
(1)
(2)
class=InvalidUser
(3)
tag and another using the class=InvalidPassword
tag (4)
.(5)
app.error
metric with the class=InvalidUser
tag from Kamon. (6)
There are a few important things that you should keep in mind when using metrics:
span.processing-time
metric
to track Span latencies and we add an operation=login
or operation=search
tag (plus some more) to identify from
where we are recording such measurements.Counters can only do one thing: increment. You can either increment()
by one or increment(times)
a specific number of
times at once.
// One-liner
Kamon.counter("app.orders.sent").withoutTags().increment()
// Fully defined and refined (tagged) counter
val sentBytes = Kamon.counter("network.traffic", information.bytes)
.withTag("direction", "out").withTag("interface", "eth0")
sentBytes.increment()
sentBytes.increment(512)
A gauge can be update(value)
to as specific value, increment()
, increment(times)
, decrement()
and decrement(times)
.
// One-liner
Kamon.gauge("users").withoutTags().update(42)
// Fully defined and refined (tagged) gauge
val onlineUsers = Kamon.gauge("users")
.withTag("status", "online")
onlineUsers.update(43)
onlineUsers.decrement()
onlineUsers.decrement(4)
onlineUsers.increment()
onlineUsers.increment(7)
Histograms record the entire distribution of values for a given metric. The only available operations are record(value)
and record(value, times)
.
// One-liner
Kamon.histogram("messaging.payload-size").withoutTags()
// Fully defined and refined (tagged) histogram
val responseSizes = Kamon.histogram("http.response-size", information.bytes)
.withTag("status-code", "200")
responseSizes.record(2048)
Timers assume that you are measuring latency so all you need to do is provide a name and start()
a timer. You will get
back a Timer.Started
instance that can be stop()
ed whenever the operation you are measuring finishes.
// One-liner
val startedTimer = Kamon.timer("operations").withoutTags().start()
// do some work
startedTimer.stop()
// Fully defined and refined (tagged) timer
val operationLatency = Kamon.timer("operation-latency")
.withTag("operation", "login")
val timer = operationLatency.start()
// do some work
timer.stop()
A range sampler is always paired with a component or piece of state that starts at zero and can increment and decrement,
like a message queue size or the number of concurrent requests being processed by a service. The exposed operations are
similar to those offered by gauges, namely increment()
, increment(times)
, decrement()
and decrement(times)
.
// One-liner
Kamon.rangeSampler("http.in-flight").withoutTags().increment()
// Fully defined and refined (tagged) timer
val mailboxSize = Kamon.rangeSampler("actor.mailbox-size")
.withTag("actor", "user/test-actor")
mailboxSize.increment()
mailboxSize.increment(12)
mailboxSize.decrement(12)
mailboxSize.decrement()