
org.log4s.log4sjs.Log4sConfig.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of log4s_sjs1_2.13 Show documentation
Show all versions of log4s_sjs1_2.13 Show documentation
High-performance SLF4J wrapper for Scala
The newest version!
package org.log4s
package log4sjs
import scala.annotation.tailrec
import scala.collection.{ mutable, immutable }
import scala.math.Ordered._
import scala.scalajs.js
import js.annotation._
/** The public interface for log configuration */
trait Log4sConfig {
def setLoggerThreshold(name: String, threshold: LogThreshold): Unit
def setLoggerThreshold(name: String, level: LogLevel): Unit
def resetLoggerThreshold(name: String): Unit
def addLoggerAppender[A: Log4sAppender.Provider](name: String, appender: A): Unit
def setLoggerAppenders[A: Log4sAppender.Provider](name: String, additive: Boolean, appenders: Seq[A]): Unit
def resetLoggerAppenders(name: String): Unit
}
object Log4sConfig extends Log4sConfig { thisConfig =>
private[this] lazy val standardAppender = new Log4sConsoleAppender
private[this] lazy val defaultAppenderSetting = AppenderSetting(Nil, true)
private[this] case class AppenderSetting(appenders: immutable.Seq[Log4sAppender.Type], additive: Boolean)
private[this] case class ConcreteLoggerState(threshold: LogThreshold, appenders: Iterable[Log4sAppender]) {
def withChild(ls: LoggerState): ConcreteLoggerState = {
val newThreshold = ls.threshold.getOrElse(threshold)
val newAppenders = {
val AppenderSetting(childAppenders, childAdditive) = ls.appenders.getOrElse(defaultAppenderSetting)
if (childAdditive) {
appenders ++ childAppenders
} else {
childAppenders
}
}
ConcreteLoggerState(newThreshold, newAppenders)
}
def isEnabled(ll: LogLevel): Boolean = {
threshold <= LevelThreshold(ll)
}
}
private[this] case class LoggerState(threshold: Option[LogThreshold] = None, appenders: Option[AppenderSetting] = None)
private[this] lazy val emptyLoggerState = LoggerState()
private[this] class Node(
val children: mutable.Map[String, Node] = mutable.Map.empty,
var state: LoggerState = emptyLoggerState)
private[this] object LoggerState {
private[this] val defaultRootState = ConcreteLoggerState(log4sjs.LogThreshold.AllThreshold, Seq(standardAppender))
private[this] val root = new Node()
def apply(parts: Seq[String]): ConcreteLoggerState = {
@inline
@tailrec
def helper(tree: collection.Map[String, Node], state: ConcreteLoggerState, path: Seq[String]): ConcreteLoggerState = {
if (path.isEmpty) {
state
} else {
tree.get(path.head) match {
case None => state
case Some(n) => helper(n.children, state.withChild(n.state), path.tail)
}
}
}
helper(root.children, defaultRootState.withChild(root.state), parts)
}
@tailrec
protected[this] def getNode(parts: Seq[String], node: Node = root): Option[Node] = {
/* This method can be written in one line as a left fold that does a `return None` in a
* `getOrElse`. However the early return is unusual and it may not perform very well to
* throw an exception in the most common case, so the tail-recursive form is fine. */
if (parts.isEmpty) {
Some(node)
} else {
node.children.get(parts.head) match {
case None => None
case Some(n2) => getNode(parts.tail, n2)
}
}
}
def get(parts: Seq[String]): LoggerState = {
getNode(parts)
.map(_.state)
.getOrElse(emptyLoggerState)
}
def update(parts: Seq[String], state: LoggerState): Unit = {
val pathNode =
parts.foldLeft(root) { (node, part) =>
node.children.getOrElseUpdate(part, new Node())
}
/* TODO: Merge settings rather than pure overwrite? */
pathNode.state = state
}
}
private[this] def logger(name: String, threshold: Option[Option[LogThreshold]] = None, appenders: Option[Option[AppenderSetting]] = None): Unit = {
val parts = LoggerParser(name)
val currentState = LoggerState.get(parts)
var updatedState = currentState
for (t <- threshold) {
updatedState = updatedState.copy(threshold = t)
}
for (a <- appenders) {
updatedState = updatedState.copy(appenders = a)
}
LoggerState.update(parts, updatedState)
}
def setLoggerThreshold(name: String, threshold: LogThreshold): Unit = {
logger(name, threshold = Some(Option(threshold)))
}
def setLoggerThreshold(name: String, level: LogLevel): Unit = {
logger(name, threshold = Some(Option(LevelThreshold(level))))
}
def setLoggerThreshold(name: String, threshold: String): Unit = {
setLoggerThreshold(name, LogThreshold.forName(threshold))
}
def resetLoggerThreshold(name: String): Unit = {
logger(name, threshold = Some(None))
}
def setLoggerAppendersDynamic(name: String, additive: Boolean, appenders: js.Array[Log4sAppender.DynamicType]): Unit = {
setLoggerAppenders(name, additive, appenders.toSeq)
}
def setLoggerAppenders[A: Log4sAppender.Provider](name: String, additive: Boolean, appenders: Seq[A]): Unit = {
val appenderSeq: immutable.Seq[Log4sAppender] = appenders.map(Log4sAppender.from(_)).toList
logger(name, appenders = Some(Some(AppenderSetting(appenderSeq, additive))))
}
/** Add an appender for a given logger */
def addLoggerAppenderDynamic(name: String, appender: Log4sAppender.DynamicType): Unit = {
addLoggerAppender(name, appender)
}
def addLoggerAppender[A: Log4sAppender.Provider](name: String, appender: A): Unit = {
val parts = LoggerParser(name)
val currentState = LoggerState.get(parts)
val currentAppenderSetting = currentState.appenders.getOrElse(AppenderSetting(Nil, true))
val newAppenderSetting = currentAppenderSetting.copy(appenders = currentAppenderSetting.appenders :+ Log4sAppender.from(appender))
val updatedState = currentState.copy(appenders = Some(newAppenderSetting))
LoggerState(parts) = updatedState
}
def resetLoggerAppenders(name: String) = {
logger(name, appenders = Some(None))
}
private[log4sjs] final def doLog(e: LoggedEvent): Unit = {
val state = LoggerState(e.loggerPath)
if (state.isEnabled(e.level)) {
for (appender <- state.appenders) {
appender.append(e)
}
}
}
private[log4sjs] final def isPathEnabled(path: Seq[String], ll: LogLevel): Boolean = {
LoggerState(path).isEnabled(ll)
}
private[log4sjs] final def isNameEnabled(name: String, ll: LogLevel): Boolean =
isPathEnabled(LoggerParser(name), ll)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy