• logging模块


      python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志。

    logging的日志分为debug()、info()、warning()、error()、critical()五个级别
    debug() 调试模式(详细)
    info() 记录(无错误)
    warning() 无错误但可能有潜在的危险
    error() 出现错误
    critical() 严重问题
    基本用法
    import logging
    
    # 基本使用:日志打印
    logging.warning("user [alex] attempted wrong password more than 3 times")
    logging.critical("server is down")
    """
    WARNING:root:user [alex] attempted wrong password more than 3 times
    CRITICAL:root:server is down
    """
    日志写入文件
    import logging
    
    logging.basicConfig(filename='log_test.log', level=logging.INFO)
    logging.debug("This message should go to the log file")
    logging.info("so should this")
    logging.warning("And this,too")
    """
    log_test.log中仅写入了warning和info信息
    """

      在basicConfig中,filename指定了文件路径,level=logging.INFO是把日志记录设置为INFO,只输入INFO或者比INFO级别更高的日志(日志级别过滤)。

    自定义日志格式
    import logging
    
    logging.basicConfig(filename='log_test.log',
                        level=logging.DEBUG,
                        format='%(asctime)s-%(name)s-%(filename)s-%(funcName)s-%(lineno)d-%(message)s',  # 参数固定格式
                        datefmt='%m/%d/%Y %I:%M:%S %p')
    
    def sayhi():
        logging.error("from sayhi....")
    sayhi()
    logging.debug("This message should go to the log file")
    logging.info("so should this")
    logging.warning("And this,too")

      执行会生成log_test.log文件,文件内容如下:

    04/18/2018 03:19:00 PM-root-logging_module.py-sayhi-40-from sayhi....
    04/18/2018 03:19:00 PM-root-logging_module.py-<module>-42-This message should go to the log file
    04/18/2018 03:19:00 PM-root-logging_module.py-<module>-43-so should this
    04/18/2018 03:19:00 PM-root-logging_module.py-<module>-44-And this,too

      除了可以在日志格式上加上时间之外,还可以自定义很多格式:

    参数格式介绍:
    %(levelno)s     # 打印数字形式的日志级别(10对应debug,20对应info,30对应warning)
    %(levelname)s   # 打印文本形式的日志级别 %(pathname)s    # 调用日志输出函数的模块的完整路径名
    %(filename)s    # 调用日志输出函数的模块的文件名
    
    %(module)s      # 调用日志输出函数的模块名
    %(funcName)s    # 调用日志输出函数的函数名
    %(lineNo)d      # 调用日志输出函数的语句所在的代码行(44)
    %(created)f     # 当前时间,用UNIX标准的表示是时间(一般时间用datafmt即可)
    %(relaticeCreated)d    # 输出日志信息时,自Logger创建以来的毫秒数
    
    %(asctime)s     # 字符串形式的当前时间,默认格式"2003-08-08 16:32:21,878",逗号后为毫秒数
    
    %(thread)d      # 线程ID  
    %(threadName)s  # 线程名
    %(process)d     # 进程ID
    
    %(message)s     # 用户输出的消息
    日志同时输出到屏幕和文件

    Python使用logging模块记录日志涉及四个主要类:
      1、logger提供了应用程序可以直接使用的接口;
      2、handler将(logger创建的)日志记录发送到合适的目的输出;
      3、filter对记录的日志过滤决定哪条日志输出;
      4、formatter决定日志记录的最终输出格式。

    这四个类之间的关系:

      首先在输出信息之前获取一个logger对象,用getLogger()方法指定文件名;其次利用StreamHandler()输送到屏幕,利用FileHandler('文件名')输送到文件;再利用addHandler()方法将handler对象加进Logger对象中。接着可以生成Formatter对象,设置文件输出格式,利用setFormatter()方法将输出格式绑定到hander对象上。

      最后由Filters对象对日志进行过滤,一般与Logger进行关联,如果屏幕和文件的日志过滤机制不同,可以与handler进行关联。

    Logger组件

      每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块、核心模块可以这样获得它的Logger:

    LOG = logging.getLogger("chat.gui")  # 图形界面模块
    LOG2 = logging.getLogger("chat.kernal") # 核心模块

      指定日志级别、绑定或删除handler和filters:

    # 指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
    logging.Logger.setLevel() # 低于指定级别将被忽略
    
    # 添加或删除指定的filter
    logging.Logger.addFilter()
    logging.Logger.removeFilter()
    
    # 添加或删除指定的handler
    logging.Logger.addHandler()
    logging.Logger.removeHandler()

      Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别

    handler模块

      handler对象负责发送相关信息到指定的目的地(控制台、文件、网络):

    logging.Handler.setLevel()  # 指定被处理信息级别
    logging.Handler.setFormatter()  # 给这个handler选择一个格式
    logging.Handler.addFilter() # 新增一个filter对象
    logging.Handler.removeFilter() # 删除一个filter对象

      每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:

    1. logging.StreamHandler 使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。
    2. logging.FileHandler 和StreamHandler 类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件
    3. logging.handlers.RotatingFileHandler  同FileHandler类似,但可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出。

      # 比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的函数是:
      
      RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
      
      """
      其中filename和mode两个参数和FileHandler一样。
          maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
          backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
      """
    4. logging.handlers.TimedRotatingFileHandler

      这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。
      # 函数如下:
      TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
      
      """
      其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
      
      interval是时间间隔。
      
      when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
          S 秒
          M 分
          H 小时
          D 天
          W 每星期(interval==0时代表星期一)
          midnight 每天凌晨
      """
    formatter组件

      日志的formatter是个独立的组件,可以跟handler组合。

    fh = logging.FileHandler("access.log")
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    fh.setFormatter(formatter) #把formmater绑定到fh上
    filter组件

      对日志过滤,可自定义一个filter,通用格式如下:(注意filter函数会返加True or False,logger根据此值决定是否输出此日志

    class IgnoreBackupLogFilter(logging.Filter):
        """忽略带db backup 的日志"""
        def filter(self, record): #固定写法
            return   "db backup" not in record.getMessage()

      然后将这个filter添加到logger中:

    logger.addFilter(IgnoreBackupLogFilter())

      下面的日志就会将符合filter条件的过滤掉

    logger.debug("test ....")
    logger.info("test info ....")
    logger.warning("start to run db backup job ....")
    logger.error("test error ...."
    同时输出屏幕、文件、带filter的例子
    import logging
    
    
    class IgnoreBackupLogFilter(logging.Filter):
        """忽略带db backup 的日志"""
    
        def filter(self, record):  # 固定写法
            return "db backup" not in record.getMessage()  # 字段不在日志消息内
    
    
    # 生成logger对象
    logger = logging.getLogger("web")
    logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning
    # 把filter对象添加到logger中 logger.addFilter(IgnoreBackupLogFilter()) # 生成handler对象 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # 屏幕debug级别 fh = logging.FileHandler("web.log") fh.setLevel(logging.WARNING) # 文件设置WARNING级别 # 把handler对象绑定到logger对象 logger.addHandler(ch) logger.addHandler(fh) # 生成formatter对象 file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s') # 把formatter对象绑定hander对象 ch.setFormatter(console_formater) fh.setFormatter(file_formater) logger.debug("test_log") logger.warning("test_log_2") logger.debug("test log db backup 3") # filter测试,不记录这条日志 """ 在全局日志级别:info (不设置默认级别是warning,一般可以把全局设低把其他级别设高) 屏幕日志级别:debug 文件日志级别:warning 这种情况下,屏幕日志级别不生效,依然按照全局日志级别仅输出一条: 2018-03-03 16:27:28,508 - web - WARNING - 23 - test_log_2 全局设置为DEBUG后,console_handler设置为INFO,若输出的日志级别为DEBUG,则不会再屏幕显示 """

      可以看到上述程序设置屏幕日志级别为debug, 文件日志级别为warning,同时过滤信息为“db backup”。屏幕输出和web.log文件日志如下所示:

    # 控制台日志
    2018-04-18 16:34:21,376 - web - DEBUG - 32 - test_log
    2018-04-18 16:34:21,376 - web - WARNING - 33 - test_log_2
    
    # web.log日志
    2018-04-18 16:34:21,376 - web - WARNING - test_log_2
    根据文件大小截断日志

      函数示例:logging.RotatingFileHandler(filename[, mode[, maxBytes[, backupCount]]]),当文件达到一定大小后,会自动将当前日志文件改名,然后创建一个新的同名的日志文件继续输出。

    import logging
    from logging import handlers
    
    
    class IgnoreBackupLogFilter(logging.Filter):
        """忽略带db backup 的日志"""
    
        def filter(self, record):  # 固定写法
            return "db backup" not in record.getMessage()  # 字段不在日志消息内
    
    
    # 生成logger对象
    logger = logging.getLogger("web")
    logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning
    
    # 把filter对象添加到logger中
    logger.addFilter(IgnoreBackupLogFilter())
    
    # 生成handler对象
    ch = logging.StreamHandler()
    # ch.setLevel(logging.DEBUG)  # 屏幕debug级别
    
    # 生成RotatingFileHandler对象
    # fh = logging.FileHandler("web.log")
    fh = handlers.RotatingFileHandler("web_jd.log", maxBytes=10, backupCount=3)   # 限制文件大小,日志截断
    # fh.setLevel(logging.WARNING)  # 文件设置WARNING级别
    
    # 把handler对象绑定到logger对象
    logger.addHandler(ch)
    logger.addHandler(fh)
    
    # 生成formatter对象
    file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s')
    
    # 把formatter对象绑定hander对象
    ch.setFormatter(console_formater)
    fh.setFormatter(file_formater)
    
    logger.debug("test_log")
    logger.warning("test_log_2")
    logger.debug("test log db backup 3")
    """
    输出web_jd.log.1  web_jd.log.2这三个文件
    web_jd.log:
    2018-03-03 16:54:32,307 - web - WARNING - test_log_2
    web_jd.log.1:
    2018-03-03 16:54:32,307 - web - DEBUG - test_log
    web_jd.log.2:
    2018-03-03 16:53:38,900 - web - DEBUG - test_log
    2018-03-03 16:53:38,901 - web - WARNING - test_log_2
    """
    根据时间截断日志

     handlers.TimedRotatingFileHandler()方法

    import logging
    from logging import handlers
    
    
    class IgnoreBackupLogFilter(logging.Filter):
        """忽略带db backup 的日志"""
    
        def filter(self, record):  # 固定写法
            return "db backup" not in record.getMessage()  # 字段不在日志消息内
    
    
    # 生成logger对象
    logger = logging.getLogger("web")
    logger.setLevel(logging.DEBUG)  # 不设置日志级别,默认日志级别是warning
    
    # 把filter对象添加到logger中
    logger.addFilter(IgnoreBackupLogFilter())
    
    # 生成handler对象
    ch = logging.StreamHandler()
    # ch.setLevel(logging.DEBUG)  # 屏幕debug级别
    # fh = logging.FileHandler("web.log")
    fh = handlers.TimedRotatingFileHandler("web_jd.log", when="S", interval=5, backupCount=3)
    # fh.setLevel(logging.WARNING)  # 文件设置WARNING级别
    # 把handler对象绑定到logger对象
    logger.addHandler(ch)
    logger.addHandler(fh)
    
    # 生成formatter对象
    file_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_formater = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s')
    # 把formatter对象绑定hander对象
    ch.setFormatter(console_formater)
    fh.setFormatter(file_formater)
    
    logger.debug("test_log")
    logger.warning("test_log_2")
    logger.debug("test log db backup 3")
    """两次执行生成两个文件
    文件web_jd.log.2018-04-18_19-29-22
    2018-04-18 19:29:22,013 - web - WARNING - test_log_2
    文件web_jd.log.2018-04-18_22-49-38
    2018-04-18 22:49:38,467 - web - DEBUG - test_log
    2018-04-18 22:49:38,469 - web - WARNING - test_log_2
    """
  • 相关阅读:
    jQuery的end() 方法
    jQuery.extend 函数使用详解
    AutoMapper完成Dto与Model的转换
    IoC实践--用Unity实现MVC5.0的IoC控制反转方法
    IoC实践--用Autofac实现MVC5.0的IoC控制反转方法
    Unity依赖注入使用详解
    React+BootStrap+ASP.NET MVC实现自适应和组件的复用
    oracle基础开发工具及常用命令
    Cisco配置发送日志到日志服务器
    Redis讲解
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8877093.html
Copyright © 2020-2023  润新知