mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-21 18:08:25 +00:00
Improve logging configuration
- Log levels of specific loggers can be defined in the config file (doesn't work with env variables) - Log events of background tasks carry now additional data
This commit is contained in:
@ -10,10 +10,26 @@ import cats.data.NonEmptyList
|
||||
|
||||
import io.circe.{Decoder, Encoder}
|
||||
|
||||
final case class LogConfig(minimumLevel: Level, format: LogConfig.Format) {}
|
||||
final case class LogConfig(
|
||||
minimumLevel: Level,
|
||||
format: LogConfig.Format,
|
||||
levels: LogConfig.ExtraLevels
|
||||
) {
|
||||
|
||||
def clearLevels: LogConfig =
|
||||
copy(levels = Map.empty)
|
||||
|
||||
def withLevel(logger: String, level: Level): LogConfig =
|
||||
copy(levels = levels.updated(logger, level))
|
||||
|
||||
def docspellLevel(level: Level): LogConfig =
|
||||
withLevel("docspell", level)
|
||||
}
|
||||
|
||||
object LogConfig {
|
||||
|
||||
type ExtraLevels = Map[String, Level]
|
||||
|
||||
sealed trait Format { self: Product =>
|
||||
def name: String =
|
||||
productPrefix.toLowerCase
|
||||
@ -38,8 +54,10 @@ object LogConfig {
|
||||
}
|
||||
|
||||
implicit val jsonDecoder: Decoder[LogConfig] =
|
||||
Decoder.forProduct2("minimumLevel", "format")(LogConfig.apply)
|
||||
Decoder.forProduct3("minimumLevel", "format", "levels")(LogConfig.apply)
|
||||
|
||||
implicit val jsonEncoder: Encoder[LogConfig] =
|
||||
Encoder.forProduct2("minimumLevel", "format")(r => (r.minimumLevel, r.format))
|
||||
Encoder.forProduct3("minimumLevel", "format", "levels")(r =>
|
||||
(r.minimumLevel, r.format, r.levels)
|
||||
)
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ final case class LogEvent(
|
||||
def data[A: Encoder](key: String, value: => A): LogEvent =
|
||||
copy(data = data.updated(key, () => Encoder[A].apply(value)))
|
||||
|
||||
def addData(m: Map[String, Json]): LogEvent =
|
||||
copy(data = data ++ m.view.mapValues(json => () => json).toMap)
|
||||
|
||||
def addMessage(msg: => String): LogEvent =
|
||||
copy(additional = (() => Left(msg)) :: additional)
|
||||
|
||||
|
@ -16,40 +16,36 @@ import scribe.jul.JULHandler
|
||||
import scribe.writer.SystemOutWriter
|
||||
|
||||
object ScribeConfigure {
|
||||
private[this] val docspellRootVerbose = "DOCSPELL_ROOT_LOGGER_LEVEL"
|
||||
|
||||
def configure[F[_]: Sync](cfg: LogConfig): F[Unit] =
|
||||
Sync[F].delay {
|
||||
replaceJUL()
|
||||
val docspellLogger = scribe.Logger("docspell")
|
||||
|
||||
unsafeConfigure(scribe.Logger.root, cfg.copy(minimumLevel = getRootMinimumLevel))
|
||||
unsafeConfigure(docspellLogger, cfg)
|
||||
unsafeConfigure(scribe.Logger("org.flywaydb"), cfg)
|
||||
unsafeConfigure(scribe.Logger("binny"), cfg)
|
||||
unsafeConfigure(scribe.Logger("org.http4s"), cfg)
|
||||
unsafeConfigure(cfg)
|
||||
}
|
||||
|
||||
private[this] def getRootMinimumLevel: Level =
|
||||
Option(System.getenv(docspellRootVerbose))
|
||||
.map(Level.fromString)
|
||||
.flatMap {
|
||||
case Right(level) => Some(level)
|
||||
case Left(err) =>
|
||||
scribe.warn(
|
||||
s"Environment variable '$docspellRootVerbose' has invalid value: $err"
|
||||
)
|
||||
None
|
||||
}
|
||||
.getOrElse(Level.Error)
|
||||
def unsafeConfigure(cfg: LogConfig): Unit = {
|
||||
unsafeConfigure(scribe.Logger.root, cfg.format, cfg.minimumLevel)
|
||||
cfg.levels.foreach { case (name, level) =>
|
||||
unsafeConfigure(scribe.Logger(name), cfg.format, level)
|
||||
}
|
||||
}
|
||||
|
||||
def unsafeConfigure(logger: scribe.Logger, cfg: LogConfig): Unit = {
|
||||
def unsafeConfigure(logger: String, cfg: LogConfig): Unit = {
|
||||
val log = scribe.Logger(logger)
|
||||
val level = cfg.levels.getOrElse(logger, cfg.minimumLevel)
|
||||
unsafeConfigure(log, cfg.format, level)
|
||||
}
|
||||
|
||||
def unsafeConfigure(
|
||||
logger: scribe.Logger,
|
||||
format: LogConfig.Format,
|
||||
level: Level
|
||||
): Unit = {
|
||||
val mods = List[scribe.Logger => scribe.Logger](
|
||||
_.clearHandlers(),
|
||||
_.withMinimumLevel(ScribeWrapper.convertLevel(cfg.minimumLevel)),
|
||||
_.withMinimumLevel(ScribeWrapper.convertLevel(level)),
|
||||
l =>
|
||||
if (logger.id == scribe.Logger.RootId) {
|
||||
cfg.format match {
|
||||
format match {
|
||||
case Format.Fancy =>
|
||||
l.withHandler(formatter = Formatter.enhanced, writer = SystemOutWriter)
|
||||
case Format.Plain =>
|
||||
|
@ -11,16 +11,13 @@ import docspell.logging.impl.ScribeConfigure
|
||||
import munit.Suite
|
||||
|
||||
trait TestLoggingConfig extends Suite {
|
||||
def docspellLogConfig: LogConfig = LogConfig(Level.Warn, LogConfig.Format.Fancy)
|
||||
def docspellLogConfig: LogConfig =
|
||||
LogConfig(rootMinimumLevel, LogConfig.Format.Fancy, Map.empty)
|
||||
|
||||
def rootMinimumLevel: Level = Level.Error
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
val docspellLogger = scribe.Logger("docspell")
|
||||
ScribeConfigure.unsafeConfigure(docspellLogger, docspellLogConfig)
|
||||
val rootCfg = docspellLogConfig.copy(minimumLevel = rootMinimumLevel)
|
||||
ScribeConfigure.unsafeConfigure(scribe.Logger.root, rootCfg)
|
||||
()
|
||||
ScribeConfigure.unsafeConfigure(docspellLogConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user