LSSTApplications  20.0.0
LSSTDataManagementBasePackage
logContinued.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 #
4 # LSST Data Management System
5 # Copyright 2013 LSST Corporation.
6 #
7 # This product includes software developed by the
8 # LSST Project (http://www.lsst.org/).
9 #
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the LSST License Statement and
21 # the GNU General Public License along with this program. If not,
22 # see <http://www.lsstcorp.org/LegalNotices/>.
23 #
24 
25 __all__ = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",
26  "Log", "configure", "configure_prop", "getDefaultLogger", "getLogger",
27  "MDC", "MDCRemove", "MDCRegisterInit", "setLevel", "getLevel", "isEnabledFor",
28  "log", "trace", "debug", "info", "warn", "warning", "error", "fatal", "logf",
29  "tracef", "debugf", "infof", "warnf", "errorf", "fatalf", "lwpID",
30  "usePythonLogging", "doNotUsePythonLogging", "UsePythonLogging",
31  "LevelTranslator", "LogHandler"]
32 
33 import logging
34 import inspect
35 import os
36 
37 from lsst.utils import continueClass
38 
39 from .log import Log
40 
41 TRACE = 5000
42 DEBUG = 10000
43 INFO = 20000
44 WARN = 30000
45 ERROR = 40000
46 FATAL = 50000
47 
48 
49 @continueClass # noqa F811 redefinition
50 class Log:
51  UsePythonLogging = False
52  """Forward Python `lsst.log` messages to Python `logging` package."""
53 
54  @classmethod
55  def usePythonLogging(cls):
56  """Forward log messages to Python `logging`
57 
58  Notes
59  -----
60  This is useful for unit testing when you want to ensure
61  that log messages are captured by the testing environment
62  as distinct from standard output.
63 
64  This state only affects messages sent to the `lsst.log`
65  package from Python.
66  """
67  cls.UsePythonLogging = True
68 
69  @classmethod
71  """Forward log messages to LSST logging system.
72 
73  Notes
74  -----
75  This is the default state.
76  """
77  cls.UsePythonLogging = False
78 
79  def trace(self, fmt, *args):
80  self._log(Log.TRACE, False, fmt, *args)
81 
82  def debug(self, fmt, *args):
83  self._log(Log.DEBUG, False, fmt, *args)
84 
85  def info(self, fmt, *args):
86  self._log(Log.INFO, False, fmt, *args)
87 
88  def warn(self, fmt, *args):
89  self._log(Log.WARN, False, fmt, *args)
90 
91  def warning(self, fmt, *args):
92  self.warn(fmt, *args)
93 
94  def error(self, fmt, *args):
95  self._log(Log.ERROR, False, fmt, *args)
96 
97  def fatal(self, fmt, *args):
98  self._log(Log.FATAL, False, fmt, *args)
99 
100  def tracef(self, fmt, *args, **kwargs):
101  self._log(Log.TRACE, True, fmt, *args, **kwargs)
102 
103  def debugf(self, fmt, *args, **kwargs):
104  self._log(Log.DEBUG, True, fmt, *args, **kwargs)
105 
106  def infof(self, fmt, *args, **kwargs):
107  self._log(Log.INFO, True, fmt, *args, **kwargs)
108 
109  def warnf(self, fmt, *args, **kwargs):
110  self._log(Log.WARN, True, fmt, *args, **kwargs)
111 
112  def errorf(self, fmt, *args, **kwargs):
113  self._log(Log.ERROR, True, fmt, *args, **kwargs)
114 
115  def fatalf(self, fmt, *args, **kwargs):
116  self._log(Log.FATAL, True, fmt, *args, **kwargs)
117 
118  def _log(self, level, use_format, fmt, *args, **kwargs):
119  if self.isEnabledFor(level):
120  frame = inspect.currentframe().f_back # calling method
121  frame = frame.f_back # original log location
122  filename = os.path.split(frame.f_code.co_filename)[1]
123  funcname = frame.f_code.co_name
124  if use_format:
125  msg = fmt.format(*args, **kwargs) if args or kwargs else fmt
126  else:
127  msg = fmt % args if args else fmt
128  if self.UsePythonLogging:
129  pylog = logging.getLogger(self.getName())
130  record = logging.LogRecord(self.getName(), LevelTranslator.lsstLog2logging(level),
131  filename, frame.f_lineno, msg, None, False, func=funcname)
132  pylog.handle(record)
133  else:
134  self.logMsg(level, filename, funcname, frame.f_lineno, msg)
135 
136  def __reduce__(self):
137  """Implement pickle support.
138  """
139  args = (self.getName(), )
140  # method has to be module-level, not class method
141  return (getLogger, args)
142 
143 # Export static functions from Log class to module namespace
144 
145 
146 def configure(*args):
147  Log.configure(*args)
148 
149 
150 def configure_prop(properties):
151  Log.configure_prop(properties)
152 
153 
155  return Log.getDefaultLogger()
156 
157 
158 def getLogger(loggername):
159  return Log.getLogger(loggername)
160 
161 
162 def MDC(key, value):
163  Log.MDC(key, str(value))
164 
165 
166 def MDCRemove(key):
167  Log.MDCRemove(key)
168 
169 
170 def MDCRegisterInit(func):
171  Log.MDCRegisterInit(func)
172 
173 
174 def setLevel(loggername, level):
175  Log.getLogger(loggername).setLevel(level)
176 
177 
178 def getLevel(loggername):
179  Log.getLogger(loggername).getLevel()
180 
181 
182 def isEnabledFor(logger, level):
183  Log.getLogger(logger).isEnabledFor(level)
184 
185 
186 def log(loggername, level, fmt, *args, **kwargs):
187  Log.getLogger(loggername)._log(level, False, fmt, *args)
188 
189 
190 def trace(fmt, *args):
191  Log.getDefaultLogger()._log(TRACE, False, fmt, *args)
192 
193 
194 def debug(fmt, *args):
195  Log.getDefaultLogger()._log(DEBUG, False, fmt, *args)
196 
197 
198 def info(fmt, *args):
199  Log.getDefaultLogger()._log(INFO, False, fmt, *args)
200 
201 
202 def warn(fmt, *args):
203  Log.getDefaultLogger()._log(WARN, False, fmt, *args)
204 
205 
206 def warning(fmt, *args):
207  warn(fmt, *args)
208 
209 
210 def error(fmt, *args):
211  Log.getDefaultLogger()._log(ERROR, False, fmt, *args)
212 
213 
214 def fatal(fmt, *args):
215  Log.getDefaultLogger()._log(FATAL, False, fmt, *args)
216 
217 
218 def logf(loggername, level, fmt, *args, **kwargs):
219  Log.getLogger(loggername)._log(level, True, fmt, *args, **kwargs)
220 
221 
222 def tracef(fmt, *args, **kwargs):
223  Log.getDefaultLogger()._log(TRACE, True, fmt, *args, **kwargs)
224 
225 
226 def debugf(fmt, *args, **kwargs):
227  Log.getDefaultLogger()._log(DEBUG, True, fmt, *args, **kwargs)
228 
229 
230 def infof(fmt, *args, **kwargs):
231  Log.getDefaultLogger()._log(INFO, True, fmt, *args, **kwargs)
232 
233 
234 def warnf(fmt, *args, **kwargs):
235  Log.getDefaultLogger()._log(WARN, True, fmt, *args, **kwargs)
236 
237 
238 def errorf(fmt, *args, **kwargs):
239  Log.getDefaultLogger()._log(ERROR, True, fmt, *args, **kwargs)
240 
241 
242 def fatalf(fmt, *args, **kwargs):
243  Log.getDefaultLogger()._log(FATAL, True, fmt, *args, **kwargs)
244 
245 
246 def lwpID():
247  return Log.lwpID
248 
249 
251  Log.usePythonLogging()
252 
253 
255  Log.doNotUsePythonLogging()
256 
257 
259  """Context manager to enable Python log forwarding temporarily.
260  """
261 
262  def __init__(self):
263  self.current = Log.UsePythonLogging
264 
265  def __enter__(self):
266  Log.usePythonLogging()
267 
268  def __exit__(self, exc_type, exc_value, traceback):
269  Log.UsePythonLogging = self.current
270 
271 
273  """Helper class to translate levels between ``lsst.log`` and Python
274  `logging`.
275  """
276  @staticmethod
277  def lsstLog2logging(level):
278  """Translates from lsst.log/log4cxx levels to `logging` module levels.
279 
280  Parameters
281  ----------
282  level : `int`
283  Logging level number used by `lsst.log`, typically one of the
284  constants defined in this module (`DEBUG`, `INFO`, etc.)
285 
286  Returns
287  -------
288  level : `int`
289  Correspoding logging level number for Python `logging` module.
290  """
291  # Python logging levels are same as lsst.log divided by 1000,
292  # logging does not have TRACE level by default but it is OK to use
293  # that numeric level and we may even add TRACE later.
294  return level//1000
295 
296  @staticmethod
297  def logging2lsstLog(level):
298  """Translates from standard python `logging` module levels to
299  lsst.log/log4cxx levels.
300 
301  Parameters
302  ----------
303  level : `int`
304  Logging level number used by Python `logging`, typically one of
305  the constants defined by `logging` module (`logging.DEBUG`,
306  `logging.INFO`, etc.)
307 
308  Returns
309  -------
310  level : `int`
311  Correspoding logging level number for `lsst.log` module.
312  """
313  return level*1000
314 
315 
316 class LogHandler(logging.Handler):
317  """Handler for Python logging module that emits to LSST logging.
318 
319  Parameters
320  ---------
321  level : `int`
322  Level at which to set the this handler.
323 
324  Notes
325  -----
326  If this handler is enabled and `lsst.log` has been configured to use
327  Python `logging`, the handler will do nothing itself if any other
328  handler has been registered with the Python logger. If it does not
329  think that anything else is handling the message it will attempt to
330  send the message via a default `~logging.StreamHandler`. The safest
331  approach is to configure the logger with an additional handler
332  (possibly the ROOT logger) if `lsst.log` is to be configured to use
333  Python logging.
334  """
335 
336  def __init__(self, level=logging.NOTSET):
337  logging.Handler.__init__(self, level=level)
338  # Format as a simple message because lsst.log will format the
339  # message a second time.
340  self.formatter = logging.Formatter(fmt="%(message)s")
341 
342  def handle(self, record):
343  logger = Log.getLogger(record.name)
344  if logger.isEnabledFor(LevelTranslator.logging2lsstLog(record.levelno)):
345  logging.Handler.handle(self, record)
346 
347  def emit(self, record):
348  if Log.UsePythonLogging:
349  # Do not forward this message to lsst.log since this may cause
350  # a logging loop.
351 
352  # Work out whether any other handler is going to be invoked
353  # for this logger.
354  pylgr = logging.getLogger(record.name)
355 
356  # If another handler is registered that is not LogHandler
357  # we ignore this request
358  if any(not isinstance(h, self.__class__) for h in pylgr.handlers):
359  return
360 
361  # If the parent has handlers and propagation is enabled
362  # we punt as well (and if a LogHandler is involved then we will
363  # ask the same question when we get to it).
364  if pylgr.parent and pylgr.parent.hasHandlers() and pylgr.propagate:
365  return
366 
367  # Force this message to appear somewhere.
368  # If something else should happen then the caller should add a
369  # second Handler.
370  stream = logging.StreamHandler()
371  stream.setFormatter(logging.Formatter(fmt="%(name)s %(levelname)s (fallback): %(message)s"))
372  stream.handle(record)
373  return
374 
375  logger = Log.getLogger(record.name)
376  # Use standard formatting class to format message part of the record
377  message = self.formatter.format(record)
378 
379  logger.logMsg(LevelTranslator.logging2lsstLog(record.levelno),
380  record.filename, record.funcName,
381  record.lineno, message)
lsst::log.log.logContinued.warnf
def warnf(fmt, *args, **kwargs)
Definition: logContinued.py:234
lsst::log.log.logContinued.logf
def logf(loggername, level, fmt, *args, **kwargs)
Definition: logContinued.py:218
lsst::log.log.logContinued.infof
def infof(fmt, *args, **kwargs)
Definition: logContinued.py:230
lsst::log.log.logContinued.UsePythonLogging
Definition: logContinued.py:258
lsst::log.log.logContinued.warn
def warn(fmt, *args)
Definition: logContinued.py:202
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:198
lsst::log.log.logContinued.error
def error(fmt, *args)
Definition: logContinued.py:210
lsst::log.log.logContinued.debugf
def debugf(fmt, *args, **kwargs)
Definition: logContinued.py:226
lsst::log.log.logContinued.Log.tracef
def tracef(self, fmt, *args, **kwargs)
Definition: logContinued.py:100
lsst::log.log.logContinued.usePythonLogging
def usePythonLogging()
Definition: logContinued.py:250
lsst::log.log.logContinued.Log.debugf
def debugf(self, fmt, *args, **kwargs)
Definition: logContinued.py:103
lsst::log.log.logContinued.Log.__reduce__
def __reduce__(self)
Definition: logContinued.py:136
lsst::log.log.logContinued.MDCRemove
def MDCRemove(key)
Definition: logContinued.py:166
lsst::log.log.logContinued.Log.infof
def infof(self, fmt, *args, **kwargs)
Definition: logContinued.py:106
pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst::log.log.logContinued.LevelTranslator.logging2lsstLog
def logging2lsstLog(level)
Definition: logContinued.py:297
lsst::log.log.logContinued.Log.UsePythonLogging
bool UsePythonLogging
Definition: logContinued.py:51
lsst::log.log.logContinued.getLevel
def getLevel(loggername)
Definition: logContinued.py:178
lsst::log.log.logContinued.Log.warnf
def warnf(self, fmt, *args, **kwargs)
Definition: logContinued.py:109
lsst::log.log.logContinued.UsePythonLogging.__init__
def __init__(self)
Definition: logContinued.py:262
lsst::log.log.logContinued.tracef
def tracef(fmt, *args, **kwargs)
Definition: logContinued.py:222
lsst::log.log.logContinued.LogHandler.formatter
formatter
Definition: logContinued.py:340
lsst::log.log.logContinued.UsePythonLogging.current
current
Definition: logContinued.py:263
lsst::log.log.logContinued.Log.debug
def debug(self, fmt, *args)
Definition: logContinued.py:82
lsst::log.log.logContinued.lwpID
def lwpID()
Definition: logContinued.py:246
lsst::log.log.logContinued.Log.warn
def warn(self, fmt, *args)
Definition: logContinued.py:88
lsst::log.log.logContinued.Log
Definition: logContinued.py:50
lsst::log.log.logContinued.Log.info
def info(self, fmt, *args)
Definition: logContinued.py:85
lsst::log.log.logContinued.Log._log
def _log(self, level, use_format, fmt, *args, **kwargs)
Definition: logContinued.py:118
lsst::log.log.logContinued.LogHandler.__init__
def __init__(self, level=logging.NOTSET)
Definition: logContinued.py:336
lsst::log.log.logContinued.configure
def configure(*args)
Definition: logContinued.py:146
lsst::log.log.logContinued.fatal
def fatal(fmt, *args)
Definition: logContinued.py:214
lsst::log.log.logContinued.Log.fatalf
def fatalf(self, fmt, *args, **kwargs)
Definition: logContinued.py:115
lsst::log.log.logContinued.errorf
def errorf(fmt, *args, **kwargs)
Definition: logContinued.py:238
lsst::log.log.logContinued.MDC
def MDC(key, value)
Definition: logContinued.py:162
lsst::log.log.logContinued.warning
def warning(fmt, *args)
Definition: logContinued.py:206
lsst::log.log.logContinued.Log.fatal
def fatal(self, fmt, *args)
Definition: logContinued.py:97
lsst::geom::any
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
Definition: CoordinateExpr.h:89
lsst::log.log.logContinued.configure_prop
def configure_prop(properties)
Definition: logContinued.py:150
lsst::utils
Definition: Backtrace.h:29
lsst::log.log.logContinued.Log.warning
def warning(self, fmt, *args)
Definition: logContinued.py:91
lsst::log.log.logContinued.LevelTranslator
Definition: logContinued.py:272
lsst::log.log.logContinued.LevelTranslator.lsstLog2logging
def lsstLog2logging(level)
Definition: logContinued.py:277
lsst::log.log.logContinued.Log.error
def error(self, fmt, *args)
Definition: logContinued.py:94
lsst::log.log.logContinued.trace
def trace(fmt, *args)
Definition: logContinued.py:190
lsst::log.log.logContinued.debug
def debug(fmt, *args)
Definition: logContinued.py:194
lsst::log.log.logContinued.getDefaultLogger
def getDefaultLogger()
Definition: logContinued.py:154
lsst::log.log.logContinued.Log.errorf
def errorf(self, fmt, *args, **kwargs)
Definition: logContinued.py:112
lsst::log.log.logContinued.fatalf
def fatalf(fmt, *args, **kwargs)
Definition: logContinued.py:242
lsst::log.log.logContinued.isEnabledFor
def isEnabledFor(logger, level)
Definition: logContinued.py:182
lsst::log.log.logContinued.doNotUsePythonLogging
def doNotUsePythonLogging()
Definition: logContinued.py:254
lsst::log.log.logContinued.getLogger
def getLogger(loggername)
Definition: logContinued.py:158
lsst::log.log.logContinued.log
def log(loggername, level, fmt, *args, **kwargs)
Definition: logContinued.py:186
lsst::log.log.logContinued.setLevel
def setLevel(loggername, level)
Definition: logContinued.py:174
lsst::log.log.logContinued.LogHandler.handle
def handle(self, record)
Definition: logContinued.py:342
lsst::log.log.logContinued.UsePythonLogging.__enter__
def __enter__(self)
Definition: logContinued.py:265
lsst::log.log.logContinued.Log.trace
def trace(self, fmt, *args)
Definition: logContinued.py:79
lsst::log.log.logContinued.UsePythonLogging.__exit__
def __exit__(self, exc_type, exc_value, traceback)
Definition: logContinued.py:268
lsst::log.log.logContinued.Log.doNotUsePythonLogging
def doNotUsePythonLogging(cls)
Definition: logContinued.py:70
lsst::log.log.logContinued.Log.usePythonLogging
def usePythonLogging(cls)
Definition: logContinued.py:55
lsst::log.log.logContinued.LogHandler.emit
def emit(self, record)
Definition: logContinued.py:347
lsst::log.log.logContinued.LogHandler
Definition: logContinued.py:316
lsst::log.log.logContinued.MDCRegisterInit
def MDCRegisterInit(func)
Definition: logContinued.py:170