From c0f818ef3016dfd749710e2f86650f4a12d0e62b Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Thu, 3 Nov 2022 15:03:48 -0500 Subject: [PATCH] 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. --- namespaced_logging.nimble | 2 +- src/namespaced_logging.nim | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/namespaced_logging.nimble b/namespaced_logging.nimble index aae22cc..5dd3daa 100644 --- a/namespaced_logging.nimble +++ b/namespaced_logging.nimble @@ -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" diff --git a/src/namespaced_logging.nim b/src/namespaced_logging.nim index affc38b..d83eb95 100644 --- a/src/namespaced_logging.nim +++ b/src/namespaced_logging.nim @@ -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, `$`]) =