zoukankan      html  css  js  c++  java
  • python3 logging

    https://docs.python.org/3.5/library/logging.html,先3.5是因为我当前的python 版本是3.5

    之所以要来详细的写是因为之前学django时也有这个,不是很理解,所以这里就多了解下。

    写到后面发现整个文章一点条理都没有,但由于内容比较多,就不重新整理了

    logging框架中主要由四个部分组成:

        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.
    
    • Loggers: 提供应用直接调用的接口
    • Handlers: 决定将日志记录发送至正确的目的地
    • Filters: 提供更精细的决定哪些日志输出的能力,简单点说就是决定哪些输出哪些不输出
    • Formatters: 制定最终输出的格式。

    logger对象

    事实上logger是不直接实例化的,但是我们可以通过模块级别的函数logging.getLogger(name)来调用。如果多次通过同一个名字调用getLogger()将只能得到对同一个对象的引用。

    注意: logging.getLogger(name) 中的name是一个支持通过“.”(点号)分层级的值。

    例如: 你定义一个logger: foo,那么foo.bar, foo.baz,就都算作它的子代,就是继承,有父子关系。

    logger名字的层级与python中包的层级是一致的。所以为了区分它,如果你基于模块来组织logger,

    那么建议你使用:logging.getLogger(__name__)这种形式,因为对于模块而言,在python

    包的命名空间中__name__的值就是模块的名字。

    常用方法:

    Logger.setLevel(lvl):

    将logger的门限设置为lvl,低于此等级的信息将被忽略,当一个Logger被创造出来时,它的等级被设置为:

    NOTSET(未设置) 这样的结果就是: 如果它是一个root logger,它将处理所有的信息,如果没有root logger

    它将继承父级的logger等级。Note: root logger可通过level waring来创建,注意这里是个坑,

    事实上默认root logger等级为warning,不要搞错了

     级别设定:前面是名字,后面是对应的数字值

     

    Logger.exception(msg, *args, **kwargs)

    以error级别来记录信息,异常信息也会被添加到信息(message),需要exception handler调用才行

    Logger.addFilter(filt)

    添加指定的过滤器

    Logger.removeFilter(filt)

    移除指定的过滤器

    这里的方法多得让人想撞死在屏幕上,以后慢慢更新吧。

    Handler

    • Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
    • Handler.setFormatter():给这个handler选择一个格式
    • Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象

    handler有多达15种,这里只说下常见的几种:

    1.logging.StreamHandler 

    发送信息到流,类文件对象即可,如终端,文件等

    2.logging.FileHandler

    发送信息到硬盘文件

    3.logging.RotatingFileHandler
    这个Handler类似于上面的FileHandler,但是它可以管理文件大小,轮询日志文件(不知道是不是检测日志文件大小)。

    当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出。

    4.logging.handlers.TimedRotatingFileHandler

    这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,

    而是间隔一定时间就 自动创建新的日志文件。

    Formatter

    Formatters 决定了记录格式。Formatter会将传递来的信息拼接成一条具体的字符串,

    默认情况下Format只会将信息%(message)s直接打印出来。Format中有一些自带的LogRecord属性可以使用,如下表格:

    其中lineno,pathname,经过实测了,并不是有些博客里说的什么当前日志记录的行号。后面会有实例。

    这里有一个简单的应用 的例子,记录出错信息:

    #!/usr/bin/env python
    #coding:utf-8
    # Created by Andy @ 2017/6/22
    
    
    import logging
    
    
    logging.basicConfig(level=logging.DEBUG,
            format='%(asctime)s %(pathname)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s ',
            datefmt='%a, %d %b %Y %H:%M:%S',
            filename=r'D:Codingoldboyday13 module	est.log',
            filemode='w')
    
    
    def login():
    	while True:
    		try:
    			name = input('Input user name:')
    			password = int(input('Input password:')) # 这里故意转成整型,触发异常
    			if name == 'andy' and password == 'nopasswd':
    				print('logging succeed!')
    		except ValueError as e:
    			logging.debug(e)
    			break
    
    if __name__ == '__main__':
    	login()
    

     终端验证

    Input user name:andy
    Input password:nopasswd
    
    Process finished with exit code 0
    

     打开test.log:

    Fri, 23 Jun 2017 09:56:40 D:/Coding/oldboy/day13 module/log.py log.py[line:24] DEBUG invalid literal for int() with base 10: 'nopasswd' 
    

     注意看,lineno 并不是在日志里面的行号,而是你代码的行号,在24行调用了logging.debug(e)

     这里现定义一个一simple_logger:

    #!/usr/bin/env python
    #coding:utf-8
    # Created by Andy @ 2017/6/22
    
    
    import logging
    import os
    
    log_path = os.path.join(os.getcwd(),'test.log')
    
    logging.basicConfig(level=logging.DEBUG,
            format='%(asctime)s %(pathname)s line:%(lineno)d %(message)s ',
            datefmt='%Y-%m-%d %H:%M:%S', # 将日期格式化成正常模式
            filename=log_path,
            filemode='a') # 指定成追加模式,默认就是追加,所以这句非必须
    
    simple_logger = logging.getLogger('simple')
    fh = logging.StreamHandler() #输出到终端
    fh.setLevel(level = logging.WARNING) #等级比默认的高,但调用时必须一致
    formatter = logging.Formatter("%(asctime)s %(message)s %(levelname)s")
    fh.setFormatter(formatter)
    simple_logger.addHandler(fh)
    
    
    def login():
    	while True:
    		try:
    			name = input('Input user name:')
    			password = int(input('Input password:')) # 这里故意转成整型,触发异常
    			if name == 'andy' and password == 'nopasswd':
    				print('logging succeed!')
    		except ValueError as e:
    			simple_logger.warning(e)
    			break
    
    if __name__ == '__main__':
    	login()
    

     运行:

    终端输出:

    Input user name:andy
    Input password:andy
    2017-06-24 09:55:57,395 invalid literal for int() with base 10: 'andy' WARNING
    

     test.log文件:

    2017-06-24 09:55:57 D:/Coding/oldboy/day13 module/log.py line:33 invalid literal for int() with base 10: 'andy' 
    

     这晨需要 注意的是:因为默认的logger等级是debug,所以它什么消息都会输出,而simple_logger则只输出比自身高等级的信息,

    并且:调用simple_logger时必须比定义的等级高于或者等于定义的等级,这句话什么意思呢?看上面的例子,simple_logger

    定义时的等级为warning,那么你调用时最少得warning等级,或者比它高的critical才能正常打印消息(它规定就是这样),否则你是看不到任何效果的

    (这里坑了好久,一直没消息打印而找不到原因,root logger默认等级是warning,而非Noset),但是如果你调用的等级比较低,

    并不影响root 这个logger打印日志信息。

    填坑来了:

    如果没指定默认的logger的等级,那么默认的等级warning就会生效,所以才出现上面的情况,如果需要将debug等级的信息也输入,那么,这里需要加一条:

    simple_logger.setLevel(logging.DEBUG)
    # 如果不设置此logger的级别,那么handler的记录是从logger传过来的,也就是默认从logger的warning来的
    

    下面是一个使用配置文件 的例子:

    #!/usr/bin/env python
    #coding:utf-8
    # Created by Andy @ 2017/6/25
    
    
    import logging
    import logging.config
    
    logging.config.fileConfig('logging.conf')
    
    # create logger
    logger = logging.getLogger('simpleExample')
    
    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
    

     配置文件:

    [loggers]
    keys=root,simpleExample
    
    [handlers]
    keys=consoleHandler,simpleHandler
    
    [formatters]
    keys=consoleFormatter,simpleFormatter
    
    [logger_root]
    level=DEBUG
    handlers=consoleHandler
    
    [logger_simpleExample]
    level=INFO
    handlers=simpleHandler
    qualname=simpleExample
    propagate=1
    
    [handler_consoleHandler]
    class=StreamHandler
    level=DEBUG
    formatter=consoleFormatter
    args=(sys.stdout,)
    
    [handler_simpleHandler]
    class=FileHandler
    level=INFO
    formatter=simpleFormatter
    args=('simple.log','w')
    
    
    [formatter_consoleFormatter]
    format=%(levelname)s :%(message)s
    
    [formatter_simpleFormatter]
    format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
    datefmt=
    

     之前的例子没已经删除了,找到原因:propagate=1 ,只有当propagate 为True时,logger的信息才能传到上一级logger,或者说父logger,如果你设置为0

    那么,就只有文件中有写入,而终端不会有信息打印出来。

  • 相关阅读:
    DC中为什么要用Uniquify?
    hdu 1596 find the safest road
    hdu2112 HDU Today
    hdu 2066 一个人的旅行
    poj 3026 Borg Maze
    poj 1979 Red and Black
    poj 1321 棋盘问题
    hdu 1010 Tempter of the Bone
    hdu 4861 Couple doubi
    codeforces584B Kolya and Tanya
  • 原文地址:https://www.cnblogs.com/Andy963/p/7067460.html
Copyright © 2011-2022 走看看