scala 阿卡伐木演员外

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10157642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:06:01  来源:igfitidea点击:

Akka Logging outside Actor

scalaloggingakka

提问by Bradford

I have an Akka Actor that makes a call to MyObject.foo(). MyObjectis not an Actor. How do I setup Logging in it? With an Actor it's simple, because I can just mixin ActorLogging. In MyObject, I don't have access to context.system. Do I create an akka.event.Loggingwith AkkaSystem() and then what for the LogSource implicit?

我有一个 Akka Actor 调用MyObject.foo(). MyObject不是演员。我如何设置登录?使用Actor很简单,因为我可以混合ActorLogging。在 MyObject 中,我无权访问 context.system。我是否akka.event.Logging使用 AkkaSystem()创建一个,然后为 LogSource 隐式创建什么?

采纳答案by Tomasz Nurkiewicz

Actually I would redirect Akka logging to slf4jand use this API directly in all unrelated classes. First add this to your configuration:

实际上我会将 Akka 日志重定向到slf4j并直接在所有不相关的类中使用这个 API。首先将其添加到您的配置中:

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

Then choose some SLF4J implementation, I suggest logback. In your actors continue using ActorLoggingtrait. In other classes simply rely on SLF4J API - or even better - try out slf4sfacade around SLF4J.

然后选择一些 SLF4J 实现,我建议logback。在您的演员中继续使用ActorLoggingtrait。在其他类中,只需依赖 SLF4J API - 或者甚至更好 -在 SLF4J 周围尝试slf4s外观。

Tip: try out the following logging pattern in Logback:

提示:在 Logback 中尝试以下日志记录模式:

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

The %X{akkaSource}will print actor path when available (just like standard logging).

%X{akkaSource}将打印演员路径时可用(就像标准的日志记录)。

回答by bnsmith

Using Akka 2.2.1, I was able to put this into my App to get logging outside of an actor:

使用 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!")

This seems like a simpler solution for unifying an application's logging.

这似乎是统一应用程序日志的更简单的解决方案。

回答by Matthew Mark Miller

As has been mentioned, you're spoiled for options for non-actor logging within an actor system. I am going to attempt to provide a set of heuristics to help you determine how you should route logging for your work.

