StdLoggingAppender - forward logs to std/logging
Primarily intended for use in libraries or other contexts where you want to fall back to std/logging if the application is not using or hasn't configured namespaced_logging. By default the StdLoggingAppender only logs when no namespaced_logging appenders are configured, but it can also be configured to always forward log messages, even when namespaced_logging is configured.
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
import std/[algorithm, atomics, json, locks, options, os, paths, sequtils,
|
import std/[algorithm, atomics, json, locks, options, os, paths, sequtils,
|
||||||
strutils, tables, times]
|
strutils, tables, times]
|
||||||
import timeutils
|
import timeutils
|
||||||
|
import std/logging as stdlog
|
||||||
|
|
||||||
from std/logging import Level
|
from std/logging import Level
|
||||||
export Level
|
export Level
|
||||||
@ -129,6 +130,19 @@ type
|
|||||||
formatter*: LogMessageFormatter
|
formatter*: LogMessageFormatter
|
||||||
absPath*: Path
|
absPath*: Path
|
||||||
|
|
||||||
|
StdLoggingAppender* = ref object of LogAppender
|
||||||
|
## Log appender that forwards log messages to the std/logging
|
||||||
|
## implementation. This is primarily intended for libraries and other
|
||||||
|
## situations where you expect that your code will be third-party to others
|
||||||
|
## and want to respect applications which use std/logging for log handlers
|
||||||
|
## and configuration.
|
||||||
|
|
||||||
|
fallbackOnly*: bool
|
||||||
|
## when true, only forward to std/logging where there are no appenders
|
||||||
|
## configured on the related LogService
|
||||||
|
|
||||||
|
formatter*: LogMessageFormatter
|
||||||
|
|
||||||
const UninitializedConfigVersion = low(int)
|
const UninitializedConfigVersion = low(int)
|
||||||
let JNULL = newJNull()
|
let JNULL = newJNull()
|
||||||
|
|
||||||
@ -436,6 +450,19 @@ proc addAppender*(ls: ThreadLocalLogService, appender: LogAppender) {.gcsafe.} =
|
|||||||
addAppender(ls[], appender)
|
addAppender(ls[], appender)
|
||||||
|
|
||||||
|
|
||||||
|
proc clearAppenders*(ls: var LogService) {.gcsafe.} =
|
||||||
|
## Remove all log appenders added to the global log service and refresh the
|
||||||
|
## local thread state. The updated global state will trigger other threads to
|
||||||
|
## refresh their state as well.
|
||||||
|
withLock ls.global.lock:
|
||||||
|
ls.global.appenders = @[]
|
||||||
|
ls.global.configVersion.atomicInc
|
||||||
|
|
||||||
|
|
||||||
|
proc clearAppenders*(ls: ThreadLocalLogService) {.gcsafe.} =
|
||||||
|
clearAppenders(ls[])
|
||||||
|
|
||||||
|
|
||||||
func getEffectiveThreshold(logger: Logger): Level {.gcsafe.} =
|
func getEffectiveThreshold(logger: Logger): Level {.gcsafe.} =
|
||||||
## Get the effective logging level threshold for a logger. This is the most
|
## Get the effective logging level threshold for a logger. This is the most
|
||||||
## specific level that is set for the logger or any of its parents. The root
|
## specific level that is set for the logger or any of its parents. The root
|
||||||
@ -525,8 +552,9 @@ template fatal*[L: Logger or Option[Logger], M](l: L, msg: M) =
|
|||||||
template fatal*[L: Logger or Option[Logger], M](l: L, error: ref Exception, msg: M) =
|
template fatal*[L: Logger or Option[Logger], M](l: L, error: ref Exception, msg: M) =
|
||||||
log(l, lvlFatal, error, msg)
|
log(l, lvlFatal, error, msg)
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# CustomerLogAppender Implementation
|
# CustomLogAppender Implementation
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
func initCustomLogAppender*[T](
|
func initCustomLogAppender*[T](
|
||||||
@ -536,7 +564,7 @@ func initCustomLogAppender*[T](
|
|||||||
threshold = lvlAll): CustomLogAppender[T] {.gcsafe.} =
|
threshold = lvlAll): CustomLogAppender[T] {.gcsafe.} =
|
||||||
|
|
||||||
if doLogMessage.isNil:
|
if doLogMessage.isNil:
|
||||||
debugEcho "initCustomLogAppender: doLogMessage is nil"
|
raise newException(ValueError, "initCustomLogAppender: doLogMessage is nil")
|
||||||
|
|
||||||
result = CustomLogAppender[T](
|
result = CustomLogAppender[T](
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
@ -545,8 +573,8 @@ func initCustomLogAppender*[T](
|
|||||||
state: state)
|
state: state)
|
||||||
|
|
||||||
method clone*[T](cla: CustomLogAppender[T]): LogAppender {.gcsafe.} =
|
method clone*[T](cla: CustomLogAppender[T]): LogAppender {.gcsafe.} =
|
||||||
if cla.doLogMessage.isNil:
|
assert not cla.doLogMessage.isNil,
|
||||||
debugEcho "CustomLogAppender#clone: source doLogMessage is nil"
|
"CustomLogAppender#clone: source doLogMessage is nil"
|
||||||
|
|
||||||
result = CustomLogAppender[T](
|
result = CustomLogAppender[T](
|
||||||
namespace: cla.namespace,
|
namespace: cla.namespace,
|
||||||
@ -561,7 +589,7 @@ method appendLogMessage[T](
|
|||||||
msg: LogMessage) {.gcsafe.} =
|
msg: LogMessage) {.gcsafe.} =
|
||||||
try:
|
try:
|
||||||
if cla.doLogMessage.isNil:
|
if cla.doLogMessage.isNil:
|
||||||
debugEcho "doLogMessage is nil"
|
raise newException(ValueError, "CustomLogAppender.appendLogMessage: doLogMessage is nil")
|
||||||
else: cla.doLogMessage(cla.state, msg)
|
else: cla.doLogMessage(cla.state, msg)
|
||||||
except Exception:
|
except Exception:
|
||||||
ls.global.reportLoggingError(
|
ls.global.reportLoggingError(
|
||||||
@ -819,6 +847,48 @@ method appendLogMessage(
|
|||||||
"unable to append to FileLogAppender")
|
"unable to append to FileLogAppender")
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# StdLoggingAppender Implementation
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func formatForwardedLog*(lm: LogMessage): string =
|
||||||
|
## Default formatter for the StdLoggingAppender that prepends the logger
|
||||||
|
## scope to the message before formatting the message via
|
||||||
|
## *formatSimpleTextLog*
|
||||||
|
"[" & lm.scope & "] " & formatSimpleTextLog(lm)
|
||||||
|
|
||||||
|
|
||||||
|
func initStdLoggingAppender*(
|
||||||
|
fallbackOnly = true,
|
||||||
|
formatter = formatForwardedLog,
|
||||||
|
namespace = "",
|
||||||
|
threshold = lvlAll): StdLoggingAppender =
|
||||||
|
|
||||||
|
result = StdLoggingAppender(
|
||||||
|
namespace: namespace,
|
||||||
|
threshold: threshold,
|
||||||
|
fallbackOnly: fallbackOnly,
|
||||||
|
formatter: formatter)
|
||||||
|
|
||||||
|
|
||||||
|
method clone*(sla: StdLoggingAppender): LogAppender {.gcsafe.} =
|
||||||
|
result = StdLoggingAppender(
|
||||||
|
namespace: sla.namespace,
|
||||||
|
threshold: sla.threshold,
|
||||||
|
fallbackOnly: sla.fallbackOnly,
|
||||||
|
formatter: sla.formatter)
|
||||||
|
|
||||||
|
|
||||||
|
method appendLogMessage*(
|
||||||
|
sla: StdLoggingAppender,
|
||||||
|
ls: ThreadLocalLogService,
|
||||||
|
msg: LogMessage) {.gcsafe.} =
|
||||||
|
|
||||||
|
if sla.fallbackOnly and ls.appenders.len > 1: return
|
||||||
|
|
||||||
|
stdlog.log(msg.level, sla.formatter(msg))
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Autoconfiguration Implementation
|
# Autoconfiguration Implementation
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user