25__all__ = [
"TRACE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL",
"CRITICAL",
"WARNING",
26 "Log",
"configure",
"configure_prop",
"configure_pylog_MDC",
"getDefaultLogger",
27 "getLogger",
"MDC",
"MDCDict",
"MDCRemove",
"MDCRegisterInit",
"setLevel",
28 "getLevel",
"isEnabledFor",
"log",
"trace",
"debug",
"info",
"warn",
"warning",
29 "error",
"fatal",
"critical",
"logf",
"tracef",
"debugf",
"infof",
"warnf",
"errorf",
"fatalf",
30 "lwpID",
"usePythonLogging",
"doNotUsePythonLogging",
"UsePythonLogging",
31 "LevelTranslator",
"LogHandler",
"getEffectiveLevel",
"getLevelName"]
37from typing
import Optional
38from deprecated.sphinx
import deprecated
58 UsePythonLogging =
False
59 """Forward Python `lsst.log` messages to Python `logging` package."""
66 """Forward log messages to Python `logging`
70 This is useful
for unit testing when you want to ensure
71 that log messages are captured by the testing environment
72 as distinct
from standard output.
74 This state only affects messages sent to the `
lsst.log`
81 """Forward log messages to LSST logging system.
85 This is the default state.
95 return self.getLevel()
99 """Returns the parent logger, or None if this is the root logger."""
102 parent_name = self.
name.rpartition(
".")[0]
104 return self.getDefaultLogger()
105 return self.getLogger(parent_name)
108 self.
_log(Log.TRACE,
False, fmt, *args)
111 self.
_log(Log.DEBUG,
False, fmt, *args)
114 self.
_log(Log.INFO,
False, fmt, *args)
117 self.
_log(Log.WARN,
False, fmt, *args)
122 self.
_log(Log.WARN,
False, fmt, *args)
125 self.
_log(Log.ERROR,
False, fmt, *args)
128 self.
_log(Log.FATAL,
False, fmt, *args)
133 self.
_log(Log.FATAL,
False, fmt, *args)
135 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
136 " Will be removed after v25",
137 version=
"v23.0", category=FutureWarning)
139 self.
_log(Log.TRACE,
True, fmt, *args, **kwargs)
141 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
142 " Will be removed after v25",
143 version=
"v23.0", category=FutureWarning)
145 self.
_log(Log.DEBUG,
True, fmt, *args, **kwargs)
147 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
148 " Will be removed after v25",
149 version=
"v23.0", category=FutureWarning)
150 def infof(self, fmt, *args, **kwargs):
151 self.
_log(Log.INFO,
True, fmt, *args, **kwargs)
153 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
154 " Will be removed after v25",
155 version=
"v23.0", category=FutureWarning)
156 def warnf(self, fmt, *args, **kwargs):
157 self.
_log(Log.WARN,
True, fmt, *args, **kwargs)
159 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
160 " Will be removed after v25",
161 version=
"v23.0", category=FutureWarning)
163 self.
_log(Log.ERROR,
True, fmt, *args, **kwargs)
165 @deprecated(reason=
"f-string log messages are now deprecated to match python logging convention."
166 " Will be removed after v25",
167 version=
"v23.0", category=FutureWarning)
169 self.
_log(Log.FATAL,
True, fmt, *args, **kwargs)
171 def _log(self, level, use_format, fmt, *args, **kwargs):
172 if self.isEnabledFor(level):
173 frame = inspect.currentframe().f_back
175 filename = os.path.split(frame.f_code.co_filename)[1]
176 funcname = frame.f_code.co_name
178 msg = fmt.format(*args, **kwargs)
if args
or kwargs
else fmt
180 msg = fmt % args
if args
else fmt
182 levelno = LevelTranslator.lsstLog2logging(level)
183 levelName = logging.getLevelName(levelno)
185 pylog = logging.getLogger(self.getName())
186 record = logging.makeLogRecord(dict(name=self.getName(),
192 pathname=frame.f_code.co_filename,
193 lineno=frame.f_lineno))
196 self.logMsg(level, filename, funcname, frame.f_lineno, msg)
199 """Implement pickle support.
201 args = (self.getName(), )
203 return (getLogger, args)
208 class_name = f
"{cls.__module__}.{cls.__qualname__}"
209 prefix =
"lsst.log.log.log"
210 if class_name.startswith(prefix):
211 class_name = class_name.replace(prefix,
"lsst.log")
212 return f
"<{class_name} '{self.name}' ({getLevelName(self.getEffectiveLevel())})>"
216 """Dictionary for MDC data.
218 This is internal
class used for better formatting of
MDC in Python
logging
219 output. It behaves like `defaultdict(str)` but overrides ``__str__``
and
220 ``__repr__`` method to produce output better suited
for logging records.
223 """Returns value for a given key or empty string for missing key.
225 return self.get(name,
"")
228 """Return string representation, strings are interpolated without
231 items = (f"{k}={self[k]}" for k
in sorted(self))
232 return "{" +
", ".join(items) +
"}"
246 Log.configure_prop(properties)
250 """Configure log4cxx to send messages to Python logging, with MDC support.
255 Name of the logging level for root log4cxx logger.
256 MDC_class : `type`, optional
257 Type of dictionary which
is added to `logging.LogRecord`
as an ``MDC``
258 attribute. Any dictionary
or ``defaultdict``-like
class can be used as
259 a type. If `
None` the `logging.LogRecord` will
not be augmented.
263 This method does two things:
265 - Configures log4cxx
with a given logging level
and a ``PyLogAppender``
266 appender
class which forwards all messages
to Python `logging`.
267 - Installs a record factory
for Python `logging` that adds ``MDC``
268 attribute to every `logging.LogRecord` object (instance of
269 ``MDC_class``). This will happen by default but can be disabled
270 by setting the ``MDC_class`` parameter to `
None`.
272 if MDC_class
is not None:
273 old_factory = logging.getLogRecordFactory()
275 def record_factory(*args, **kwargs):
276 record = old_factory(*args, **kwargs)
277 record.MDC = MDC_class()
280 logging.setLogRecordFactory(record_factory)
283log4j.rootLogger = {}, PyLog
284log4j.appender.PyLog = PyLogAppender
290 return Log.getDefaultLogger()
293def getLogger(loggername):
294 return Log.getLogger(loggername)
298 return Log.MDC(key,
str(value))
306 Log.MDCRegisterInit(func)
310 Log.getLogger(loggername).
setLevel(level)
314 return Log.getLogger(loggername).
getLevel()
328def log(loggername, level, fmt, *args, **kwargs):
329 Log.getLogger(loggername)._log(level,
False, fmt, *args)
333 Log.getDefaultLogger()._log(TRACE,
False, fmt, *args)
337 Log.getDefaultLogger()._log(DEBUG,
False, fmt, *args)
341 Log.getDefaultLogger()._log(INFO,
False, fmt, *args)
345 Log.getDefaultLogger()._log(WARN,
False, fmt, *args)
353 Log.getDefaultLogger()._log(ERROR,
False, fmt, *args)
357 Log.getDefaultLogger()._log(FATAL,
False, fmt, *args)
364def logf(loggername, level, fmt, *args, **kwargs):
365 Log.getLogger(loggername)._log(level,
True, fmt, *args, **kwargs)
369 Log.getDefaultLogger()._log(TRACE,
True, fmt, *args, **kwargs)
373 Log.getDefaultLogger()._log(DEBUG,
True, fmt, *args, **kwargs)
377 Log.getDefaultLogger()._log(INFO,
True, fmt, *args, **kwargs)
381 Log.getDefaultLogger()._log(WARN,
True, fmt, *args, **kwargs)
385 Log.getDefaultLogger()._log(ERROR,
True, fmt, *args, **kwargs)
389 Log.getDefaultLogger()._log(FATAL,
True, fmt, *args, **kwargs)
397 """Return the name associated with this logging level.
399 Returns "Level %d" if no name can be found.
401 names = ("DEBUG",
"TRACE",
"WARNING",
"FATAL",
"INFO",
"ERROR")
403 test_level = getattr(Log, name)
404 if test_level == level:
406 return f
"Level {level}"
414 Log.usePythonLogging()
418 Log.doNotUsePythonLogging()
422 """Context manager to enable Python log forwarding temporarily.
429 Log.usePythonLogging()
431 def __exit__(self, exc_type, exc_value, traceback):
432 Log.UsePythonLogging = self.
current
436 """Helper class to translate levels between ``lsst.log`` and Python
441 """Translates from lsst.log/log4cxx levels to `logging` module levels.
446 Logging level number used by `lsst.log`, typically one of the
447 constants defined in this module (`DEBUG`, `INFO`, etc.)
452 Correspoding logging level number
for Python `logging` module.
461 """Translates from standard python `logging` module levels to
467 Logging level number used by Python `logging`, typically one of
468 the constants defined by `logging` module (`logging.DEBUG`,
469 `logging.INFO`, etc.)
474 Correspoding logging level number for `
lsst.log` module.
480 """Handler for Python logging module that emits to LSST logging.
485 Level at which to set the this handler.
489 If this handler is enabled
and `
lsst.log` has been configured to use
490 Python `logging`, the handler will do nothing itself
if any other
491 handler has been registered
with the Python logger. If it does
not
492 think that anything
else is handling the message it will attempt to
493 send the message via a default `~logging.StreamHandler`. The safest
494 approach
is to configure the logger
with an additional handler
495 (possibly the ROOT logger)
if `
lsst.log`
is to be configured to use
500 logging.Handler.__init__(self, level=level)
506 logger = Log.getLogger(record.name)
507 if logger.isEnabledFor(LevelTranslator.logging2lsstLog(record.levelno)):
508 logging.Handler.handle(self, record)
511 if Log.UsePythonLogging:
517 pylgr = logging.getLogger(record.name)
521 if any(
not isinstance(h, self.__class__)
for h
in pylgr.handlers):
527 if pylgr.parent
and pylgr.parent.hasHandlers()
and pylgr.propagate:
533 stream = logging.StreamHandler()
534 stream.setFormatter(logging.Formatter(fmt=
"%(name)s %(levelname)s (fallback): %(message)s"))
535 stream.handle(record)
538 logger = Log.getLogger(record.name)
542 logger.logMsg(LevelTranslator.logging2lsstLog(record.levelno),
543 record.filename, record.funcName,
544 record.lineno, message)
table::Key< std::string > name
def logging2lsstLog(level)
def lsstLog2logging(level)
def __init__(self, level=logging.NOTSET)
def fatal(self, fmt, *args)
def trace(self, fmt, *args)
def debugf(self, fmt, *args, **kwargs)
def warn(self, fmt, *args)
def tracef(self, fmt, *args, **kwargs)
def error(self, fmt, *args)
def warning(self, fmt, *args)
def infof(self, fmt, *args, **kwargs)
def critical(self, fmt, *args)
def _log(self, level, use_format, fmt, *args, **kwargs)
def errorf(self, fmt, *args, **kwargs)
def debug(self, fmt, *args)
def info(self, fmt, *args)
def fatalf(self, fmt, *args, **kwargs)
def warnf(self, fmt, *args, **kwargs)
def __getitem__(self, str name)
def __exit__(self, exc_type, exc_value, traceback)
def doNotUsePythonLogging()
def isEnabledFor(loggername, level)
def MDCRegisterInit(func)
def setLevel(loggername, level)
def fatalf(fmt, *args, **kwargs)
def tracef(fmt, *args, **kwargs)
def logf(loggername, level, fmt, *args, **kwargs)
def debugf(fmt, *args, **kwargs)
def configure_pylog_MDC(str level, Optional[type] MDC_class=MDCDict)
def infof(fmt, *args, **kwargs)
def warnf(fmt, *args, **kwargs)
def errorf(fmt, *args, **kwargs)
def configure_prop(properties)
def getEffectiveLevel(loggername)