LSSTApplications  19.0.0-14-gb0260a2+6327455aeb,20.0.0+44dbdb3492,20.0.0+8a208d85ec,20.0.0+914fcaec49,20.0.0+a571b09ef0,20.0.0+f15d39cacd,20.0.0-1-g253301a+8a208d85ec,20.0.0-1-g5b95a8c+351e15424a,20.0.0-16-g760a3dc6+7dead9ab29,20.0.0-18-gcabc0c9fd+54cb7ade16,20.0.0-2-g4dae9ad+8a636d8bd2,20.0.0-2-g61b8584+b4ab3064f8,20.0.0-2-ga51b5d4+1f4ba438e8,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+3033df31e9,20.0.0-2-gf072044+8a208d85ec,20.0.0-2-gf1f7952+8a636d8bd2,20.0.0-22-g54e2caa+8bd7be2b67,20.0.0-25-g5eafb0f+8a636d8bd2,20.0.0-28-g73474ed+df2822652a,20.0.0-29-g1235a2f+94e05d8818,20.0.0-3-g8f21e14+2bd63a3b42,20.0.0-3-gbd60e8c+ffb20d0b0d,20.0.0-3-gbecbe05+7f0063ada4,20.0.0-4-g4bc9b9f+5be46ab906,20.0.0-4-g97dc21a+df2822652a,20.0.0-4-gb4befbc+928dca1c48,20.0.0-4-gf910f65+b4ab3064f8,20.0.0-42-g74ec3ae9+afa8208526,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g4aa86cc+9b37c72498,20.0.0-6-g9a5b7a1+9aa0dcac42,20.0.0-6-gd222c45+7040a8a6f6,20.0.0-73-gf477d90+d0de1c7e9f,20.0.0-9-g4aef684+2aec92f563,20.0.0-9-g5051ac2+d529cf1a41,w.2020.47
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 (FIXME: remove for py 3.8+)
50 class Log: # noqa: F811
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 # This will cause a warning in Sphinx documentation due to confusion between
187 # Log and log. https://github.com/astropy/sphinx-automodapi/issues/73 (but
188 # note that this does not seem to be Mac-only).
189 def log(loggername, level, fmt, *args, **kwargs):
190  Log.getLogger(loggername)._log(level, False, fmt, *args)
191 
192 
193 def trace(fmt, *args):
194  Log.getDefaultLogger()._log(TRACE, False, fmt, *args)
195 
196 
197 def debug(fmt, *args):
198  Log.getDefaultLogger()._log(DEBUG, False, fmt, *args)
199 
200 
201 def info(fmt, *args):
202  Log.getDefaultLogger()._log(INFO, False, fmt, *args)
203 
204 
205 def warn(fmt, *args):
206  Log.getDefaultLogger()._log(WARN, False, fmt, *args)
207 
208 
209 def warning(fmt, *args):
210  warn(fmt, *args)
211 
212 
213 def error(fmt, *args):
214  Log.getDefaultLogger()._log(ERROR, False, fmt, *args)
215 
216 
217 def fatal(fmt, *args):
218  Log.getDefaultLogger()._log(FATAL, False, fmt, *args)
219 
220 
221 def logf(loggername, level, fmt, *args, **kwargs):
222  Log.getLogger(loggername)._log(level, True, fmt, *args, **kwargs)
223 
224 
225 def tracef(fmt, *args, **kwargs):
226  Log.getDefaultLogger()._log(TRACE, True, fmt, *args, **kwargs)
227 
228 
229 def debugf(fmt, *args, **kwargs):
230  Log.getDefaultLogger()._log(DEBUG, True, fmt, *args, **kwargs)
231 
232 
233 def infof(fmt, *args, **kwargs):
234  Log.getDefaultLogger()._log(INFO, True, fmt, *args, **kwargs)
235 
236 
237 def warnf(fmt, *args, **kwargs):
238  Log.getDefaultLogger()._log(WARN, True, fmt, *args, **kwargs)
239 
240 
241 def errorf(fmt, *args, **kwargs):
242  Log.getDefaultLogger()._log(ERROR, True, fmt, *args, **kwargs)
243 
244 
245 def fatalf(fmt, *args, **kwargs):
246  Log.getDefaultLogger()._log(FATAL, True, fmt, *args, **kwargs)
247 
248 
249 def lwpID():
250  return Log.lwpID
251 
252 
253 # This will cause a warning in Sphinx documentation due to confusion between
254 # UsePythonLogging and usePythonLogging.
255 # https://github.com/astropy/sphinx-automodapi/issues/73 (but note that this
256 # does not seem to be Mac-only).
258  Log.usePythonLogging()
259 
260 
262  Log.doNotUsePythonLogging()
263 
264 
266  """Context manager to enable Python log forwarding temporarily.
267  """
268 
269  def __init__(self):
270  self.current = Log.UsePythonLogging
271 
272  def __enter__(self):
273  Log.usePythonLogging()
274 
275  def __exit__(self, exc_type, exc_value, traceback):
276  Log.UsePythonLogging = self.current
277 
278 
280  """Helper class to translate levels between ``lsst.log`` and Python
281  `logging`.
282  """
283  @staticmethod
284  def lsstLog2logging(level):
285  """Translates from lsst.log/log4cxx levels to `logging` module levels.
286 
287  Parameters
288  ----------
289  level : `int`
290  Logging level number used by `lsst.log`, typically one of the
291  constants defined in this module (`DEBUG`, `INFO`, etc.)
292 
293  Returns
294  -------
295  level : `int`
296  Correspoding logging level number for Python `logging` module.
297  """
298  # Python logging levels are same as lsst.log divided by 1000,
299  # logging does not have TRACE level by default but it is OK to use
300  # that numeric level and we may even add TRACE later.
301  return level//1000
302 
303  @staticmethod
304  def logging2lsstLog(level):
305  """Translates from standard python `logging` module levels to
306  lsst.log/log4cxx levels.
307 
308  Parameters
309  ----------
310  level : `int`
311  Logging level number used by Python `logging`, typically one of
312  the constants defined by `logging` module (`logging.DEBUG`,
313  `logging.INFO`, etc.)
314 
315  Returns
316  -------
317  level : `int`
318  Correspoding logging level number for `lsst.log` module.
319  """
320  return level*1000
321 
322 
323 class LogHandler(logging.Handler):
324  """Handler for Python logging module that emits to LSST logging.
325 
326  Parameters
327  ----------
328  level : `int`
329  Level at which to set the this handler.
330 
331  Notes
332  -----
333  If this handler is enabled and `lsst.log` has been configured to use
334  Python `logging`, the handler will do nothing itself if any other
335  handler has been registered with the Python logger. If it does not
336  think that anything else is handling the message it will attempt to
337  send the message via a default `~logging.StreamHandler`. The safest
338  approach is to configure the logger with an additional handler
339  (possibly the ROOT logger) if `lsst.log` is to be configured to use
340  Python logging.
341  """
342 
343  def __init__(self, level=logging.NOTSET):
344  logging.Handler.__init__(self, level=level)
345  # Format as a simple message because lsst.log will format the
346  # message a second time.
347  self.formatter = logging.Formatter(fmt="%(message)s")
348 
349  def handle(self, record):
350  logger = Log.getLogger(record.name)
351  if logger.isEnabledFor(LevelTranslator.logging2lsstLog(record.levelno)):
352  logging.Handler.handle(self, record)
353 
354  def emit(self, record):
355  if Log.UsePythonLogging:
356  # Do not forward this message to lsst.log since this may cause
357  # a logging loop.
358 
359  # Work out whether any other handler is going to be invoked
360  # for this logger.
361  pylgr = logging.getLogger(record.name)
362 
363  # If another handler is registered that is not LogHandler
364  # we ignore this request
365  if any(not isinstance(h, self.__class__) for h in pylgr.handlers):
366  return
367 
368  # If the parent has handlers and propagation is enabled
369  # we punt as well (and if a LogHandler is involved then we will
370  # ask the same question when we get to it).
371  if pylgr.parent and pylgr.parent.hasHandlers() and pylgr.propagate:
372  return
373 
374  # Force this message to appear somewhere.
375  # If something else should happen then the caller should add a
376  # second Handler.
377  stream = logging.StreamHandler()
378  stream.setFormatter(logging.Formatter(fmt="%(name)s %(levelname)s (fallback): %(message)s"))
379  stream.handle(record)
380  return
381 
382  logger = Log.getLogger(record.name)
383  # Use standard formatting class to format message part of the record
384  message = self.formatter.format(record)
385 
386  logger.logMsg(LevelTranslator.logging2lsstLog(record.levelno),
387  record.filename, record.funcName,
388  record.lineno, message)
lsst::log.log.logContinued.warnf
def warnf(fmt, *args, **kwargs)
Definition: logContinued.py:237
lsst::log.log.logContinued.logf
def logf(loggername, level, fmt, *args, **kwargs)
Definition: logContinued.py:221
lsst::log.log.logContinued.infof
def infof(fmt, *args, **kwargs)
Definition: logContinued.py:233
lsst::log.log.logContinued.UsePythonLogging
Definition: logContinued.py:265
lsst::log.log.logContinued.warn
def warn(fmt, *args)
Definition: logContinued.py:205
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:201
lsst::log.log.logContinued.error
def error(fmt, *args)
Definition: logContinued.py:213
lsst::log.log.logContinued.debugf
def debugf(fmt, *args, **kwargs)
Definition: logContinued.py:229
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:257
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
lsst::log.log.logContinued.LevelTranslator.logging2lsstLog
def logging2lsstLog(level)
Definition: logContinued.py:304
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.pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst::log.log.logContinued.UsePythonLogging.__init__
def __init__(self)
Definition: logContinued.py:269
lsst::log.log.logContinued.tracef
def tracef(fmt, *args, **kwargs)
Definition: logContinued.py:225
lsst::log.log.logContinued.LogHandler.formatter
formatter
Definition: logContinued.py:347
lsst::log.log.logContinued.UsePythonLogging.current
current
Definition: logContinued.py:270
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:249
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:343
lsst::log.log.logContinued.configure
def configure(*args)
Definition: logContinued.py:146
lsst::log.log.logContinued.fatal
def fatal(fmt, *args)
Definition: logContinued.py:217
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:241
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:209
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:279
lsst::log.log.logContinued.LevelTranslator.lsstLog2logging
def lsstLog2logging(level)
Definition: logContinued.py:284
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:193
lsst::log.log.logContinued.debug
def debug(fmt, *args)
Definition: logContinued.py:197
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:245
lsst::log.log.logContinued.isEnabledFor
def isEnabledFor(logger, level)
Definition: logContinued.py:182
lsst::log.log.logContinued.doNotUsePythonLogging
def doNotUsePythonLogging()
Definition: logContinued.py:261
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:189
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:349
lsst::log.log.logContinued.UsePythonLogging.__enter__
def __enter__(self)
Definition: logContinued.py:272
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:275
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:354
lsst::log.log.logContinued.LogHandler
Definition: logContinued.py:323
lsst::log.log.logContinued.MDCRegisterInit
def MDCRegisterInit(func)
Definition: logContinued.py:170