python custom log file and save it to the specified location

Change the storage location of the log by passing in the log file parameters.
Don't talk nonsense, just go to the code:

from logging import getLogger, FileHandler, Formatter, StreamHandler, \
    raiseExceptions, INFO, DEBUG, WARN, ERROR
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
import os
import sys

loggers = {
    
    }


# The background is set with 40 plus the number of the color, and the foreground with 30

def prepareLogging(name, logDir):
    global loggers
    if loggers.get(name):
        return loggers.get(name)
    else:
        logger = getLogger(name)
        # dir must exist, so create dir
        # FIXME: if no absolute path is assigned, logs directory will be in the same directory with  mainPictureServer.py - use the relative path first.
        # any better solution?
        if not os.path.exists(logDir):
            os.makedirs(logDir)

        # TimedRotatingFileHandler : when - (s)econd|(m)inute|(h)our|(d)ay|w0-26(0-monday)|midnight
        hdlr = TimedRotatingFileHandler(logDir + "/" + name + ".txt", when="d", interval=1, backupCount=30)
        # hdlr = RotatingFileHandler(logDir+"/"+name+".txt", maxBytes=1024<<10, backupCount=30)
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        formatter = Formatter(
            '%(thread)-6.6s %(asctime)s.%(msecs)02.2d %(filename)-12.12s_%(lineno)03d %(levelname)-3.3s] %(message)s',
            '%m-%d %H:%M:%S')

        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

        ch = StreamHandler()
        ch.setLevel(INFO)
        formatter = Formatter(
            '%(thread)-4.4s %(asctime)s.%(msecs)02.2d %(filename)-12.12s_%(lineno)03d] %(levelname)-2.2s] %(message)s',
            '%M:%S')
        ch.setFormatter(formatter)
        # logger.propagate = False #without this, message will be duplicated
        logger.addHandler(ch)

        loggers[name] = logger

        logger.setLevel(INFO)
        return logger


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)

if hasattr(sys, '_getframe'):
    currentframe = lambda: sys._getframe(3)
else:  # pragma: no cover
    def currentframe():
        """Return the frame object for the caller's stack frame."""
        try:
            raise Exception
        except Exception:
            return sys.exc_info()[2].tb_frame.f_back


class MyLogger(object):
    # as the caller will be MyLogger, so need copy logger implement for info(), warning, error()

    def __init__(self, logger):
        self.logger = logger

    def debug(self, msg, *args, **kwargs):
        if self.logger.isEnabledFor(DEBUG):
            self._log(DEBUG, msg, args, **kwargs)

    def info(self, msg, *args, **kwargs):
        if self.logger.isEnabledFor(INFO):
            self._log(INFO, msg, args, **kwargs)

    def warn(self, msg, *args, **kwargs):
        if self.logger.isEnabledFor(WARN):
            self._log(WARN, msg, args, **kwargs)

    def error(self, msg, *args, **kwargs):
        if self.logger.isEnabledFor(ERROR):
            self._log(ERROR, msg, args, **kwargs)

    def _log(self, level, msg, args, exc_info=None, extra=None):
        """
        Low-level logging routine which creates a LogRecord and then calls
        all the handlers of this logger to handle the record.
        """
        # Add wrapping functionality here.
        if _srcfile:
            # IronPython doesn't track Python frames, so findCaller throws an
            # exception on some versions of IronPython. We trap it here so that
            # IronPython can use logging.
            try:
                fn, lno, func = self.findCaller()
            except ValueError:
                fn, lno, func = "(unknown file)", 0, "(unknown function)"
        else:
            fn, lno, func = "(unknown file)", 0, "(unknown function)"
        if exc_info:
            if not isinstance(exc_info, tuple):
                exc_info = sys.exc_info()
        record = self.logger.makeRecord(
            self.logger.name, level, fn, lno, msg, args, exc_info, func, extra)
        self.logger.handle(record)

    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 == _srcfile:
                f = f.f_back
                continue
            rv = (co.co_filename, f.f_lineno, co.co_name)
            break
        return rv

    def log(self, level, msg, *args, **kwargs):
        """
        Log 'msg % args' with the integer severity 'level'.

        To pass exception information, use the keyword argument exc_info with
        a true value, e.g.

        logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
        """
        if not isinstance(level, int):
            if raiseExceptions:
                raise TypeError("level must be an integer")
            else:
                return
        if self.logger.isEnabledFor(level):
            self._log(level, msg, args, **kwargs)

    def _prefix(self, elevId):
        if str(elevId) == '1':
            prefix = ''
        else:
            prefix = ' ' * 30
        return prefix

    def infoE(self, elevId, msg, *args, **kwargs):
        self.info("{}{}".format(self._prefix(elevId), msg), *args, **kwargs)

    def warnE(self, elevId, msg, *args, **kwargs):
        self.warn("{}{}".format(self._prefix(elevId), msg), *args, **kwargs)

    def errorE(self, elevId, msg, *args, **kwargs):
        self.error("{}{}".format(self._prefix(elevId), msg), *args, **kwargs)

    def print0(self, msg, *args, **kwargs):
        method_name = sys._getframe(1).f_code.co_name
        line_no = sys._getframe(1).f_lineno
        _m = "{}_{}:{}{}".format(method_name, line_no, "", msg)
        print(_m)
        self.debug(_m, *args, **kwargs)

    def printE(self, elevId, msg, *args, **kwargs):
        p = self._prefix(elevId)
        method_name = sys._getframe(1).f_code.co_name
        line_no = sys._getframe(1).f_lineno
        _m = "{}_{}:{}{}".format(method_name, line_no, p, msg)
        print(p + msg)
        self.debug(p + msg, *args, **kwargs)


def logtt(logger):
    logger.info('hello logs')


if __name__ == '__main__':
    logger = MyLogger(prepareLogging("hello", './logs'))
    logtt(logger)

Guess you like

Origin blog.csdn.net/qq_43030934/article/details/107339983