# # Copyright (c) 2018 Red Hat, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # """ Logger - VDO manager logging $Id: //eng/vdo-releases/magnesium/src/python/vdo/utils/Logger.py#3 $ """ import logging import logging.handlers import os import sys from types import MethodType class Logger(object): """Wrappers and configuration methods for the Python logger. Attributes: logfile (string): the path to the logfile if specified. myname (string): name of the command being run. quiet (bool): if True, don't print to stdout. """ myname = os.path.basename(sys.argv[0]) quiet = False logfile = None ###################################################################### # Public methods ###################################################################### @classmethod def announce(cls, logger, msg): """Print a status message to stdout and log it as well.""" if not cls.quiet: print(msg) logger.info(msg) ###################################################################### @classmethod def configure(cls, name, logfile = None, debug = False): """Configure the logging system according to the arguments.""" cls.myname = name cls.logfile = logfile debugging = debug formatBase = ': %(levelname)s - %(message)s' debugBase = (': %(name)s' if debugging else '') + formatBase logger = logging.getLogger() logger.setLevel(logging.NOTSET) handler = logging.StreamHandler(sys.stderr) handler.setFormatter(logging.Formatter(cls.myname + debugBase)) handler.setLevel(logging.DEBUG if debugging else logging.WARNING) logger.addHandler(handler) if cls.logfile is not None: try: if os.path.exists(cls.logfile) and not os.path.isfile(cls.logfile): # Support /dev/stderr and the like. logstream = open(cls.logfile, "w") handler = logging.StreamHandler(stream=logstream) else: handler = logging.handlers.RotatingFileHandler(cls.logfile, maxBytes=10*1024*1024, backupCount=5) formatter = logging.Formatter('%(asctime)s %(name)s' + formatBase) handler.setFormatter(formatter) handler.setLevel(logging.DEBUG if debugging else logging.INFO) logger.addHandler(handler) except Exception as ex: logger.warn('Unable to configure logging to {logfile}: {ex}' .format(logfile=cls.logfile, ex=ex)) try: handler = logging.handlers.SysLogHandler(address='/dev/log') handler.setFormatter(logging.Formatter(cls.myname + formatBase)) handler.setLevel(logging.WARNING) logger.addHandler(handler) except Exception as ex: logger.warn('Unable to configure logging for rsyslog: {0}'.format(ex)) ###################################################################### @classmethod def getLogger(cls, name): """Returns a Python logger decorated with the announce method.""" logger = logging.getLogger(name) logger.announce = MethodType(cls.announce, logger, logger.__class__) return logger ###################################################################### @classmethod def loggingOptions(cls): """Return a list of strings containing the logging options specified.""" options = [ ] if cls.logfile is not None: options.append("--logfile=" + str(cls.logfile)) return options ###################################################################### # Overridden methods ###################################################################### def __init__(self): super(Logger, self).__init__()