ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python日志logging模块详解

2021-04-13 20:00:28  阅读:145  来源: 互联网

标签:logging level Python msg 日志 logger Logger


1. 简述

把我自己理解的概念用通俗易懂的话讲出来大概就是

查看日志是开发人员日常获取信息、排查异常、发现问题的最好途径,日志记录中通常会标记有异常产生的原因、发生时间、具体错误行数等信息,这极大的节省了我们的排查时间,无形中提高了编码效率。

2. 级别分类

下表是日志按照级别分类,指的是 Debug、Info、WARNING、ERROR 、CRITICAL 等严重等级进行划分。

级别数值说明
CRITICAL50十分严重的问题导致程序已经不能运行
ERROR40有错误导致程序的某些功能不能按照预期工作
WARNING30可以是一些意料之外的问题,也可以是一些预期将要发生的问题的警告
INFO20表明程序正常运行
DEBUG10比较详细的信息,一般在调试问题的时候使用
NOTSET0没有日志级别,任何信息都会输出

上述级别分类是在日志系统里通用的。在 python 中对应的模块函数分别为 debug()、info()、warning()、error()、critical() 
Python 中日志的默认等级是 WARNING , DEBUG  和 INFO  级别的日志将不会得到显示,在 logging 中更改设置。

3. 日志的输出

先来简单使用下 python 的 logging 模块输出日志的功能

import logging

logging.debug('this is a debug msg')
logging.info('this is a info msg')
logging.warning('this is a warning msg')
logging.error('this is a error msg')

输出如下

WARNING:root:this is a warning msg
ERROR:root:this is a error msg

这样的输出证实了上面所说

“Python 中日志的默认等级是 WARNINGDEBUG  和 INFO  级别的日志将不会得到显示”

我们来修改下 Python 默认的日志等级为 DEBUG

import logging

logging.basicConfig(level=logging.DEBUG)
logging.debug('this is a debug msg')
logging.info('this is a info msg')
logging.warning('this is a warning msg')
logging.error('this is a error msg')

再来看看输出结果,正如我们所预期的那样

DEBUG:root:this is a debug msg
INFO:root:this is a info msg
WARNING:root:this is a warning msg
ERROR:root:this is a error msg

4. 模块函数及四大组件

上面的代码只是将我们想要的日志信息输出到了控制台,如果我们要记录日志到文件中,就要用到强大的logging模块级别的函数,或者是 logging 的四大组件了。

上面设置日志级别的 logging.DEBUG 就是所说的级别函数,而四大组件分别是 loggers、handlers、filters、formatters ,从名字上也不难看出这些组件的作用

组件名称logging中对应的类功能
日志器Logger提供日志系统使用的接口
处理器Handlerlogger 收集到的日志发送到指定的地方
过滤器Filterlogger 收集日志的时候提供过滤规则
格式器Formatter设定日志的输出格式

工作原理

日志器(logger)是入口,真正工作的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。

Logger

Logger 的三个功能点

  • 提供记录日志的接口,如 logging.debug
  • 基于日志的严重级别或 filter 对象来对日志进行处理,过滤
  • 将处理过的日志信息发送到设定的 handlers

Logger 对象常用方法如下

方法功能描述
Logger.setLevel()设置日志处理的最低严重级别
Logger.addHandler()将 handler 对象添加到 logger 对象中
Logger.removeHandler()将 hanlder 对象从 logger 对象中移除
Logger.addFilter()将 filter 对象添加到 logger 对象中
Logger.removeFilter()将 filter 对象从 logger 对象中移除

获取 logger 对象有两种方式,我们通常使用第二种方式

  • 通过 Logger 类的实例化方法创建一个 Logger 类的实例,, 例如 logger = Logger()
  • 通过logging.getLogger()  方法。 logging.getLogger() 方法有一个可选参数 name ,该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为 ‘root’。若以相同的 name 参数值多次调用 getLogger()  方法,将会返回指向同一个 logger 对象的引用。

对于 logger 层级的补充

  • logger 的名称是一个以 . 分割的层级结构,每个 . 后面的 logger 都是 . 前面的 logger 的 child。例如,有一个名称为 A 的 logger,其它 logger 名称分别为 A.B, A.B.C 都是 A 的后代。
  • logger 有一个"有效等级(effective level)"的概念。如果一个 logger 上没有被明确设置一个 level,那么该logger将会向上查找已经明确定义了 level 的 logger 。需要说明的是,root logger 总是会有一个明确的level设置(默认为 WARNING)。当决定是否去处理一个已发生的事件时,logger 的有效等级将会被用来决定是否将该事件传递给该 logger 的 handlers 进行处理。
  • child loggers 在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先 loggers 相关的 handlers。因此,我们不必为一个应用程序中所使用的所有 loggers 定义和配置 handlers,只需要为一个顶层的 logger 配置 handlers,然后按照需要创建 child loggers 就可足够了。我们也可以通过将一个 logger 的 propagate 属性设置为False来关闭这种传递机制。

