Ранее в заметке Делаем метрики и мониторинг для Akka при помощи Kamon мы уже познакомились с некоторыми возможностями Kamon. Правда, нельзя сказать, что возможности эти были особо впечатляющими, так как метрики можно вполне успешно писать и безо всякого Kamon. Сегодня же мы познакомимся с некоторыми другими средствами, предоставляемыми этой несколько спорной, но определенно очень мощной библиотекой.

Первая довольно часто встречающаяся на практике задача — неявное пробрасывание некоторого контекста между акторами. Допустим, актор A1 проставляет некоторый контест, например, информацию о пользователе, запросе, с которым он пришел в бэкенд, а также, возможно, некоторых параметрах этого запроса. Затем актор A1 шлет запрос A2, тот шлет A3, и так далее, до A42. Отметим, что если в проекте используется Akka Cluster , акторы эти могут быть на очень даже разных машинах. В какой-то момент мы решили, что в акторе A42 неплохо бы получить информацию о контексте, полученном в акторе A1. Можно, конечно, пробрасывать этот контекст явно во всех сообщениях между акторами. Или менее явно, если воспользоваться имплиситами. Но для этого нам понадобится поправить код как минимум в 42 местах! А возможно и больше, так как акторы могут обмениваться несколькими типам сообщений.

К счастью, с помощью Kamon эту проблему можно решить намного проще.

В акторе A1 пишем что-то вроде:

Tracer. withNewContext (
«TestContext» ,
traceToken = Some ( s «dummy-trace-token» ) ,
autoFinish = true ) {
// … тут обычный код с запросами к остальным акторам …
}

Теперь в акторе A42 можно написать:

val token = Tracer. currentContext . token

… и получить текущий контекст, в данном случае строчку «dummy-trace-token». Понятно, что в общем случае нам хотелось бы передавать что-то чуть более интересное, чем обычные строки. Это легко реализовать, создав новый case class с поддержкой сериализации в JSON . Работает такое пробрасывание контекста на магии AspectJ, поэтому в IntelliJ IDEA на забудьте в Run → Edit Configurations… → VM Options прописать -javaagent:/path/to/aspectjweaver-1.8.2.jar . Также этот параметр требуется передавать JVM при запуске приложения в продакте, поэтому не забудьте поправить wrapper.conf или что вы там используете в проекте.

Не правда ли, приведенное выше решение лучше, чем внесение правок в 42 местах?

Рассмотрим еще пример. Когда в большом (и особенно — распределенном!) проекте что-то где-то начинает тормозить, определить, что именно, где именно и почему тормозит не всегда бывает просто. Kamon помогает нам и здесь.

Определим такой вот актор для сборки трейсов:

package me. eax . examples . tracing

import akka. actor . { ActorLogging, Actor }
import kamon. trace . TraceInfo

class TraceSubscriber extends Actor with ActorLogging {
var traceNumber = 0
override def receive : Receive = {
case inf : TraceInfo =>
traceNumber = traceNumber + 1
val segmentsNumber = inf. segments . size
log. info (
s «»»|Trace number $traceNumber —
|Trace Name: ${inf.name},
|timestamp: ${inf.timestamp},
|elapsedTime: ${inf.elapsedTime},
|segmentsNumber: $segmentsNumber
|»»»
. stripMargin . replace ( n , ‘ ‘ )
)
}
}

Подпишем его на трейсы:

val traceSubscriber = {
system. actorOf ( Props ( new TraceSubscriber ) , «traceSubscriber» )
}
Kamon. tracer . subscribe ( traceSubscriber )

Теперь внутри блока Tracer.withNewContext (см выше) мы можем определять так называемые «сегменты»:

Tracer. currentContext . withNewAsyncSegment (
«Main/sayHello» ,
«ask» ,
«me.eax.example» ) {
// … тут обычный код …
}

При выходе из блока Tracer.withNewContext в актор traceSubscriber магическим образом будет прилетать информация обо всех сегментах, выполненных в рамках контекста. Помимо информации, используемой в примере кода выше, можно также получить данные и о каждом отдельном сегменте, включая время, которое этот сегмент выполнялся:

Трассировка в Akka при помощи Kamon

Само собой разумеется, частоту, с которой прилетают сэмплы трейсов, можно настроить через конфиг.

Полную версию исходного кода к этой заметке можно найти на GitHub . Обратите особое внимание на использование плагина sbt-aspectj, подкладывание файла META-INF/aop.xml, а также настройки проекта в build.sbt. Следует понимать, что этот пост поверхностно описывает сравнительно простой пример, а больше подробной информации о представленном выше функционале вы найдете на официальном сайте Kamon .

А используете ли вы в своих проектах описанные возможности Kamon?

EnglishRussianUkrainian