zoukankan      html  css  js  c++  java
  • python对日志处理的封装

    一个适应性范围较广的日志处理

    # coding=utf8
    """
    @author bfzs
    """
    import os
    import logging
    from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler
    from cloghandler import ConcurrentRotatingFileHandler
    
    format_dict = {
        1: logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - %(levelname)s -  %(message)s', "%Y-%m-%d %H:%M:%S"),
        2: logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - %(levelname)s -  %(message)s', "%Y-%m-%d %H:%M:%S"),
        3: logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - %(levelname)s -  %(message)s', "%Y-%m-%d %H:%M:%S"),
        4: logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - %(levelname)s -  %(message)s', "%Y-%m-%d %H:%M:%S"),
        5: logging.Formatter('%(asctime)s - %(name)s - %(lineno)d - %(levelname)s -  %(message)s', "%Y-%m-%d %H:%M:%S"),
    }
    
    
    class LogLevelException(Exception):
        def __init__(self, log_level):
            err = '设置的日志级别是 {0}, 设置错误,请设置为1 2 3 4 5 范围的数字'.format(log_level)
            Exception.__init__(self, err)
    
    
    class Log(object):
        """
        一个日志类,用于创建和捕获日志,支持将日志打印到控制台打印和写入日志文件。
        """
    
        def __init__(self, logger_name=None, log_level_int=1, is_add_stream_handler=True, log_path=None, log_filename=None):
            """
            :param logger_name: 日志名称,当为None时候打印所有日志
            :param log_level_int: 日志级别,设置为 1 2 3 4 5,分别对应DEBUG,INFO,WARNING,ERROR,CRITICAL
            :param is_add_stream_handler: 是否打印日志到控制台
            :param log_path: 设置存放日志的文件夹路径
            :param log_filename: 日志的名字,仅当log_path和log_filename都不为None时候才写入到日志文件。
            :type logger_name :str
            :type log_level_int :int
            :type is_add_stream_handler :bool
            :type log_path :str
            :type log_filename :str
            """
            self.logger = logging.getLogger(logger_name)
            self.__check_log_level(log_level_int)
            self._logger_level = self.__transform_logger_level(log_level_int)
            self._is_add_stream_handler = is_add_stream_handler
            self._log_path = log_path
            self._log_filename = log_filename
            self._formatter = format_dict[log_level_int]
            self.__set_logger_level()
            self.__add_handlers()
    
        def debug(self, msg):
            self.logger.debug(msg)
    
        def info(self, msg):
            self.logger.info(msg)
    
        def warning(self, msg):
            self.logger.warning(msg)
    
        def error(self, msg):
            self.logger.error(msg)
    
        def critical(self, msg):
            self.logger.critical(msg)
    
        def __set_logger_level(self):
            self.logger.setLevel(self._logger_level)
    
        @staticmethod
        def __check_log_level(log_level_int):
            if log_level_int not in [1, 2, 3, 4, 5]:
                raise LogLevelException(log_level_int)
    
        @staticmethod
        def __transform_logger_level(log_level_int):
            logger_level = None
            if log_level_int == 1:
                logger_level = logging.DEBUG
            elif log_level_int == 2:
                logger_level = logging.INFO
            elif log_level_int == 3:
                logger_level = logging.WARNING
            elif log_level_int == 4:
                logger_level = logging.ERROR
            elif log_level_int == 5:
                logger_level = logging.CRITICAL
            return logger_level
    
        def __add_handlers(self):
            if self._is_add_stream_handler:
                self.__add_stream_handler()
            if all([self._log_path, self._log_filename]):
                self.__add_file_handler()
    
        def __add_stream_handler(self):
            """
            日志显示到控制台
            """
            stream_handler = logging.StreamHandler()
            stream_handler.setLevel(self._logger_level)
            stream_handler.setFormatter(self._formatter)
            self.logger.addHandler(stream_handler)
    
        def __add_file_handler(self):
            """
            日志写入日志文件
            """
            if not os.path.exists(self._log_path):
                os.makedirs(self._log_path)
            log_file = os.path.join(self._log_path, self._log_filename)
            os_name = os.name
            print os_name
            rotate_file_handler = None
            if os_name == 'nt':
                # windows下用这个,非进程安全
                rotate_file_handler = RotatingFileHandler(log_file, mode="a", maxBytes=10 * 1024 * 1024, backupCount=10, encoding="utf-8")
            if os_name == 'posix':
                # linux下可以使用ConcurrentRotatingFileHandler,进程安全的日志方式
                rotate_file_handler = ConcurrentRotatingFileHandler(log_file, mode="a", maxBytes=10 * 1024 * 1024, backupCount=10, encoding="utf-8")
            rotate_file_handler.setLevel(logging.DEBUG)
            rotate_file_handler.setFormatter(self._formatter)
            self.logger.addHandler(rotate_file_handler)
    
    
    def test_func():
        """测试日志打印,单独运行test_func函数是不会打印出这条日志,没有添加handler"""
        logger = logging.getLogger('test')
        logger.info(u'需要被打印的日志')
    
    
    if __name__ == "__main__":
        test_log = Log('test', 1, log_path='./logs', log_filename='test.log')
        test_func()
        test_log.info(u'添加一条日志')
    
        import requests
    
        request_log = Log('urllib3.connectionpool', 1)  # 测试三方包的日志
        resp = requests.get('https://www.baidu.com')

    场景:将不同的日志写入到不同的文件,分析业务问题,查看三方包的日志。

     有的三方包的日志是必须捕获,例如concurrent包的日志,线程池运行错误都是通过日志的方式报错,如果不对日志进行打印捕获,很多语法错误或者流程错误都看不到,可能会以为写的东西没毛病呢。

  • 相关阅读:
    函数 定义与调用
    python文件基本操作(读,写,追加)
    python集合深浅copy
    day6 bytes类型用法
    字典的增删改查
    一个文件启动Django(基础中的基础)
    Django错误集
    Linux的Shell
    Linux的Vim文本编辑器
    Linux管道符和重定向与环境变量
  • 原文地址:https://www.cnblogs.com/ydf0509/p/8971475.html
Copyright © 2011-2022 走看看