Акка Логинг вне актера

У меня есть Akka Actor, который звонит MyObject.foo(). MyObject не актер. Как мне настроить Вход в систему? С Актером это просто, потому что я могу просто подмешать ActorLogging. В MyObject у меня нет доступа к context.system. Могу ли я создать akka.event.Logging с помощью AkkaSystem (), а зачем тогда неявный LogSource?


person Bradford    schedule 14.04.2012    source источник
comment
Вы это читали? : doc.akka.io/docs/akka/2.0/scala/logging .html   -  person Viktor Klang    schedule 15.04.2012
comment
@ViktorKlang ага. Однако он, похоже, не отвечает на мой вопрос и не описывает, зачем нужен регистратор событий Akka (в отличие от простого использования SLF4J непосредственно в Актере).   -  person Bradford    schedule 15.04.2012
comment
Потому что вы можете сделать любой серверный модуль регистрации асинхронным, поскольку ведение журнала выполняется через актера.   -  person Viktor Klang    schedule 15.04.2012
comment
@ViktorKlang, почему бы вам просто не реализовать SLF4J API с бэкэндом асинхронного делегирования Akka? Вместо этого API ведения журналов Akka делает странные вещи, например меняет порядок исключения и сообщения на обратный, и не поддерживает исключения для log.warning.   -  person Raman    schedule 23.01.2013
comment
Не помогло бы, кто-то еще пожаловался бы, что мы не использовали Java Logging API (кто-то уже использовал).   -  person Viktor Klang    schedule 24.01.2013


Ответы (6)


На самом деле я бы перенаправил ведение журнала Akka на slf4j и использовал это API напрямую во всех несвязанных классах. Сначала добавьте это в свою конфигурацию:

akka {
    event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
    loglevel = "DEBUG"
}

Затем выберите какую-нибудь реализацию SLF4J. Я предлагаю logback. В ваших актерах продолжайте использовать черту ActorLogging. В других классах просто полагайтесь на SLF4J API - или даже лучше - попробуйте slf4s фасад вокруг SLF4J.

Совет: попробуйте следующий шаблон ведения журнала в Logback:

<pattern>%d{HH:mm:ss.SSS} | %-5level | %thread | %X{akkaSource} | %logger{1} | %m%n%rEx</pattern>

%X{akkaSource} будет печатать путь к актеру, если он доступен (как при стандартном ведении журнала).

person Tomasz Nurkiewicz    schedule 14.04.2012
comment
Спасибо. Я не совсем уверен, почему существует ActorLogging, но, поскольку это так, имеет ли значение, что метод, который вызывает мой актер, будет использовать API SLF4J напрямую вместо использования системы событий журнала Akka? Какие опасности? В качестве альтернативы я мог бы создать субъект регистрации и просто отправлять туда сообщения журнала. Что здесь предпочтительнее? - person Bradford; 15.04.2012
comment
Но если вы напрямую используете фабрику SLF4J, вы не получите Async-журнал, верно? Я использую грязную статику для доступа к системному объекту atm: / - person Antony Stubbs; 23.04.2012
comment
@AntonyStubbs: нет, если вы хотите извлечь выгоду из асинхронного ведения журнала, вам нужно будет отправить сообщение какому-то актеру - и использовать этого актера для регистрации сообщения ... - person Tomasz Nurkiewicz; 23.04.2012
comment
@TomaszNurkiewicz, верно, это то, что akka предоставляет с помощью своей структуры субъектов ведения журнала (Slf4jEventHandler). Я нашел решение, которое есть в моем ответе. - person Antony Stubbs; 20.05.2012
comment
У меня точно такая же проблема, и когда я увидел этот ответ, я был уверен, что нашел свое решение, но оно не работает! Я добавил в свой application.conf строку обработчиков событий, как описано, в моем случае "MyObject" создается с отражением, а внутри него создается регистратор путем вызова org.slf4j.LoggerFactory.getLogger(getClass.getName), и все же все ключи, которые я поместил в MDC, все% X места пустые /: может кто-нибудь поделится золотым советом? - person kumetix; 11.05.2015

