From 6451d26c91550472dc3d9d97ee84e7d4a1a61840 Mon Sep 17 00:00:00 2001 From: Alon Bar-Lev Date: Wed, 30 Apr 2025 17:40:03 +0300 Subject: [PATCH 1/2] logging: Support extra context for LogRecord. Extra context is usable to enrich log record with concrete context additions. Signed-off-by: Alon Bar-Lev --- python-stdlib/logging/logging.py | 66 +++++++++++++++++--------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/python-stdlib/logging/logging.py b/python-stdlib/logging/logging.py index f4874df7d..059c96045 100644 --- a/python-stdlib/logging/logging.py +++ b/python-stdlib/logging/logging.py @@ -28,7 +28,7 @@ class LogRecord: - def set(self, name, level, message): + def __init__(self, name, level, message, extra=None): self.name = name self.levelno = level self.levelname = _level_dict[level] @@ -36,6 +36,11 @@ def set(self, name, level, message): self.ct = time.time() self.msecs = int((self.ct - int(self.ct)) * 1000) self.asctime = None + if extra is not None: + for key in extra: + if (key in ["message", "asctime"]) or (key in self.__dict__): + raise KeyError("Attempt to overwrite %r in LogRecord" % key) + setattr(self, key, extra[key]) class Handler: @@ -110,7 +115,6 @@ def __init__(self, name, level=NOTSET): self.name = name self.level = level self.handlers = [] - self.record = LogRecord() def setLevel(self, level): self.level = level @@ -121,36 +125,36 @@ def isEnabledFor(self, level): def getEffectiveLevel(self): return self.level or getLogger().level or _DEFAULT_LEVEL - def log(self, level, msg, *args): + def log(self, level, msg, *args, extra=None): if self.isEnabledFor(level): if args: if isinstance(args[0], dict): args = args[0] msg = msg % args - self.record.set(self.name, level, msg) + record = LogRecord(self.name, level, msg, extra) handlers = self.handlers if not handlers: handlers = getLogger().handlers for h in handlers: - h.emit(self.record) + h.emit(record) - def debug(self, msg, *args): - self.log(DEBUG, msg, *args) + def debug(self, msg, *args, **kwargs): + self.log(DEBUG, msg, *args, **kwargs) - def info(self, msg, *args): - self.log(INFO, msg, *args) + def info(self, msg, *args, **kwargs): + self.log(INFO, msg, *args, **kwargs) - def warning(self, msg, *args): - self.log(WARNING, msg, *args) + def warning(self, msg, *args, **kwargs): + self.log(WARNING, msg, *args, **kwargs) - def error(self, msg, *args): - self.log(ERROR, msg, *args) + def error(self, msg, *args, **kwargs): + self.log(ERROR, msg, *args, **kwargs) - def critical(self, msg, *args): - self.log(CRITICAL, msg, *args) + def critical(self, msg, *args, **kwargs): + self.log(CRITICAL, msg, *args, **kwargs) - def exception(self, msg, *args, exc_info=True): - self.log(ERROR, msg, *args) + def exception(self, msg, *args, exc_info=True, **kwargs): + self.log(ERROR, msg, *args, **kwargs) tb = None if isinstance(exc_info, BaseException): tb = exc_info @@ -178,32 +182,32 @@ def getLogger(name=None): return _loggers[name] -def log(level, msg, *args): - getLogger().log(level, msg, *args) +def log(level, msg, *args, **kwargs): + getLogger().log(level, msg, *args, **kwarg) -def debug(msg, *args): - getLogger().debug(msg, *args) +def debug(msg, *args, **kwargs): + getLogger().debug(msg, *args, **kwargs) -def info(msg, *args): - getLogger().info(msg, *args) +def info(msg, *args, **kwargs): + getLogger().info(msg, *args, **kwargs) -def warning(msg, *args): - getLogger().warning(msg, *args) +def warning(msg, *args, **kwargs): + getLogger().warning(msg, *args, **kwargs) -def error(msg, *args): - getLogger().error(msg, *args) +def error(msg, *args, **kwargs): + getLogger().error(msg, *args, **kwargs) -def critical(msg, *args): - getLogger().critical(msg, *args) +def critical(msg, *args, **kwargs): + getLogger().critical(msg, *args, **kwargs) -def exception(msg, *args): - getLogger().exception(msg, *args) +def exception(msg, *args, **kwargs): + getLogger().exception(msg, *args, *kwargs) def shutdown(): From 686f1ca90fc1115c1e7f1d47f397e4daa053b155 Mon Sep 17 00:00:00 2001 From: Alon Bar-Lev Date: Wed, 30 Apr 2025 17:58:29 +0300 Subject: [PATCH 2/2] logging: Move exc_info to common log. The keyword parameters are populated to common log and exc_info should be common to all methods anyway. This change the default to be exc_info=False for all cases similar to the standard python. Signed-off-by: Alon Bar-Lev --- python-stdlib/logging/logging.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/python-stdlib/logging/logging.py b/python-stdlib/logging/logging.py index 059c96045..3c2dbfda6 100644 --- a/python-stdlib/logging/logging.py +++ b/python-stdlib/logging/logging.py @@ -125,7 +125,7 @@ def isEnabledFor(self, level): def getEffectiveLevel(self): return self.level or getLogger().level or _DEFAULT_LEVEL - def log(self, level, msg, *args, extra=None): + def log(self, level, msg, *args, exc_info=False, extra=None): if self.isEnabledFor(level): if args: if isinstance(args[0], dict): @@ -138,6 +138,16 @@ def log(self, level, msg, *args, extra=None): for h in handlers: h.emit(record) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + def debug(self, msg, *args, **kwargs): self.log(DEBUG, msg, *args, **kwargs) @@ -153,17 +163,8 @@ def error(self, msg, *args, **kwargs): def critical(self, msg, *args, **kwargs): self.log(CRITICAL, msg, *args, **kwargs) - def exception(self, msg, *args, exc_info=True, **kwargs): + def exception(self, msg, *args, **kwargs): self.log(ERROR, msg, *args, **kwargs) - tb = None - if isinstance(exc_info, BaseException): - tb = exc_info - elif hasattr(sys, "exc_info"): - tb = sys.exc_info()[1] - if tb: - buf = io.StringIO() - sys.print_exception(tb, buf) - self.log(ERROR, buf.getvalue()) def addHandler(self, handler): self.handlers.append(handler)