3 Commits
0.2.0 ... 0.3.2

Author SHA1 Message Date
ab20a30434 Swallow impossible exception. 2023-02-25 14:45:05 -07:00
f3dbac0896 Fix default prefix format. 2022-11-03 15:14:43 -05:00
c0f818ef30 setLevelForNamespace now instantiates the namespace if necessary
- Hide initLoggingNamespace. getLoggerForNamespace should be used
  instead.
- setLevelForNamespace now calls getLoggerForNamespace to ensure the
  namespace exists when a caller tries to set the logging level.
  Previously it was possible to call setLevelForNamespace before the
  namespace was initialized, meaning that the setting had no effect.
  This is especially problematic for cases where a library is using
  namespaced logging with the filter set to a high level by default.
  The code using that library may want to enable debug logs, and is
  likely to call setLevelForNamespace in initialization code that runs
  prior to the library code which instantiates the namespace.
2022-11-03 15:03:48 -05:00
2 changed files with 40 additions and 16 deletions

View File

@ -1,6 +1,6 @@
# Package # Package
version = "0.2.0" version = "0.3.2"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Wrapper around std/logging to provide namespaced logging." description = "Wrapper around std/logging to provide namespaced logging."
license = "MIT" license = "MIT"

View File

@ -1,6 +1,6 @@
import logging, sequtils, strutils, tables import std/[logging, options, sequtils, strutils, tables]
export logging.Level export logging
type type
LoggingNamespace* = ref object LoggingNamespace* = ref object
@ -15,7 +15,12 @@ template knownNamespaces(): TableRef[string, LoggingNamespace] =
knownNamespacesInst = newTable[string, LoggingNamespace]() knownNamespacesInst = newTable[string, LoggingNamespace]()
knownNamespacesInst knownNamespacesInst
proc initLoggingNamespace*(name: string, level = lvlInfo, msgPrefix: string): LoggingNamespace = proc initLoggingNamespace(
name: string,
level = lvlInfo,
msgPrefix: string
): LoggingNamespace {.raises: [].} =
result = LoggingNamespace( result = LoggingNamespace(
name: name, name: name,
level: level, level: level,
@ -23,26 +28,45 @@ proc initLoggingNamespace*(name: string, level = lvlInfo, msgPrefix: string): Lo
knownNamespaces[name] = result knownNamespaces[name] = result
proc initLoggingNamespace*(name: string, level = lvlInfo): LoggingNamespace = proc getLoggerForNamespace*(
return initLoggingNamespace(name, level, name & ": ") namespace: string,
level = lvlInfo,
msgPrefix: Option[string] = none[string]()
): LoggingNamespace {.raises: [].} =
## Get a LogginNamesapce for the given namespace. The first time this is
## called for a given name space a new logger will be created. In that case,
## the optional `level` and `msgPrefix` will be used to configure the logger.
## In all other cases, these paratmers are ignored and the existing namespace
## instance is returned
proc getLoggerForNamespace*(namespace: string, level = lvlInfo): LoggingNamespace = if knownNamespaces.hasKey(namespace):
if knownNamespaces.hasKey(namespace): return knownNamespaces[namespace] try: return knownNamespaces[namespace]
else: return initLoggingNamespace(namespace, level) except KeyError:
try: error "namespaced_logging: Impossible error. " &
"knownNamespaces contains " & namespace & " but raised a KeyError " &
"trying to access it."
except: discard
else:
if msgPrefix.isSome:
return initLoggingNamespace(namespace, level, msgPrefix.get)
else:
return initLoggingNamespace(namespace, level, namespace & ": ")
proc setLevelForNamespace*(namespace: string, lvl: Level, recursive = false) = proc setLevelForNamespace*(namespace: string, lvl: Level, recursive = false) {.raises: [] .} =
if recursive: if recursive:
for k, v in knownNamespaces.pairs: for k, v in knownNamespaces.pairs:
if k.startsWith(namespace): if k.startsWith(namespace):
v.level = lvl v.level = lvl
elif knownNamespaces.hasKey(namespace): knownNamespaces[namespace].level = lvl else: getLoggerForNamespace(namespace).level = lvl
proc name*(ns: LoggingNamespace): string = ns.name proc name*(ns: LoggingNamespace): string = ns.name
proc log*(ns: LoggingNamespace, level: Level, args: varargs[string, `$`]) = proc log*(ns: LoggingNamespace, level: Level, args: varargs[string, `$`]) {.raises: [] .} =
if level >= ns.level: try:
if not ns.msgPrefix.isEmptyOrWhitespace: if level >= ns.level:
log(level, args.mapIt(ns.msgPrefix & it)) if not ns.msgPrefix.isEmptyOrWhitespace:
else: log(level, args) log(level, args.mapIt(ns.msgPrefix & it))
else: log(level, args)
except: discard
proc debug*(ns: LoggingNamespace, args: varargs[string, `$`]) = log(ns, lvlDebug, args) proc debug*(ns: LoggingNamespace, args: varargs[string, `$`]) = log(ns, lvlDebug, args)
proc info*(ns: LoggingNamespace, args: varargs[string, `$`]) = log(ns, lvlInfo, args) proc info*(ns: LoggingNamespace, args: varargs[string, `$`]) = log(ns, lvlInfo, args)