← На главную

Трассировка в Akka при помощи библиотеки Kamon

Ранее в заметке Делаем метрики и мониторинг для 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?