summaryrefslogtreecommitdiff
path: root/lib/taurus/core/util/log.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/taurus/core/util/log.py')
-rw-r--r--lib/taurus/core/util/log.py894
1 files changed, 894 insertions, 0 deletions
diff --git a/lib/taurus/core/util/log.py b/lib/taurus/core/util/log.py
new file mode 100644
index 00000000..aa98e871
--- /dev/null
+++ b/lib/taurus/core/util/log.py
@@ -0,0 +1,894 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## This file is part of Taurus
+##
+## http://taurus-scada.org
+##
+## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## Taurus is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Taurus is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with Taurus. If not, see <http://www.gnu.org/licenses/>.
+##
+#############################################################################
+
+"""This module contains a set of useful logging elements based on python's
+:mod:`logging` system."""
+
+__all__ = ["LogIt", "TraceIt", "DebugIt", "InfoIt", "WarnIt", "ErrorIt",
+ "CriticalIt", "MemoryLogHandler", "LogExceptHook", "Logger",
+ "LogFilter",
+ "_log", "trace", "debug", "info", "warning", "error", "fatal",
+ "critical"]
+
+__docformat__ = "restructuredtext"
+
+import os
+import sys
+import logging.handlers
+import weakref
+import warnings
+import traceback
+import inspect
+import threading
+
+from object import Object
+from wrap import wraps
+from excepthook import BaseExceptHook
+
+TRACE = 5
+logging.addLevelName(TRACE, "TRACE")
+
+#
+# _srcfile is used when walking the stack to check when we've got the first
+# caller stack frame.
+#
+if hasattr(sys, 'frozen'): #support for py2exe
+ _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])
+elif __file__[-4:].lower() in ['.pyc', '.pyo']:
+ _srcfile = __file__[:-4] + '.py'
+else:
+ _srcfile = __file__
+_srcfile = os.path.normcase(_srcfile)
+
+# next bit filched from 1.5.2's inspect.py
+def currentframe():
+ """Return the frame object for the caller's stack frame."""
+ try:
+ raise Exception
+ except:
+ return sys.exc_info()[2].tb_frame.f_back
+
+if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
+# done filching
+
+
+class LogIt(object):
+ """A function designed to be a decorator of any method of a Logger subclass.
+ The idea is to log the entrance and exit of any decorated method of a Logger
+ subclass.
+ Example::
+
+ from taurus.core.util.log import Logger, LogIt
+
+ class Example(Logger):
+
+ @LogIt(Logger.Debug)
+ def go(self):
+ print "Hello world "
+
+ This will generate two log messages of Debug level, one before the function
+ go is called and another when go finishes. Example output::
+
+ MainThread DEBUG 2010-11-15 15:36:11,440 Example: -> go
+ Hello world of mine
+ MainThread DEBUG 2010-11-15 15:36:11,441 Example: <- go
+
+ This decorator can receive two optional arguments **showargs** and **showret**
+ which are set to False by default. Enabling them will had verbose infomation
+ about the parameters and return value. The following example::
+
+ from taurus.core.uti.log import Logger, LogIt
+
+ class Example(Logger):
+
+ @LogIt(Logger.Debug, showargs=True, showret=True)
+ def go(self, msg):
+ msg = "Hello world",msg
+ print msg
+ return msg
+
+ would generate an output like::
+
+ MainThread DEBUG 2010-11-15 15:42:02,353 Example: -> go('of mine',)
+ Hello world of mine
+ MainThread DEBUG 2010-11-15 15:42:02,353 Example: <- go = Hello world of mine
+
+ .. note::
+ it may happen that in these examples that the output of the method
+ appears before or after the log messages. This is because log
+ messages are, by default, written to the *stardard error* while the print
+ message inside the go method outputs to the *standard ouput*. On many
+ systems these two targets are not synchronized.
+ """
+
+ def __init__(self, level=logging.DEBUG, showargs=False, showret=False, col_limit=0):
+ self._level = level
+ self._showargs = showargs
+ self._showret = showret
+ self._col_limit = col_limit
+
+ def __call__(self, f):
+ @wraps(f)
+ def wrapper(*args, **kwargs):
+ f_self = args[0]
+ if f_self.log_level > self._level:
+ return f(*args, **kwargs)
+
+ has_log = hasattr(f_self, "log")
+ fname = f.func_name
+ log_obj = f_self
+ if not has_log:
+ log_obj = logging.getLogger()
+ try:
+ fname = "%s.%s" % (f_self.__class__.__name__, fname)
+ except:
+ pass
+ in_msg = "-> %s" % fname
+ if self._showargs:
+ if len(args) > 1: in_msg += str(args[1:])
+ if len(kwargs): in_msg += str(kwargs)
+ if self._col_limit and len(in_msg) > self._col_limit: in_msg = "%s [...]" % in_msg[:self._col_limit-6]
+ log_obj.log(self._level, in_msg)
+ out_msg = "<-"
+ try:
+ ret = f(*args, **kwargs)
+ except Exception, e:
+ exc_info = sys.exc_info()
+ out_msg += " (with %s) %s" % (e.__class__.__name__, fname)
+ log_obj.log(self._level, out_msg, exc_info=exc_info)
+ raise
+ out_msg += " %s" % fname
+ if not ret is None and self._showret:
+ out_msg += " = %s" % str(ret)
+ if self._col_limit and len(out_msg) > self._col_limit:
+ out_msg = "%s [...]" % out_msg[:self._col_limit-6]
+ log_obj.log(self._level, out_msg)
+ return ret
+ return wrapper
+
+
+class TraceIt(LogIt):
+ """Specialization of LogIt for trace level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, TraceIt
+ class Example(Logger):
+
+ @TraceIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=TRACE, showargs=showargs, showret=showret)
+
+
+class DebugIt(LogIt):
+ """Specialization of LogIt for debug level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, DebugIt
+ class Example(Logger):
+
+ @DebugIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=logging.DEBUG, showargs=showargs, showret=showret)
+
+
+class InfoIt(LogIt):
+ """Specialization of LogIt for info level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, InfoIt
+ class Example(Logger):
+
+ @InfoIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=logging.INFO, showargs=showargs, showret=showret)
+
+
+class WarnIt(LogIt):
+ """Specialization of LogIt for warn level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, WarnIt
+ class Example(Logger):
+
+ @WarnIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=logging.WARN, showargs=showargs, showret=showret)
+
+
+class ErrorIt(LogIt):
+ """Specialization of LogIt for error level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, ErrorIt
+ class Example(Logger):
+
+ @ErrorIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=logging.ERROR, showargs=showargs, showret=showret)
+
+
+class CriticalIt(LogIt):
+ """Specialization of LogIt for critical level messages.
+ Example::
+
+ from taurus.core.util.log import Logger, CriticalIt
+ class Example(Logger):
+
+ @CriticalIt()
+ def go(self):
+ print "Hello world"
+
+ .. seealso:: :class:`LogIt`"""
+ def __init__(self, showargs=False, showret=False):
+ LogIt.__init__(self, level=logging.CRITICAL, showargs=showargs, showret=showret)
+
+
+class MemoryLogHandler(list, logging.handlers.BufferingHandler):
+ """An experimental log handler that stores temporary records in memory.
+ When flushed it passes the records to another handler"""
+
+ def __init__(self, capacity=1000):
+ list.__init__(self)
+ logging.handlers.BufferingHandler.__init__(self, capacity=capacity)
+ self._handler_list_changed = False
+
+ def shouldFlush(self, record):
+ """Determines if the given record should trigger the flush
+
+ :param record: (logging.LogRecord) a log record
+ :return: (bool) wheter or not the handler should be flushed
+ """
+ return (len(self.buffer) >= self.capacity) or \
+ (record.levelno >= Logger.getLogLevel()) or \
+ self._handler_list_changed
+
+ def flush(self):
+ """Flushes this handler"""
+ for record in self.buffer:
+ for handler in self:
+ handler.handle(record)
+ self.buffer = []
+
+ def close(self):
+ """Closes this handler"""
+ self.flush()
+ del self[:]
+ logging.handlers.BufferingHandler.close(self)
+
+
+class LogExceptHook(BaseExceptHook):
+ """A callable class that acts as an excepthook that logs the exception in
+ the python logging system.
+
+ :param hook_to: callable excepthook that will be called at the end of
+ this hook handling [default: None]
+ :type hook_to: callable
+ :param name: logger name [default: None meaning use class name]
+ :type name: str
+ :param level: log level [default: logging.ERROR]
+ :type level: int"""
+
+ def __init__(self, hook_to=None, name=None, level=logging.ERROR):
+ BaseExceptHook.__init__(self, hook_to=hook_to)
+ name = name or self.__class__.__name__
+ self._level = level
+ self._log = Logger(name=name)
+
+ def report(self, *exc_info):
+ text = "".join(traceback.format_exception(*exc_info))
+ if text[-1] == '\n':
+ text = text[:-1]
+ self._log.log(self._level, "Unhandled exception:\n%s", text)
+
+
+class _Logger(logging.Logger):
+
+ def findCaller(self):
+ """
+ Find the stack frame of the caller so that we can note the source
+ file name, line number and function name.
+ """
+ f = currentframe()
+ #On some versions of IronPython, currentframe() returns None if
+ #IronPython isn't run with -X:Frames.
+ if f is not None:
+ f = f.f_back
+ rv = "(unknown file)", 0, "(unknown function)"
+ while hasattr(f, "f_code"):
+ co = f.f_code
+ filename = os.path.normcase(co.co_filename)
+ if filename in (_srcfile, logging._srcfile):
+ f = f.f_back
+ continue
+ rv = (co.co_filename, f.f_lineno, co.co_name)
+ break
+ return rv
+
+
+class Logger(Object):
+ """The taurus logger class. All taurus pertinent classes should inherit
+ directly or indirectly from this class if they need taurus logging
+ facilities."""
+
+ #: Internal usage
+ root_inited = False
+
+ #: Internal usage
+ root_init_lock = threading.Lock()
+
+ #: Critical message level (constant)
+ Critical = logging.CRITICAL
+
+ #: Fatal message level (constant)
+ Fatal = logging.FATAL
+
+ #: Error message level (constant)
+ Error = logging.ERROR
+
+ #: Warning message level (constant)
+ Warning = logging.WARNING
+
+ #: Info message level (constant)
+ Info = logging.INFO
+
+ #: Debug message level (constant)
+ Debug = logging.DEBUG
+
+ #: Trace message level (constant)
+ Trace = TRACE
+
+ #: Default log level (constant)
+ DftLogLevel = Info
+
+ #: Default log message format (constant)
+ DftLogMessageFormat = '%(threadName)-14s %(levelname)-8s %(asctime)s %(name)s: %(message)s'
+
+ #: Default log format (constant)
+ DftLogFormat = logging.Formatter(DftLogMessageFormat)
+
+ #: Current global log level
+ log_level = DftLogLevel
+
+ #: Default log message format
+ log_format = DftLogFormat
+
+ #: the main stream handler
+ stream_handler = None
+
+
+ def __init__(self, name='', parent=None, format=None):
+ """The Logger constructor
+
+ :param name: (str) the logger name (default is empty string)
+ :param parent: (Logger) the parent logger or None if no parent exists (default is None)
+ :param format: (str) the log message format or None to use the default log format (default is None)
+ """
+ self.call__init__(Object)
+
+ if format: self.log_format = format
+ Logger.initRoot()
+
+ if name is None or len(name) == 0:
+ name = self.__class__.__name__
+ self.log_name = name
+ if parent is not None:
+ self.log_full_name = '%s.%s' % (parent.log_full_name, name)
+ else:
+ self.log_full_name = name
+
+ self.log_obj = self._getLogger(self.log_full_name)
+ self.log_handlers = []
+
+ self.log_parent = None
+ self.log_children = {}
+ if parent is not None:
+ self.log_parent = weakref.ref(parent)
+ parent.addChild(self)
+
+ def cleanUp(self):
+ """The cleanUp. Default implementation does nothing
+ Overwrite when necessary"""
+ pass
+
+ @classmethod
+ def initRoot(cls):
+ """Class method to initialize the root logger. Do **NOT** call this
+ method directly in your code
+ """
+ if cls.root_inited:
+ return cls._getLogger()
+
+ try:
+ cls.root_init_lock.acquire()
+ root_logger = cls._getLogger()
+ logging.addLevelName(cls.Trace, "TRACE")
+ cls.stream_handler = logging.StreamHandler(sys.__stderr__)
+ cls.stream_handler.setFormatter(cls.log_format)
+ root_logger.addHandler(cls.stream_handler)
+
+ console_log_level = os.environ.get("TAURUSLOGLEVEL", None)
+ if console_log_level is not None:
+ console_log_level = console_log_level.capitalize()
+ if hasattr(cls, console_log_level):
+ cls.log_level = getattr(cls, console_log_level)
+ root_logger.setLevel(cls.log_level)
+ Logger.root_inited = True
+ finally:
+ cls.root_init_lock.release()
+ return root_logger
+
+ @classmethod
+ def addRootLogHandler(cls, h):
+ """Adds a new handler to the root logger
+
+ :param h: (logging.Handler) the new log handler
+ """
+ h.setFormatter(cls.getLogFormat())
+ cls.initRoot().addHandler(h)
+
+ @classmethod
+ def removeRootLogHandler(cls, h):
+ """Removes the given handler from the root logger
+
+ :param h: (logging.Handler) the handler to be removed
+ """
+ cls.initRoot().removeHandler(h)
+
+ @classmethod
+ def enableLogOutput(cls):
+ """Enables the :class:`logging.StreamHandler` which dumps log records,
+ by default, to the stderr.
+ """
+ cls.initRoot().addHandler(cls.stream_handler)
+
+ @classmethod
+ def disableLogOutput(cls):
+ """Disables the :class:`logging.StreamHandler` which dumps log records,
+ by default, to the stderr.
+ """
+ cls.initRoot().removeHandler(cls.stream_handler)
+
+ @classmethod
+ def setLogLevel(cls,level):
+ """sets the new log level (the root log level)
+
+ :param level: (int) the new log level
+ """
+ cls.log_level = level
+ cls.initRoot().setLevel(level)
+
+ @classmethod
+ def getLogLevel(cls):
+ """Retuns the current log level (the root log level)
+
+ :return: (int) a number representing the log level
+ """
+ return cls.log_level
+
+ @classmethod
+ def setLogFormat(cls,format):
+ """sets the new log message format
+
+ :param level: (str) the new log message format
+ """
+ cls.log_format = logging.Formatter(format)
+ root_logger = cls.initRoot()
+ for h in root_logger.handlers:
+ h.setFormatter(cls.log_format)
+
+ @classmethod
+ def getLogFormat(cls):
+ """Retuns the current log message format (the root log format)
+
+ :return: (str) the log message format
+ """
+ return cls.log_format
+
+ @classmethod
+ def resetLogLevel(cls):
+ """Resets the log level (the root log level)"""
+ cls.setLogLevel(cls.DftLogLevel)
+
+ @classmethod
+ def resetLogFormat(cls):
+ """Resets the log message format (the root log format)"""
+ cls.setLogFormat(cls.DftLogFormat)
+
+ @classmethod
+ def addLevelName(cls, level_no, level_name):
+ """Registers a new log level
+
+ :param level_no: (int) the level number
+ :param level_name: (str) the corresponding name
+ """
+ logging.addLevelName(level_no, level_name)
+ level_name = level_name.capitalize()
+ if not hasattr(cls, level_name):
+ setattr(cls, level_name, level_no)
+
+ @classmethod
+ def getRootLog(cls):
+ """Retuns the root logger
+
+ :return: (logging.Logger) the root logger
+ """
+ return cls.initRoot()
+
+ @staticmethod
+ def _getLogger(name=None):
+ orig_logger_class = logging.getLoggerClass()
+ try:
+ logging.setLoggerClass(_Logger)
+ ret = logging.getLogger(name)
+ return ret
+ finally:
+ logging.setLoggerClass(orig_logger_class)
+
+ @classmethod
+ def getLogger(cls, name=None):
+ cls.initRoot()
+ return cls._getLogger(name=name)
+
+ def getLogObj(self):
+ """Returns the log object for this object
+
+ :return: (logging.Logger) the log object
+ """
+ return self.log_obj
+
+ def getParent(self):
+ """Returns the log parent for this object or None if no parent exists
+
+ :return: (logging.Logger or None) the log parent for this object
+ """
+ if self.log_parent is None:
+ return None
+ return self.log_parent()
+
+ def getChildren(self):
+ """Returns the log children for this object
+
+ :return: (sequence<logging.Logger) the list of log children
+ """
+ children = []
+ for _, ref in self.log_children.iteritems():
+ child = ref()
+ if child is not None:
+ children.append(child)
+ return children
+
+ def addChild(self, child):
+ """Adds a new logging child
+
+ :param child: (logging.Logger) the new child
+ """
+ if not self.log_children.get(id(child)):
+ self.log_children[id(child)]=weakref.ref(child)
+
+ def addLogHandler(self, handler):
+ """Registers a new handler in this object's logger
+
+ :param handler: (logging.Handler) the new handler to be added
+ """
+ self.log_obj.addHandler(handler)
+ self.log_handlers.append(handler)
+
+ def copyLogHandlers(self, other):
+ """Copies the log handlers of other object to this object
+
+ :param other: (object) object which contains 'log_handlers'
+ """
+ for handler in other.log_handlers:
+ self.addLogHandler(handler)
+
+ def trace(self, msg, *args, **kw):
+ """Record a trace message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.log`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.log(self.Trace, msg, *args, **kw)
+
+ def traceback(self, level=Trace, extended=True):
+ """Log the usual traceback information, followed by a listing of all the
+ local variables in each frame.
+
+ :param level: (int) the log level assigned to the traceback record
+ :param extended: (bool) if True, the log record message will have multiple lines
+
+ :return: (str) The traceback string representation
+ """
+ out = traceback.format_exc()
+ if extended:
+ out += "\n"
+ out += self._format_trace()
+
+ self.log_obj.log(level, out)
+ return out
+
+ def stack(self, target=Trace):
+ """Log the usual stack information, followed by a listing of all the
+ local variables in each frame.
+
+ :param target: (int) the log level assigned to the record
+
+ :return: (str) The stack string representation
+ """
+ out = self._format_stack()
+ self.log_obj.log(target, out)
+ return out
+
+ def _format_trace(self):
+ return self._format_stack(inspect.trace)
+
+ def _format_stack(self, stack_func=inspect.stack):
+ line_count = 3
+ stack = stack_func(line_count)
+ out = ''
+ for frame_record in stack:
+ out += '\n\t' + 60*'-'
+ frame, filename, line, funcname, lines, index = frame_record
+ #out += '\n\t depth = %d' % frame[5]
+ out += '\n\t filename = %s' % filename
+ out += '\n\t function = %s' % funcname
+ if lines is None:
+ code = '<code could not be found>'
+ out += '\n\t line = [%d]: %s' % (line, code)
+ else:
+ lines, line_nb = [ s.strip(' \n') for s in lines ], len(lines)
+ if line_nb >= 3:
+ out += '\n\t line = [%d]: %s' % (line-1, lines[0])
+ out += '\n\t -> line = [%d]: %s' % (line, lines[1])
+ out += '\n\t line = [%d]: %s' % (line+1, lines[2])
+ elif line_nb > 0:
+ out += '\n\t -> line = [%d]: %s' % (line, lines[0])
+ if frame:
+ out += '\n\t locals = '
+ for k,v in frame.f_locals.items():
+ out += '\n\t\t%20s = ' % k
+ try:
+ cut = False
+ v = str(v)
+ i = v.find('\n')
+ if i == -1:
+ i = 80
+ else:
+ i = min(i, 80)
+ cut = True
+ if len(v) > 80: cut = True
+ out += v[:i]
+ if cut: out += '[...]'
+ except:
+ out += '<could not find suitable string representation>'
+ return out
+
+ def log(self, level, msg, *args, **kw):
+ """Record a log message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.log`.
+
+ :param level: (int) the record level
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.log(level, msg, *args, **kw)
+
+ def debug(self, msg, *args, **kw):
+ """Record a debug message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.debug`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.debug(msg, *args, **kw)
+
+ def info(self, msg, *args, **kw):
+ """Record an info message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.info`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.info(msg, *args, **kw)
+
+ def warning(self, msg, *args, **kw):
+ """Record a warning message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.warning`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.warning(msg, *args, **kw)
+
+ def deprecated(self, msg, *args, **kw):
+ """Record a deprecated warning message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.warning`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ filename, lineno, func = self.log_obj.findCaller()
+ depr_msg = warnings.formatwarning(msg, DeprecationWarning, filename, lineno)
+ self.log_obj.warning(depr_msg, *args, **kw)
+
+ def error(self, msg, *args, **kw):
+ """Record an error message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.error`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.error(msg, *args, **kw)
+
+ def fatal(self, msg, *args, **kw):
+ """Record a fatal message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.fatal`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.fatal(msg, *args, **kw)
+
+ def critical(self, msg, *args, **kw):
+ """Record a critical message in this object's logger. Accepted *args* and
+ *kwargs* are the same as :meth:`logging.Logger.critical`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ :param kw: list of keyword arguments
+ """
+ self.log_obj.critical(msg, *args, **kw)
+
+ def exception(self, msg, *args):
+ """Log a message with severity 'ERROR' on the root logger, with
+ exception information.. Accepted *args* are the same as
+ :meth:`logging.Logger.exception`.
+
+ :param msg: (str) the message to be recorded
+ :param args: list of arguments
+ """
+ self.log_obj.exception(msg, *args)
+
+ def flushOutput(self):
+ """Flushes the log output"""
+ self.syncLog()
+
+ def syncLog(self):
+ """Synchronises the log output"""
+ logger = self
+ synced = []
+ while logger is not None:
+ for handler in logger.log_handlers:
+ if handler in synced:
+ continue
+ try:
+ sync = getattr(handler, 'sync')
+ except:
+ continue
+ sync()
+ synced.append(handler)
+ logger = logger.getParent()
+
+ def getLogName(self):
+ """Gets the log name for this object
+
+ :return: (str) the log name
+ """
+ return self.log_name
+
+ def getLogFullName(self):
+ """Gets the full log name for this object
+
+ :return: (str) the full log name
+ """
+ return self.log_full_name
+
+ def changeLogName(self,name):
+ """Change the log name for this object.
+
+ :param name: (str) the new log name
+ """
+ self.log_name = name
+ p = self.getParent()
+ if p is not None:
+ self.log_full_name = '%s.%s' % (p.log_full_name, name)
+ else:
+ self.log_full_name = name
+
+ self.log_obj = logging.getLogger(self.log_full_name)
+ for handler in self.log_handlers:
+ self.log_obj.addHandler(handler)
+
+ for child in self.getChildren():
+ child.changeLogName(child.log_name)
+
+
+class LogFilter(logging.Filter):
+ """Experimental log filter"""
+
+ def __init__(self, level):
+ self.filter_level = level
+ logging.Filter.__init__(self)
+
+ def filter(self, record):
+ ok = (record.levelno == self.filter_level)
+ return ok
+
+def __getrootlogger():
+ return Logger.getLogger("TaurusRootLogger")
+
+# cannot export log because upper package taurus.core.util imports this 'log'
+# module and it would itself be overwritten by this log function
+def _log(level, msg, *args, **kw):
+ return __getrootlogger().log(level, msg, *args, **kw)
+
+def trace(msg, *args, **kw):
+ return _log(Logger.Trace, msg, *args, **kw)
+
+def debug(msg, *args, **kw):
+ return __getrootlogger().debug(msg, *args, **kw)
+
+def info(msg, *args, **kw):
+ return __getrootlogger().info(msg, *args, **kw)
+
+def warning(msg, *args, **kw):
+ return __getrootlogger().warning(msg, *args, **kw)
+
+def error(msg, *args, **kw):
+ return __getrootlogger().error(msg, *args, **kw)
+
+def fatal(msg, *args, **kw):
+ return __getrootlogger().fatal(msg, *args, **kw)
+
+def critical(msg, *args, **kw):
+ return __getrootlogger().critical(msg, *args, **kw)