• Python标准库学习之logging


    前言

    在python程序中,出于调试监测或者追踪(track)的目的,一般会在关键的部位加print语句来输出监测的变量值,但对于复杂的程序来讲,这样的调试手段就远远不够了,这也是logging库存在的意义,也有必要进行学习一番。

    Logging 提供了一套函数组来满足简单记录的需求,比如debug(),info(),error(),和critical().

    这些个函数其实是有层次的,这也是logging的重要理念之一,也就是可以设置一定的阈值,当低于该阈值时候,不管它,当等于或者高于该阈值时,才进行记录。

    Level When it’s used
    DEBUG Detailed information, typically of interest only when diagnosing problems.
    INFO Confirmation that things are working as expected.
    WARNING An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.
    ERROR Due to a more serious problem, the software has not been able to perform some function.
    CRITICAL A serious error, indicating that the program itself may be unable to continue running.

    注意:上表的层次就是由低到高。

    默认的level是WARNING,追踪事件的方式多种多样,最简单的就是直接输出到console,另一个常见的方式是写入文件中。

    初级应用

    初级应用就是简单的通过logging.basicConfig进行简单的设置(或者不设置,用默认的),然后直接用logging.debug(),logging.info(),logging.warning()等输出。

    小例子

    import logging
    logging.warning('Watch out!')  # will print a message to the console
    logging.info('I told you so')  # will not print anything
    

    outputs:

    WARNING:root:Watch out!
    

    因为默认层是WARINING,所以logging.info()不输出。

    Logging 到文件

    import logging
    logging.basicConfig(filename='example.log',level=logging.DEBUG)
    logging.debug('This message should go to the log file')
    logging.info('So should this')
    logging.warning('And this, too')
    

    outputs:

    DEBUG:root:This message should go to the log file
    INFO:root:So should this
    WARNING:root:And this, too
    

    改变输出的格式

    import logging
    logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
    logging.debug('This message should appear on the console')
    logging.info('So should this')
    logging.warning('And this, too')
    

    outputs:

    DEBUG:This message should appear on the console
    INFO:So should this
    WARNING:And this, too
    

    这里注意'root'不见了,因为我们重新设置了输出格式,格式中只有levelname和messages。

    显示时间

    import logging
    logging.basicConfig(format='%(asctime)s %(message)s')
    logging.warning('is when this event was logged.')
    

    outputs:

    2020-09-13 14:45:26,252 is when this event was logged
    

    高级用法

    logging实际上采用了模块化的方法,提供了几个组件:loggers,handlers,filters,和formatters.

    官网是这样定义几个组件的作用的:

    • Loggers expose the interface that application code directly uses.
    • Handlers send the log records (created by loggers) to the appropriate destination.
    • Filters provide a finer grained facility for determining which log records to output.
    • Formatters specify the layout of log records in the final output.

    被追踪的信息就是在Logger,Handler,Filter,Formatter之间传递:

    首先Logging是通过调用Logger类实例的方法进行的,每个实例都有个名称,用'.'来作为命名空间的继承关系。

    常用的对于module-level的logger的创建方法是

    logger = logging.getLogger(__name__)
    

    然后需要为log message设定destination,比如file,http get/post,email, sockets,queue等。destination是通过handler来确定的。默认是没有任何的destination的,可通过basicConfig()来进行简单的设置:

    image-20200913151520493

    装配

    有3种装配方法:

    • 用logger,handler,filter,formatter对象的装配方法进行装配
    import logging
    
    # create logger
    logger = logging.getLogger('simple_example')
    logger.setLevel(logging.DEBUG)
    
    # create console handler and set level to debug
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    
    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # add formatter to ch
    ch.setFormatter(formatter)
    
    # add ch to logger
    logger.addHandler(ch)
    
    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
    
    • 用fileConfig()方法

    logging.conf文件

    [loggers] #声明logger
    keys=root,rotateFileDemo #键值对
    [handlers] #声明handler
    keys=consoleHandler,rotateHandler #键值对
    [formatters] #声明formatter
    keys=simpleFormatter#键值对
    
    [logger_root] #对于root的配置,必须是looger_xxx的形式
    level=DEBUG
    handlers=consoleHandler
    
    [logger_rotateFileDemo]#对于rotateFileDemo的配置
    level=DEBUG
    handlers=rotateHandler 
    qualname=rotateDemo  #logger名称,应用程序通过 logging.getLogger获取。对于不能获取的名称,记录到root模块。
    propagate=0  # 是否继承父类的log 信息,0:否 1:是.其父类这里是root
    
    
    [handler_consoleHandler] #对于consoleHandler的配置,必须是handler_xxx的形式
    class=StreamHandler  #类
    level=DEBUG 
    formatter=simpleFormatter 
    args=(sys.stdout,)  #类参数
    
    [handler_rotateHandler] 
    class=handlers.RotatingFileHandler  #这里注意是 handlers.RotatingfileHandler
    level=DEBUG
    formatter=simpleFormatter
    args=('app.log','a',1024,5)  #该类的参数
    
    [formatter_simpleFormatter] #simpleFormatter的定义及配置
    format=%(asctime)s-%(name)s-%(levelname)s-%(message)s
    

    loggingDemo.py

    import logging
    import logging.config 
    import time 
    logging.config.fileConfig('logging.conf')
    logger=logging.getLogger('rotateDemo')
    
    while True:
        logger.info('info message')
        time.sleep(0.1)
    

    对于RotatingFileHandler,这里args=('app.log','a',1024,5) ,即记录到app.log中,当超过1024 bytes后,分别备份为app.log.01,app.log.02,app.log.03,app.log.04,app.log.05,然后再有的话不再增加。

    • 运用dictConfig()进行配置

    传入dictConfig()的dict,必须包含以下的键:

    • version,当前唯一合法值是1,主要考虑到向后兼容性。
    • formatters
    • filters
    • handlers
      • class(强制必须有)
      • level(可选)
      • formatter(可选)
      • filter(可选)
    • loggers
      • level(可选)
      • propagare(可选)
      • filters(可选)
      • handlers(可选)
    • root,设定root logger。
    • incremental,配置是否解释为在已经存在的配置上增加,默认为False,意思就是设定的配置将代替原来的配置。
    • disable_existing_loggers:是否使得已经存在loggers失效,默认为True,如果incremental 是True,则忽略该项。

    例子:

    import logging 
    import logging.config
    LOGGING={
        'version':1,
        'formatters':{
            'simple':{
                'format':'[%(asctime)s]%(levelname)s%(message)s',
                'datefmt':'%Y-%m-%d %H:%M:%S'
            },
            'verbose':{
                'format':'[%(asctime)s]%(levelname)s[%(name)s.%(funcName)s%(lineno)d%(message)s',
                'datefmt':'%Y-%m-%d %H:%M:%S'
            }
        },
        'handlers':{
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
                'formatter':'simple'
            },
            'development_logfile':{
                'level':'DEBUG',
                'class':'logging.FileHandler',
                'filename':'test.log',
                'formatter':'verbose',
    
            },
                'production_logfile':{
                'level':'ERROR',
                'class':'logging.handlers.RotatingFileHandler',
                'filename':'test_production.log',
                'maxBytes':1024,
                'backupCount':3,
                'formatter':'simple'
            },
        'dba_logfile':{
            'level':'DEBUG',
            'class':'logging.handlers.WatchedFileHandler',
            'filename':'test_dba.log',
            'formatter':'simple'
        },
        },
        'root':{
            'level':'DEBUG',
            'handlers':['console'],
        },
        'loggers':{
            'coffee':{
                'handlers':['development_logfile'],
                # 'propagare':0,
                # 'qualname':'coffee'
            },
        'dba':{
            'handlers':['dba_logfile']
        }
        }
    
    }
    
    logging.config.dictConfig(LOGGING)
    logger=logging.getLogger('coffee')
    logger.info('dictlogger info')
    

    ##### 愿你一寸一寸地攻城略地,一点一点地焕然一新 #####
  • 相关阅读:
    nginx 按天生成日志
    cmder
    EXCEL最大行数问题:org.apache.xmlbeans.impl.store.Saver$TextSaver.resize(Saver.java:1700)
    nginx configure 错误记录
    Flume NetCat Demo
    Flume
    hbase
    kafka安装配置
    azkaban
    sqoop
  • 原文地址:https://www.cnblogs.com/johnyang/p/13661705.html
Copyright © 2020-2023  润新知