package xyz.driver.core
import java.text.SimpleDateFormat
import java.util.Date
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.LayoutBase
import org.apache.commons.lang3.StringUtils
import org.slf4j.Marker
object logging {
trait Logger {
def fatal(message: String): Unit
def fatal(message: String, cause: Throwable): Unit
def fatal(message: String, args: AnyRef*): Unit
def fatal(marker: Marker, message: String): Unit
def fatal(marker: Marker, message: String, cause: Throwable): Unit
def fatal(marker: Marker, message: String, args: AnyRef*): Unit
def error(message: String): Unit
def error(message: String, cause: Throwable): Unit
def error(message: String, args: AnyRef*): Unit
def error(marker: Marker, message: String): Unit
def error(marker: Marker, message: String, cause: Throwable): Unit
def error(marker: Marker, message: String, args: AnyRef*): Unit
def audit(message: String): Unit
def audit(message: String, cause: Throwable): Unit
def audit(message: String, args: AnyRef*): Unit
def audit(marker: Marker, message: String): Unit
def audit(marker: Marker, message: String, cause: Throwable): Unit
def audit(marker: Marker, message: String, args: AnyRef*): Unit
def debug(message: String): Unit
def debug(message: String, cause: Throwable): Unit
def debug(message: String, args: AnyRef*): Unit
def debug(marker: Marker, message: String): Unit
def debug(marker: Marker, message: String, cause: Throwable): Unit
def debug(marker: Marker, message: String, args: AnyRef*): Unit
}
/**
* Logger implementation which uses `com.typesafe.scalalogging.Logger` on the back.
* It redefines the meaning of logging levels to fit to the Driver infrastructure design,
* and as using error and warn, debug and trace was always confusing and mostly done wrong.
*
* @param scalaLogging com.typesafe.scalalogging.Logger which logging will be delegated to
*/
class TypesafeScalaLogger(scalaLogging: com.typesafe.scalalogging.Logger) extends Logger {
def fatal(message: String): Unit = scalaLogging.error("FATAL " + message)
def fatal(message: String, cause: Throwable): Unit = scalaLogging.error("FATAL " + message, cause)
def fatal(message: String, args: AnyRef*): Unit = scalaLogging.error("FATAL " + message, args)
def fatal(marker: Marker, message: String): Unit = scalaLogging.error(marker, "FATAL " + message)
def fatal(marker: Marker, message: String, cause: Throwable): Unit =
scalaLogging.error(marker, "FATAL " + message, cause)
def fatal(marker: Marker, message: String, args: AnyRef*): Unit =
scalaLogging.error(marker, "FATAL " + message, args)
def error(message: String): Unit = scalaLogging.warn("ERROR " + message)
def error(message: String, cause: Throwable): Unit = scalaLogging.warn("ERROR " + message, cause)
def error(message: String, args: AnyRef*): Unit = scalaLogging.warn("ERROR " + message, args)
def error(marker: Marker, message: String): Unit = scalaLogging.warn(marker, "ERROR " + message)
def error(marker: Marker, message: String, cause: Throwable): Unit =
scalaLogging.warn(marker, "ERROR " + message, cause)
def error(marker: Marker, message: String, args: AnyRef*): Unit =
scalaLogging.warn(marker, "ERROR " + message, args)
def audit(message: String): Unit = scalaLogging.info("AUDIT " + message)
def audit(message: String, cause: Throwable): Unit = scalaLogging.info("AUDIT " + message, cause)
def audit(message: String, args: AnyRef*): Unit = scalaLogging.info("AUDIT " + message, args)
def audit(marker: Marker, message: String): Unit = scalaLogging.info(marker, "AUDIT " + message)
def audit(marker: Marker, message: String, cause: Throwable): Unit =
scalaLogging.info(marker, "AUDIT " + message, cause)
def audit(marker: Marker, message: String, args: AnyRef*): Unit =
scalaLogging.info(marker, "AUDIT " + message, args)
def debug(message: String): Unit = scalaLogging.debug("DEBUG " + message)
def debug(message: String, cause: Throwable): Unit = scalaLogging.debug("DEBUG " + message, cause)
def debug(message: String, args: AnyRef*): Unit = scalaLogging.debug("DEBUG " + message, args)
def debug(marker: Marker, message: String): Unit = scalaLogging.debug(marker, "DEBUG " + message)
def debug(marker: Marker, message: String, cause: Throwable): Unit =
scalaLogging.debug(marker, "DEBUG " + message, cause)
def debug(marker: Marker, message: String, args: AnyRef*): Unit =
scalaLogging.debug(marker, "DEBUG " + message, args)
}
object NoLogger extends Logger {
def fatal(message: String): Unit = {}
def fatal(message: String, cause: Throwable): Unit = {}
def fatal(message: String, args: AnyRef*): Unit = {}
def fatal(marker: Marker, message: String): Unit = {}
def fatal(marker: Marker, message: String, cause: Throwable): Unit = {}
def fatal(marker: Marker, message: String, args: AnyRef*): Unit = {}
def error(message: String): Unit = {}
def error(message: String, cause: Throwable): Unit = {}
def error(message: String, args: AnyRef*): Unit = {}
def error(marker: Marker, message: String): Unit = {}
def error(marker: Marker, message: String, cause: Throwable): Unit = {}
def error(marker: Marker, message: String, args: AnyRef*): Unit = {}
def audit(message: String): Unit = {}
def audit(message: String, cause: Throwable): Unit = {}
def audit(message: String, args: AnyRef*): Unit = {}
def audit(marker: Marker, message: String): Unit = {}
def audit(marker: Marker, message: String, cause: Throwable): Unit = {}
def audit(marker: Marker, message: String, args: AnyRef*): Unit = {}
def debug(message: String): Unit = {}
def debug(message: String, cause: Throwable): Unit = {}
def debug(message: String, args: AnyRef*): Unit = {}
def debug(marker: Marker, message: String): Unit = {}
def debug(marker: Marker, message: String, cause: Throwable): Unit = {}
def debug(marker: Marker, message: String, args: AnyRef*): Unit = {}
}
class DriverLayout extends LayoutBase[ILoggingEvent] {
import scala.collection.JavaConverters._
private val FieldSeparator = "="
private val DateFormatString = "MM/dd/yyyy HH:mm:ss"
private val newline = System.getProperty("line.separator")
private val IgnoredClassesInStack = Set("org.apache.catalina", "org.apache.coyote", "sun.reflect", "javax.servlet")
override def doLayout(loggingEvent: ILoggingEvent): String = {
val date = new SimpleDateFormat(DateFormatString).format(new Date(loggingEvent.getTimeStamp))
val level = StringUtils.rightPad(loggingEvent.getLevel.toString, 5)
val message = new StringBuilder(s"$date [$level] - ${loggingEvent.getMessage}$newline")
logContext(message, loggingEvent)
Option(loggingEvent.getCallerData) foreach { stacktrace =>
val stacktraceLength = stacktrace.length
if (stacktraceLength > 0) {
val location = stacktrace.head
val _ = message
.append(s"Location: ${location.getClassName}.${location.getMethodName}:${location.getLineNumber}$newline")
.append(s"Exception: ${location.toString}$newline")
if (stacktraceLength > 1) {
message.append(stacktrace.tail.filterNot { e =>
IgnoredClassesInStack.forall(ignored => !e.getClassName.startsWith(ignored))
} map {
_.toString
} mkString newline)
}
}
}
message.toString
}
private def logContext(message: StringBuilder, loggingEvent: ILoggingEvent) = {
Option(loggingEvent.getMDCPropertyMap).map(_.asScala).filter(_.nonEmpty).foreach { context =>
message.append(
context map { case (key, value) => s"$key$FieldSeparator$value" } mkString ("Context: ", " ", newline)
)
}
}
}
}