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.
This commit is contained in:
Jonathan Bernard 2022-11-03 15:03:48 -05:00
parent 8245cfbdf7
commit c0f818ef30
2 changed files with 20 additions and 9 deletions

View File

@ -1,6 +1,6 @@
# Package
version = "0.2.0"
version = "0.3.0"
author = "Jonathan Bernard"
description = "Wrapper around std/logging to provide namespaced logging."
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
LoggingNamespace* = ref object
@ -15,7 +15,7 @@ template knownNamespaces(): TableRef[string, LoggingNamespace] =
knownNamespacesInst = newTable[string, LoggingNamespace]()
knownNamespacesInst
proc initLoggingNamespace*(name: string, level = lvlInfo, msgPrefix: string): LoggingNamespace =
proc initLoggingNamespace(name: string, level = lvlInfo, msgPrefix: string): LoggingNamespace =
result = LoggingNamespace(
name: name,
level: level,
@ -23,19 +23,30 @@ proc initLoggingNamespace*(name: string, level = lvlInfo, msgPrefix: string): Lo
knownNamespaces[name] = result
proc initLoggingNamespace*(name: string, level = lvlInfo): LoggingNamespace =
return initLoggingNamespace(name, level, name & ": ")
proc getLoggerForNamespace*(
namespace: string,
level = lvlInfo,
msgPrefix: Option[string] = none[string]()
): LoggingNamespace =
## 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): return knownNamespaces[namespace]
else: return initLoggingNamespace(namespace, level)
else:
if msgPrefix.isSome:
return initLoggingNamespace(namespace, level, msgPrefix.get)
else:
return initLoggingNamespace(namespace, level, namespace)
proc setLevelForNamespace*(namespace: string, lvl: Level, recursive = false) =
if recursive:
for k, v in knownNamespaces.pairs:
if k.startsWith(namespace):
v.level = lvl
elif knownNamespaces.hasKey(namespace): knownNamespaces[namespace].level = lvl
else: getLoggerForNamespace(namespace).level = lvl
proc name*(ns: LoggingNamespace): string = ns.name
proc log*(ns: LoggingNamespace, level: Level, args: varargs[string, `$`]) =