Как сделать доступными значения sourceThread и akkaTimestamp в событиях журнала, отправляемых частями, отличными от Akka?

Наш проект Akka зависит от какого-то другого кода, отличного от akka. Из этого кода наш способ получить регистратор — вызвать org.slf4j.LoggerFactory.getLogger(ThisClass.class)

Я хотел бы иметь реальное время и реальный поток, когда и где произошло событие, включенные в печать журнала, поэтому я получаю значения akkaTimestamp< /strong> и sourceThread следующим образом:

log4j.appender.console.layout.ConversionPattern=[%-5p] [%X{akkaTimestamp}] [%X{sourceThread}] %c{5}: %m%n

Проблема в том, что эти значения, извлеченные из MDC, недоступны в отпечатках, которые были отправлены из регистраторов, не являющихся akka.

Вот говорят

Вероятно, будет хорошей идеей использовать значение MDC sourceThread также в частях приложения, отличных от Akka, чтобы это свойство всегда было доступно в журналах.

Но они никогда не говорят, как /:


person kumetix    schedule 03.05.2015    source источник
comment
Не уверен насчет akkaTimestamp, но для sourceThread я просто вызываю MDC.put("sourceThread", Thread.currentThread().getName()) либо в акторе перед вызовом неактерного кода, либо в некоторых случаях это будет первое, что я делаю в неактерном коде. Если вы можете получить доступ к akkaTimestamp из контекста актера, вы также можете установить это.   -  person nickebbitt    schedule 03.05.2015
comment
спасибо @nickebbitt, но этого решения недостаточно. помимо зависимостей нашей собственной стороны, у нас также есть много сторонних сторон, таких как искры, хаупы и т. д. У меня не всегда есть хуки, на которые я могу повесить вызовы на MDC, и даже если бы я это сделал, это не слишком много смысла - слишком много обслуживания в долгосрочной перспективе. Я предполагаю, что я действительно ищу способ сообщить log4j, чтобы он проверял в каждой публикации события, есть ли значения для akkaTimestamp и sourceThread, а в случае отсутствия заполните значения из %d и %t соответственно.   -  person kumetix    schedule 04.05.2015
comment
Да, обслуживание - это проблема, и сторонние зависимости. По этой причине подход ограничен. Я рассматривал решение АОП, но еще не исследовал этот вариант.   -  person nickebbitt    schedule 04.05.2015


Ответы (2)


Как говорит Конрад, это не так уж и сложно. Вот что сработало для меня:

import akka.util.Helpers
import ch.qos.logback.core.ConsoleAppender
import org.slf4j.MDC

/**
 * Decorates MDC with same keys as Akka in
 * <a href="https://github.com/akka/akka/blob/master/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jLogger.scala#L89">Slf4jLogger</a>
 * So that logging messages dispatched from non-akka threads has same data.
 */
class AkkaCompatibleConsoleAppender[E] extends ConsoleAppender[E] {

  val mdcThreadAttributeName = "sourceThread"
  val mdcAkkaTimestamp = "akkaTimestamp"

  override def append(eventObject: E): Unit = {
    try {
      MDC.put(mdcAkkaTimestamp, Helpers.currentTimeMillisToUTCString(System.currentTimeMillis()))
      MDC.put(mdcThreadAttributeName, Thread.currentThread().getName)
      super.append(eventObject)
    } finally {
      MDC.remove(mdcAkkaTimestamp)
      MDC.remove(mdcThreadAttributeName)
    }
  }
}

А затем в logback.xml:

<appender name="STDOUT" class="agordo.server.AkkaCompatibleConsoleAppender">
    <encoder>
        <pattern>%X{akkaTimestamp} %-5level %logger{36} %X{sourceThread} %X{akkaSource} - %msg%n</pattern>           
    </encoder>
</appender>
person Yuriy Lazaryev    schedule 24.05.2015
comment
Еще не пробовал, но выглядит многообещающе. Спасибо! - person kumetix; 25.05.2015
comment
Смысл akkaTimestamp в том, что он записан во время события. , а не когда оно было зарегистрировано. Последняя информация доступна в Logback как %date. Я не знаю, как получить временную метку источника в пользовательском коде. - person dskrvk; 04.09.2016
comment
Небольшое дополнение: если вы используете одно и то же приложение для журналов, сгенерированных как Akka, так и журналов, не созданных Akka, безусловный MDC.put перезапишет значения, предоставленные Akka, в основном возвращаясь к использованию %d и %thread. Поэтому проверьте if (MDC.get(mdcAkkaTimestamp) == null || MDC.put(mdcThreadAttributeName) == null) перед их добавлением. - person Vasiliy Ivashin; 23.12.2016
comment
Я пытаюсь сделать это на игровой платформе. Проблема в загрузке класса. Как я могу настроить этот класс, чтобы игра знала? - person Eugene Chung; 10.11.2017
comment
Это неправильно! threadName не равно реальному sourceThread, который обрабатывал сообщения в акторе. - person Arya; 25.07.2019
comment
@VasiliyIvashin: Было бы лучше, если бы вы обновили сам фрагмент кода. - person d-coder; 23.08.2019

Вы можете настроить свои регистраторы, отличные от akka, на использование того же стиля MDC. Это не очень сложно, и вы можете посмотреть Slf4jLogger, чтобы увидеть, как это делается.

Для текущего потока вы можете просто использовать Thread.currentThread.getName, а на время (чтобы быть 1:1 с внедрением Akka) вы можете взглянуть на метод Helpers.currentTimeMillisToUTCString в Akka (см. здесь для currentTimeMillisToUTCString)

Удачного хакинга!

person Konrad 'ktoso' Malawski    schedule 03.05.2015
comment
Если я вас правильно понимаю, то, что вы предлагаете мне, - это перейти ко всем моим собственным зависимостям, не относящимся к akka, и заменить все вызовы LoggerFactory.getLogger на MyLoggeFactory.getLogger, которые вручную поместят дату и поток под ключами akkaTimestamp и sourceThread в MDC, это правильно? ? Не достаточно хорош. У меня все еще есть много сторонних разработчиков, таких как spark и hadoop, у которых нет доступа к точкам жизненного цикла, в которых отправляются их события журнала. - person kumetix; 04.05.2015
comment
И да и нет. Если вы хотите добавить информацию в места (сторонний код), где они ее не предоставляют, вы можете использовать там свой собственный Appender, который обернет существующий Appender slf4j, введет данные MDC и вызовет базовый регистратор (подумайте о ручном АОП). Это не весело, но и не проблема akka или scala - так работает SLF4J. - person Konrad 'ktoso' Malawski; 04.05.2015
comment
@ konrad-ktoso-malawski то, что вы говорите, звучит интересно, но из-за отсутствия (всего немного) примеров кода я понятия не имею, как это реализовать /: - person kumetix; 04.05.2015
comment
Это немного исследовательски и хакерски, у меня нет готового решения, только идеи, которые должны работать :) - person Konrad 'ktoso' Malawski; 04.05.2015