![JAR search and dependency download from the Maven repository](/logo.png)
com.persist.logging.LogActor.scala Maven / Gradle / Ivy
The newest version!
package com.persist.logging
import scala.concurrent.Promise
import akka.actor.Props
import com.persist.Exceptions.SystemException
import org.joda.time.format.ISODateTimeFormat
import com.persist.JsonOps._
import LoggingLevels._
import scala.language.postfixOps
import scala.language.existentials
private[logging] object LogActor {
sealed trait LogActorMessage
case class LogMessage(level: Level, id: AnyId,
time: Long, actorName: Option[String], msg: Json, sourceLocation: SourceLocation,
ex: Throwable, kind: String = "") extends LogActorMessage
case class SetLevel(level: Level) extends LogActorMessage
case class AltMessage(category: String, time: Long, j: JsonObject, id: AnyId, ex: Throwable) extends LogActorMessage
case class Slf4jMessage(level: Level, time: Long, className: String, msg: String, line: Int, file: String,
ex: Throwable) extends LogActorMessage
case class SetSlf4jLevel(level: Level) extends LogActorMessage
case class AkkaMessage(time: Long, level: Level, source: String, clazz: Class[_], msg: Any, cause: Option[Throwable])
extends LogActorMessage
case class SetAkkaLevel(level: Level) extends LogActorMessage
case object LastAkkaMessage extends LogActorMessage
case class SetFilter(filter: Option[(JsonObject, Level) => Boolean]) extends LogActorMessage
case object StopLogging extends LogActorMessage
def props(done: Promise[Unit], standardHeaders: JsonObject,
appends: Seq[LogAppender], initLevel: Level, initSlf4jLevel: Level, initAkkaLevel: Level)
= Props(new LogActor(done, standardHeaders, appends,
initLevel, initSlf4jLevel, initAkkaLevel))
}
private[logging] class LogActor(done: Promise[Unit], standardHeaders: JsonObject,
appenders: Seq[LogAppender], initLevel: Level,
initSlf4jLevel: Level, initAkkaLevel: Level) extends ActorLogging {
import LogActor._
private[this] var filter: Option[(JsonObject, Level) => Boolean] = None
private[this] var level: Level = initLevel
private[this] var akkaLogLevel: Level = initAkkaLevel
private[this] var slf4jLogLevel: Level = initSlf4jLevel
private[this] val logFmt = ISODateTimeFormat.dateTime()
private[this] val system = context.system
private def exToJson(ex: Throwable): Json = {
val name = ex.getClass.toString()
ex match {
case ex: RichException =>
JsonObject("ex" -> name, "msg" -> ex.richMsg)
case ex: SystemException =>
JsonObject("kind" -> ex.kind, "info" -> ex.info)
case ex: Throwable =>
JsonObject("ex" -> name, "msg" -> ex.getMessage)
}
}
private def getStack(ex: Throwable): Seq[JsonObject] = {
val stack = ex.getStackTrace map {
case trace =>
val j0 = if (trace.getLineNumber > 0) {
JsonObject("line" -> trace.getLineNumber)
} else {
emptyJsonObject
}
val j1 = JsonObject(
"class" -> trace.getClassName,
"file" -> trace.getFileName,
"method" -> trace.getMethodName
)
j0 ++ j1
}
stack
}
private def exceptionJson(ex: Throwable): JsonObject = {
val stack = getStack(ex)
val j1 = ex match {
case r: RichException if r.cause != noException =>
JsonObject("cause" -> exceptionJson(r.cause))
case ex1: Throwable if ex.getCause() != null =>
JsonObject("cause" -> exceptionJson(ex.getCause()))
case _ => emptyJsonObject
}
JsonObject("trace" -> JsonObject("msg" -> exToJson(ex), "stack" -> stack.toSeq)) ++ j1
}
private def append(stdHeaders: JsonObject, baseMsg: JsonObject, category: String, level: Level) {
val keep = category != "common" || (filter match {
case Some(f) => f(stdHeaders ++ baseMsg, level)
case None => true
})
if (keep) {
for (a <- appenders) a.append(baseMsg, category)
}
}
def receive = {
case LogMessage(level, id, time, actorName, msg, sourceLocation, ex, kind) =>
val t = logFmt.print(time)
val j = JsonObject("@timestamp" -> t, "msg" -> msg, "file" -> sourceLocation.fileName, "@severity" -> level.name,
"@category" -> "common")
val j0 = if (sourceLocation.line > 0) {
JsonObject("line" -> sourceLocation.line)
} else {
emptyJsonObject
}
val className = (sourceLocation.packageName, sourceLocation.className) match {
case (p, "") => ""
case ("", c) => c
case (p, c) => s"$p.$c"
}
val j1 = if (className == "") {
emptyJsonObject
} else {
JsonObject("class" -> className)
}
val j2 = actorName match {
case Some(actorName) => JsonObject("actor" -> actorName)
case None => emptyJsonObject
}
val j3 = if (ex == noException) {
emptyJsonObject
} else {
exceptionJson(ex)
}
val j4 = id match {
case RequestId(trackingId, spanId, level) =>
JsonObject("@traceId" -> JsonArray(trackingId, spanId))
case noId => emptyJsonObject
}
val j5 = if (kind == "") {
emptyJsonObject
} else {
JsonObject("kind" -> kind)
}
val shortMsg = j ++ j0 ++ j1 ++ j2 ++ j3 ++ j4 ++ j5
append(standardHeaders, shortMsg, "common", level)
case SetLevel(level1) => level = level1
case AltMessage(category, time, j, id, ex) =>
val t = logFmt.print(time)
val j3 = if (ex == noException) {
emptyJsonObject
} else {
exceptionJson(ex)
}
val j4 = id match {
case RequestId(trackingId, spanId, level) =>
JsonObject("@traceId" -> JsonArray(trackingId, spanId))
case noId => emptyJsonObject
}
append(standardHeaders, j ++ j3 ++ j4 ++ JsonObject("@timestamp" -> t), category, LoggingLevels.INFO)
case Slf4jMessage(level, time, className, msg, line, file, ex) => {
if (level.pos >= slf4jLogLevel.pos) {
val t = logFmt.print(time)
val j = JsonObject("@timestamp" -> t, "msg" -> msg, "file" -> file,
"@severity" -> level.name, "class" -> className, "kind" -> "slf4j", "@category" -> "common")
val j0 = if (line > 0) {
JsonObject("line" -> line)
} else {
emptyJsonObject
}
val j1 = if (ex == noException) {
emptyJsonObject
} else {
exceptionJson(ex)
}
val shortMsg = j ++ j0 ++ j1
append(standardHeaders, shortMsg, "common", level)
}
}
case SetSlf4jLevel(level) => slf4jLogLevel = level
case AkkaMessage(time, level, source, clazz, msg, cause) =>
if (level.pos >= akkaLogLevel.pos) {
val msg1 = if (msg == null) "UNKNOWN" else msg
val t = logFmt.print(time)
val j1 = cause match {
case Some(ex) => exceptionJson(ex)
case None => emptyJsonObject
}
val shortMsg = JsonObject("@timestamp" -> t, "kind" -> "akka", "msg" -> msg1.toString(), "actor" -> source,
"@severity" -> level.name, "class" -> clazz.getName(), "@category" -> "common") ++ j1
append(standardHeaders, shortMsg, "common", level)
}
case SetAkkaLevel(level) => akkaLogLevel = level
case LastAkkaMessage =>
val akkaLog = akka.event.Logging(context.system, this)
akkaLog.error("DIE")
case StopLogging =>
done.success(())
context.stop(self)
case SetFilter(f) => filter = f
case msg: Any =>
log.warn("Unrecognized LogActor message:" + msg)(() => DefaultSourceLocation)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy