У меня есть Akka Actor, который звонит MyObject.foo()
. MyObject
не актер. Как мне настроить Вход в систему? С Актером это просто, потому что я могу просто подмешать ActorLogging. В MyObject у меня нет доступа к context.system. Могу ли я создать akka.event.Logging
с помощью AkkaSystem (), а зачем тогда неявный LogSource?
Акка Логинг вне актера
Ответы (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}
будет печатать путь к актеру, если он доступен (как при стандартном ведении журнала).
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!")
Это кажется более простым решением для унификации ведения журнала приложения.
Как уже упоминалось, вы избалованы опциями для ведения журнала без актора в системе актора. Я попытаюсь предоставить набор эвристик, которые помогут вам определить, как следует направлять ведение журнала для вашей работы.
- 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. Это довольно просто.
- 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 на выбранный вами регистратор.
- 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 для всего остального. Просто обратите внимание, что смешивание блокирующего и неблокирующего ведения журнала может вызвать состояния гонки, когда причины (записываемая асинхронно через актера) регистрируются после их последствий (регистрируемая синхронизация напрямую).
Теперь я решил просто передать мою центральную систему журналирования через внедрение конструктора DI (Guice). И в моих классах, которые регулярно регистрируют (где важна асинхронность), я беру внедренную ActorSystem и вызываю
this.log = akka.event.Logging.getLogger(actorSystem, this);
в конструкторе классов.
( 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. В документации содержится дополнительная информация, которую можно найти здесь а>
просто создайте свой собственный регистратор:
private val log = LoggerFactory.getLogger(YourClass.getClass)