Используя Akka 2.2.1, я смог поместить это в свое приложение для входа в систему вне актера:

import akka.event.Logging
val system = ActorSystem("HelloSystem", ConfigFactory.load.getConfig("akka"))
val log = Logging.getLogger(system, this)
log.info("Hi!")

Это кажется более простым решением для унификации ведения журнала приложения.

person bnsmith    schedule 24.09.2013
comment
Этот ответ не решает реальной проблемы. Вы создаете целую систему ActorSystem только для того, чтобы выполнить некоторую регистрацию в классе. Если вам это нужно где-то еще, вы собираетесь создать еще одну ActorSystem? Можно также передать ссылку на вашу первую созданную ActorSystem. - person Simão Martins; 08.07.2015
comment
Не уверен, почему это было сильно поддержано в свете предыдущего комментария. Но я хотел бы надеяться, что вместо этого будет безопасно передать классу функцию ведения журнала вашего актера. - person matanster; 18.04.2018

Как уже упоминалось, вы избалованы опциями для ведения журнала без актора в системе актора. Я попытаюсь предоставить набор эвристик, которые помогут вам определить, как следует направлять ведение журнала для вашей работы.

  1. You can use a logger (log4j 1.x, logback, log4j 2.x) directly in both actor and non-actor code.
    • This tightly couples your code to a logger implementation. This is fine if it's your code, not to be used elsewhere, but not fine if you're building a library or intend to open source your work.
    • Если вы сделаете это, вы не получите никакой пользы от системы актеров. Вызовы регистрации могут превратиться в вызовы блокировки, в зависимости от того, как вы настроили регистратор, и, таким образом, это осуждается везде, где важны производительность или контроль обратного давления.
    • Поскольку код актора (вместе со службами, которые он может использовать) может работать во многих различных потоках, некоторые традиционные действия по ведению журнала, такие как использование локального MDC (сопоставленного диагностического контекста), могут приводить к странным условиям гонки и переключению контекста с выходными журналами из сообщений, которые переходить от актера к актеру. Такие действия, как замена MDC на сообщения перед их отправкой, могут стать необходимыми для сохранения контекста между кодом субъекта и кодом, не являющимся субъектом.
    • Для захвата событий ActorSystem, таких как мертвые письма и наблюдение, вам может потребоваться написать адаптер журналирования и указать его в вашем application.conf. Это довольно просто.
  2. You can use the SLF4J facade for both actor and non-actor logging.
    • You are no longer coupled to a logger impl and what's more your services aren't coupled to akka. This is the best option for portability.
    • Вы можете унаследовать блокирующее поведение от своей логической структуры.
    • Возможно, вам придется управлять MDC
    • Для захвата событий ActorSystem вам необходимо указать «akka.event.slf4j.Slf4jLogger» в вашем application.conf
    • Вам нужно будет включить jar поставщика slf4j в путь к классам для маршрутизации событий журнала slf4j на выбранный вами регистратор.
  3. You can use Akka's Logging as your facade in both Actor and non-actor code
    • You aren't coupled to a logger impl OR to slf4j, but you're coupled to a version of akka. This is probably a requirement of your system anyway, but for libraries it might reduce portability.
    • Вы должны обойти систему акторов, чтобы они действовали как «шина» для регистраторов. Тесная связь с работающей системой акторов еще больше снижает переносимость. (В приложении я обычно создаю небольшую черту LoggingViaActorSystem с неявной или глобальной ActorSystem, что упрощает работу с этим в коде, но не между зависимостями).
    • Неблокирующая асинхронная регистрация гарантируется, даже если ваш регистратор не поддерживает их. Причинно-следственная последовательность ведения журнала, вероятно, связана с использованием одного почтового ящика потребителя. Однако безопасность памяти и обратное давление - нет (я считаю, что ведение журнала Akka использует неограниченный почтовый ящик) -
    • Чтобы избежать сложность управления собственными MDC по мере передачи работы от актера к исполнителю. Согласованность должна быть сохранена, даже если код, не являющийся субъектом, изменяет эти MDC.
    • Ведение журнала вряд ли будет доступно во время сбоя из-за нехватки памяти и чувствительно к нехватке потоков в диспетчере по умолчанию
    • Вам нужно будет указать выбранный вами регистратор в application.conf, если вы не хотите входить в стандартный выход.