Handler

Hander 常用的方法也不多

方法功能描述
Handler.setLevel()设置日志处理的最低严重级别
Handler.setFormatter()为 handler 对象设置一个格式器对象
Handler.addFilter()将 filter 对象添加到 handler 对象中
Handler.removeFilter()将 filter 对象从 handler 对象中移除

但是和 Logger 类似,我们在获取 handler 对象的时候最好不要直接实例化 Handler 这个基类。logging 模块已经为我们定义好了一些常用的 handler

  • logging.StreamHandler 将日志消息发送到 Stream, 如 std.out, std.err
  • logging.FileHandler 将日志消息发送到文件中,默认是 a 模式追加写入
  • logging.handlers.SMTPHandler 将日志消息发送到指定邮箱
  • logging.handlers.HTTPHandler 将日志消息以 GET 或是 POST 的方式发送到一个 HTTP服务器
  • logging.handlers.RotatingFileHandler 日志文件支持按照大小切割并发送到文件
  • logging.handlers.TimedRotatingFileHandler 日志文件支持按照时间切割并发送到文件

Formatter

Formater 对象用于配置日志信息的最终顺序、结构和内容。与 logging.Handler 基类不同的是,可以直接实例化 Formatter 类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个 Formatter 的子类来完成。 Formatter 类的构造方法定义如下
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

该构造方法接收 3 个可选参数:

  • fmt :指定消息格式化字符串,如果不指定该参数则默认使用 message 的原始值
  • datefmt :指定日期格式字符串,如果不指定该参数则默认使用 %Y-%m-%d %H:%M:%S
  • style :可取值为 %, {, $ ,如果不指定该参数则默认使用 “%”

fmt 中允许使用的变量可以参考下表。

  • **%(name)s**  Logger的名字
  • **%(levelno)s**  数字形式的日志级别
  • **%(levelname)s**  文本形式的日志级别
  • **%(pathname)s**  调用日志输出函数的模块的完整路径名,可能没有
  • **%(filename)s**  调用日志输出函数的模块的文件名
  • **%(module)s**  调用日志输出函数的模块名
  • **%(funcName)s**  调用日志输出函数的函数名
  • **%(lineno)d**  调用日志输出函数的语句所在的代码行
  • **%(created)f**  当前时间,用UNIX标准的表示时间的浮点数表示
  • **%(relativeCreated)d**  输出日志信息时的,自Logger创建以来的毫秒数|
  • **%(asctime)s**  字符串形式的当前时间。默认格式是 “yyyy-mm-dd HH:MM:SS,SSS”
  • **%(thread)d**  线程ID
  • **%(threadName)s**  线程名
  • **%(process)d**  进程ID
  • **%(message)s**  用户输出的消息

Filter

Filter 可以被 Handler 和 Logger 用来做比 level 更细粒度的、更复杂的过滤功能。Filter 是一个过滤器基类,它只允许某个 logger 层级下的日志事件通过过滤。

比如,一个 filter 实例化时传递的 name 参数值为 A.B ,那么该 filter 实例将只允许名称为类似如下规则的 loggers 产生的日志记录通过过滤: A.B, A.B.C, A.B.C.D, A.B.D ,而名称为 A.BB, B.A.B 的 loggers 产生的日志则会被过滤掉。如果 name 的值为空字符串,则允许所有的日志事件通过过滤。

5. 实战应用

import logging
import os
import sys


BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_PATH)


def my_logger(log_name='NANCY_LOG',
              log_file=f'{BASE_PATH}/log_demo/log/nancy.log',
              level=logging.DEBUG):
    # 创建logger对象
    logger = logging.getLogger(log_name)
    logger.setLevel(level)       # 添加等级

    # 创建控制台 console handler
    ch = logging.StreamHandler()
    ch.setLevel(level)

    # 创建文件   handler
    fh = logging.FileHandler(log_file)
    fh.setLevel(level)

    # 创建   formatter
    formatter = logging.Formatter('%(asctime)s '
                                  '%(filename)s '
                                  '[line:%(lineno)s] '
                                  '%(name)s '
                                  '%(levelname)s: '
                                  '%(message)s')

    # 添加日志格式  formatter
    # ch.setFormatter(formatter)
    fh.setFormatter(formatter)

    # 把ch fh 添加到  logger中
    logger.addHandler(ch)
    logger.addHandler(fh)

    return logger


def main():
    # 测试
    logger = my_logger(log_name='nancy test',
                       level=logging.DEBUG)

    logger.info('test logging info'.center(30, '*'))
    logger.debug('test logging debug'.center(30, '*'))
    logger.error('test logging error'.center(30, '*'))
    logger.warning('test logging warning'.center(30, '*'))
    logger.critical('test logging critical'.center(30, '*'))


if __name__ == '__main__':
    main()

标签:logging,level,Python,msg,日志,logger,Logger
来源: https://blog.csdn.net/weixin_45651841/article/details/115676756

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有