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

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

  • 相关阅读:
    Entity Framework 5.0运行.NET Framework 4.0之上在查询表达式中使用显示转换的一个问题
    How to get memcached all keys
    不同dll相同Type.FullName引发的问题
    WinDbg的cmdtree命令
    警惕缺省参数(Optional Parameters)对类型(Type)构造函数(Constructor)设计的影响
    如何解决Silverlight InitializeError #2103 Invalid or malformed application: Check manifest
    在北京拿5000.00元的工资
    分区表2
    C#操作config文件
    分区表1
  • 原文地址:https://www.cnblogs.com/Andy963/p/7067460.html
Copyright © 2011-2022 走看看