正如已经提到的,您被演员系统中的非演员日志记录选项所宠坏。我将尝试提供一组启发式方法来帮助您确定应该如何为您的工作路由日志记录。

  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.
    • If you do this, you gain no benefits from the actor system. Logging calls may become blocking calls, depending on how you have your logger set up, and thus this is frowned upon wherever performance or control over back pressure are important concerns.
    • Because actor code (along with services it can consume) can operate on many different threads, some traditional logging activities such as the use of a threadlocal MDC (Mapped Diagnostic Context) can result in bizarre race conditions and context swtiching with logs output from messages that pass from actor to actor. Activities such as swapping MDCs onto messages before sending them may become necessary to preserve context between actor and non actor code.
    • To capture ActorSystem events such as dead letters and supervision, you may need to write a logging adapter and specify it in your application.conf. These are pretty straightforward.
  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.
    • You may inherit blocking behavior from your log framework.
    • You may have to manage MDCs
    • To capture ActorSystem events you'll need to specify "akka.event.slf4j.Slf4jLogger" in your application.conf
    • You'll need to include an slf4j provider jar on the classpath to route slf4j log events to your chosen logger
  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.
    • You have to pass around an actor system to act as the "bus" for loggers. Tight coupling to a working actor system reduces portability further. (Within an app I usually build a little LoggingViaActorSystem trait with an implicit or global ActorSystem, which makes it easier to deal with this in code but not across dependencies).
    • Non-blocking aynchronous logging is guaranteed, even if your logger doesn't support them. Causal consistency of logging is likely due to the use of a single consumer mailbox. However, memory safety and back pressure are not (I believe Akka logging uses an unbounded mailbox) --
    • There are options such as use of a DiagnosticLoggingAdapterfor avoiding the complexity of managing your own MDCs as work passes from actor to actor. Consistency should be preserved even as non-actor code mutates these MDCs.
    • Logging is not likely to be available during an out-of-memory crash, and is sensitive to thread starvation on the default dispatcher
    • You'll need to specify your chosen logger in application.conf unless you're interested in logging to standard out
  1. 您可以直接在参与者和非参与者代码中使用记录器(log4j 1.x、logback、log4j 2.x)。
    • 这将您的代码与记录器实现紧密耦合。如果它是您的代码,而不是在其他地方使用,这很好,但如果您正在构建一个库或打算开源您的工作,那就不好了。
    • 如果您这样做,您将无法从参与者系统中获得任何好处。记录调用可能会成为阻塞调用,这取决于您设置记录器的方式,因此在性能或对背压的控制是重要问题的任何地方都不赞成这样做。
    • 由于参与者代码(连同它可以使用的服务)可以在许多不同的线程上运行,一些传统的日志记录活动,例如使用线程本地 MDC(映射诊断上下文)可能会导致奇怪的竞争条件和上下文切换与来自消息的日志输出从演员到演员。诸如在发送消息之前将 MDC 交换到消息的活动可能变得必要以保留参与者和非参与者代码之间的上下文。
    • 要捕获死信和监督等 ActorSystem 事件,您可能需要编写日志适配器并在 application.conf 中指定它。这些非常简单。
  2. 您可以将 SLF4J 外观用于参与者和非参与者日志记录。
    • 您不再与记录器 impl 耦合,而且您的服务也不再与 akka 耦合。这是便携性的最佳选择。
    • 您可以从日志框架继承阻塞行为。
    • 您可能需要管理 MDC
    • 要捕获 ActorSystem 事件,您需要在 application.conf 中指定“akka.event.slf4j.Slf4jLogger”
    • 您需要在类路径中包含一个 slf4j 提供程序 jar 以将 slf4j 日志事件路由到您选择的记录器
  3. 您可以在 Actor 和非 Actor 代码中使用 Akka 的日志记录作为您的外观
    • 您没有耦合到记录器 impl 或 slf4j,但您耦合到了 akka 版本。无论如何,这可能是您的系统的要求,但对于库来说,它可能会降低可移植性。
    • 你必须传递一个actor系统来充当记录器的“总线”。与工作actor系统的紧密耦合进一步降低了可移植性。(在应用程序中,我通常会构建一个带有隐式或全局 ActorSystem 的 LoggingViaActorSystem 特征,这使得在代码中处理这个问题更容易,但不能跨依赖项处理)。
    • 保证非阻塞异步日志记录,即使您的记录器不支持它们。日志的因果一致性很可能是由于使用了单个消费者邮箱。然而,内存安全和背压不是(我相信 Akka 日志使用无界邮箱)——
    • 有一些选项,例如使用DiagnosticLoggingAdapter来避免在工作从一个参与者传递到另一个参与者时管理自己的 MDC 的复杂性。即使非参与者代码改变了这些 MDC,也应该保持一致性。
    • 在内存不足崩溃期间日志记录不太可能可用,并且对默认调度程序上的线程饥饿很敏感
    • 您需要在 application.conf 中指定您选择的记录器,除非您有兴趣登录到标准输出

You're welcome to mix and match the above behaviors as necessary to meet your requirements. For example, you might choose to bind to SLF4J for libraries and use Akka logging for everything else. Just note that mixing blocking and non-blocking logging could cause race conditions where causes (logged async via an actor) are logged after their effects (logged sync directly).

欢迎您根据需要混合和匹配上述行为以满足您的要求。例如,您可以选择将库绑定到 SLF4J,并为其他所有内容使用 Akka 日志记录。请注意,混合阻塞和非阻塞日志记录可能会导致竞争条件,其中原因(通过参与者异步记录)在其影响(直接记录同步)之后被记录。

回答by Antony Stubbs

I've now settled on simply passing my central logging system around through DI constructor injection (Guice). And in my classes that do logging regularly (where asynchronicity is important), I take the injected ActorSystem and call the

我现在已经决定简单地通过 DI 构造函数注入 (Guice) 传递我的中央日志系统。在我定期记录日志的类中(其中异步性很重要),我使用注入的 ActorSystem 并调用

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

in the classes constructor.

在类构造函数中。

回答by Mohsen Kashi

simply create your own logger:

只需创建自己的记录器:

private val log = LoggerFactory.getLogger(YourClass.getClass)