Multithreading 与akka一起登录。应用程序设计
假设我有一个基于Multithreading 与akka一起登录。应用程序设计,multithreading,scala,concurrency,akka,Multithreading,Scala,Concurrency,Akka,假设我有一个基于Futures、在scala.concurrent上的scala应用程序来处理asyn/concurrency(到目前为止没有使用任何参与者) 在许多地方,我使用log4j将内容记录到日志文件中。 由于是I/O,我想我可以通过向LoggingActor发送日志消息来提高性能 大概是这样的: def stuffTodo(arg:String)(implicit ex:ExecutionContext) : Future[Result] = { // important perf
Futures
、在scala.concurrent
上的scala应用程序来处理asyn/concurrency(到目前为止没有使用任何参与者)
在许多地方,我使用log4j将内容记录到日志文件中。
由于是I/O,我想我可以通过向LoggingActor发送日志消息来提高性能
大概是这样的:
def stuffTodo(arg:String)(implicit ex:ExecutionContext) : Future[Result] = {
// important performant work
// ..
logAcrot ! LogMessage("message-1")
// ...
}
其中msg:case类日志消息(msg:String,隐式ExecutionContext)
然后在ActorLog
def receive = {
case LogMessage(msg:String, ex:ExecutionContext) ⇒ {log.info(msg + ex)}
}
我见过其他一些方法,它们基本上是包装scala.concurent.ExecutionContext
(使用当前线程)并使用-magic(log4j),通过将线程id附加到日志消息来进行日志记录。但最终它会阻止/减慢线程/执行(据我所知),并使应用程序变慢
在这种情况下,对于这个参与者,日志记录保持独立/异步,同时保持顺序
走这条路好吗?分享经验故事?赞成/反对/担忧?在尝试重载之前询问..这看起来像是过度工程化了 我将使用logback,并实现自定义异步Appender,如果我想这样做的话,那么如果我决定不中断,我就不必更改代码
否则日志库是很好的选择,我可能会尝试调整它以获得更好的性能,并依靠其他人的经验来实现此功能。Akka已经对日志提供了很好的支持,这在页面上有文档记录。我认为在您的系统中创建一个日志参与者是不必要的,尤其是当这个机制已经存在时 您可能已经使用了异步执行日志记录的
LoggingAdapter
类,它通过将其发布到事件总线来实现这一点。您应该能够在参与者或外部使用相同的机制
看看
记录Mixin
Scala有一个用于actor的mixin,它为actor创建记录器并允许设置MDC。从文件:
import Logging.MDC
final case class Req(work: String, visitorId: Int)
class MdcActorMixin extends Actor with akka.actor.DiagnosticActorLogging {
var reqId = 0
override def mdc(currentMessage: Any): MDC = {
reqId += 1
val always = Map("requestId" -> reqId)
val perMessage = currentMessage match {
case r: Req => Map("visitorId" -> r.visitorId)
case _ => Map()
}
always ++ perMessage
}
def receive: Receive = {
case r: Req => {
log.info(s"Starting new request: ${r.work}")
}
}
}
在参与者之外登录
Logging.scala
文件中有两个在参与者之外创建LoggingSource的示例:
trait MyType { // as an example
def name: String
}
implicit val myLogSourceType: LogSource[MyType] = new LogSource[MyType] {
def genString(a: MyType) = a.name
}
class MyClass extends MyType {
val log = Logging(eventStream, this) // will use "hallo" as logSource
def name = "hallo"
}
第二种变体用于包含参与者系统的地址:
如果需要,可以在日志适配器上设置MDC
记录线程和MDC
当日志记录由另一个线程异步执行时,文档还介绍了您在日志记录线程上的观点
由于日志记录是异步完成的,因此
在映射的诊断上下文(MDC)中捕获已执行的日志记录
属性名为sourceThread的。使用Logback时,线程名称为
可与模式布局中的%X{sourceThread}说明符一起使用
配置
跟随你的链接:我做了这个:看起来很有效。但是仍然应该弄清楚如何使布局工作/应用:很好。我已经使用日志文件中的一些示例为其他人更新了答案。
trait MyType { // as an example
def name: String
}
implicit val myLogSourceType: LogSource[MyType] = new LogSource[MyType] {
def genString(a: MyType) = a.name
def genString(a: MyType, s: ActorSystem) = a.name + "," + s
}
class MyClass extends MyType {
val sys = ActorSystem("sys")
val log = Logging(sys, this) // will use "hallo,akka://sys" as logSource
def name = "hallo"
}