Вы можете комбинировать и сочетать приведенные выше варианты поведения, если это необходимо для удовлетворения ваших требований. Например, вы можете выбрать привязку к SLF4J для библиотек и использовать ведение журнала Akka для всего остального. Просто обратите внимание, что смешивание блокирующего и неблокирующего ведения журнала может вызвать состояния гонки, когда причины (записываемая асинхронно через актера) регистрируются после их последствий (регистрируемая синхронизация напрямую).

person Matthew Mark Miller    schedule 18.02.2016
comment
Исключает ли вариант 3 простую передачу регистратора актора Akka с использованием класса, не являющегося актором? - person matanster; 18.04.2018

Теперь я решил просто передать мою центральную систему журналирования через внедрение конструктора DI (Guice). И в моих классах, которые регулярно регистрируют (где важна асинхронность), я беру внедренную ActorSystem и вызываю

this.log = akka.event.Logging.getLogger(actorSystem, this);

в конструкторе классов.

person Antony Stubbs    schedule 19.05.2012
comment
Другой вариант, который может вам больше понравиться в случаях, когда вы не хотите увеличивать объект для хранения такой ссылки, - это добавить второй список параметров ( implicit log:LoggingAdapter ) к методам, которые должны вести журнал. - person AmigoNico; 12.10.2013

Согласно последней (в настоящее время версии 2.6.9) документации по ведению журнала Использование Регистратора, полученного от org.slf4j.LoggerFactory, совершенно нормально, и на самом деле это рекомендуемый способ входа в систему вне актера. Я копирую здесь и далее точную формулировку.

Совершенно нормально использовать регистратор, полученный через org.slf4j.LoggerFactory, но тогда события регистрации не будут включать значение akkaSource MDC. Это рекомендуемый способ при входе в систему вне актера, включая ведение журнала из будущих обратных вызовов.

Я также предоставляю ниже фрагмент, основанный на примере

val log = LoggerFactory.getLogger("com.mypackage.MyObject")

Future {
  // do something
  "result"
}.onComplete {
  case Success(result) => log.info("Success!: {}", result)
  case Failure(exc)    => log.error("Failure!", exc)
}

Чтобы минимизировать потери производительности при ведении журнала, можно настроить асинхронный аппендер для бэкэнда SLF4J. Logback - это рекомендуемый бэкэнд для ведения журнала.

dependencies {
  compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
}

Отправная точка для настройки logback.xml для производства:

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>myapp.log</file>
    <immediateFlush>false</immediateFlush>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>myapp_%d{yyyy-MM-dd}.log</fileNamePattern>
    </rollingPolicy>
    <encoder>
        <pattern>[%date{ISO8601}] [%level] [%logger] [%marker] [%thread] - %msg MDC: {%mdc}%n</pattern>
    </encoder>
</appender>

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <queueSize>8192</queueSize>
    <neverBlock>true</neverBlock>
    <appender-ref ref="FILE" />
</appender>

<root level="INFO">
    <appender-ref ref="ASYNC"/>
</root>

Ведение журнала обычно означает ввод-вывод и блокировки, которые могут замедлить работу вашего кода, если он выполняется синхронно.

Конфигурации, показанные выше, предоставлены документацией по ведению журнала AKKA. В документации содержится дополнительная информация, которую можно найти здесь

person Spyros K    schedule 01.09.2020

просто создайте свой собственный регистратор:

private val log = LoggerFactory.getLogger(YourClass.getClass)
person Mohsen Kashi    schedule 04.11.2018