python logging日志模块

目录

1.日志的作用

2.日志级别

3.logging模块定义的格式字符串字段

4.logging模块的使用方式

5.logging模块基本使用

6. logging日志模块相关类及其常用方法介绍

7.使用logging四大组件记录日志 


1.日志的作用

项目部署上线后,开发者还需要监测程序运行的状态,但是又不能将运行的状态信息直接输出到控制台上,所以开发者可以把这些程序的运行状态信息根据不同的严重级别记录到日志文件中。这样的话当程序运行出现故障时,开发者可以查看日志文件中记录的错误信息快速定位到程序中存在的bug的位置,及时做出修复。

2.日志级别

logging模块把日志分为5个级别,详细描述信息如下(按照级别递增排序):

括号为级别所对应的数值

  • DEBUG(10)
  • INFO(20)
  • WARNING(30)
  • ERROR(40)
  • CRITICAL(50)

使用logging模块时需要设置记录日志的级别,程序运行起来后logging会记录大于等于所设置的级别的日志记录。比如设置的日志级别是INFO,则程序运行时INFO、WARNING、ERROR、CRITICAL四个级别的日志记录都会被记录下来。

日志级别(level)描述信息
DEBUG详细信息,一般用于调试程序,诊断程序中的问题
INFO记录关键节点信息,证明程序是按照开发者预期运行的
WARNING预料之外的事件发生记录的信息,但是此时程序还是可以正常运行的,比如:磁盘空间不足
ERROR由于严重的问题导致程序的一些功能已经不能正常运行了
CRITICAL发生严重错误导致程序崩溃

开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志记录来进行开发或部署调试;

应用程序上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志记录的效率。

日志级别的指定通常都是在应用程序的配置文件中进行指定的。指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出,小于该等级的日志记录将会被丢弃。

3.logging模块定义的格式字符串字段

字段/属性名称使用格式描述
asctime%(asctime)s日志事件发生的时间,如:2003-07-08 16:49:45,896
created%(created)f日志事件发生的时间-时间戳,是当时调用time.time()函数返回的值
relativeCreated%(relativeCreated)d日志事件发生的时间相对于logging模块加载时间的相对毫秒数
msecs%(msecs)d日志事件发生时间的毫秒部分
levelname%(levelname)s日志记录的文字形式的日志级别(‘DEBUG’、'INFO'、'WARNING'、'ERROR'、'CRITICAL')
levelno%(levelno)s日志记录的数字形式的日志级别(10、20、30、40、50)
name%(name)s使用的日志器名称,默认是'root',因为默认使用的是rootLogger
message%(message)s日志记录的文本内容,通过 msg % args 计算得到的
pathname%(pathname)s调用日志记录函数的源码文件的全路径
filename%(filename)spathname的文件名,包含文件名后缀
module%(module)sfilename的名称部分,不包含文件名的后缀
lineno%(lineno)d调用日志记录函数的源代码所在的行号
funcName%(funcName)s调用日志记录函数的函数名
process%(process)d进程ID
processName%(processName)s进程名称,Python 3.1新增
thread%(thread)d线程ID
threadName%(threadName)s线程名称

4.logging模块的使用方式

logging模块提供了两种记录日志信息的方式:

  • 第一种方式是使用logging提供的模块级别的函数
  • 第二种方式是使用logging日志系统的四大组件

其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。

logging模块定义的模块级别的常用函数如下:

函数说明
logging.debug(msg, *args, **kwargs)创建一条严重级别为DEBUG的日志记录
logging.info(msg, *args, **kwargs)创建一条严重级别为INFO的日志记录
logging.warning(msg, *args, **kwargs)创建一条严重级别为WARNING的日志记录
logging.error(msg, *args, **kwargs)创建一条严重级别为ERROR的日志记录
logging.critical(msg, *args, **kwargs)创建一条严重级别为CRITICAL的日志记录
logging.log(level, *args, **kwargs)创建一条严重级别为level的日志记录
logging.basicConfig(**kwargs)对root logger进行一次性配置

其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息,其他几个都是用于记录各个级别日志的函数。

logging库的四大组件如下:

组件说明
loggers提供应用程序代码直接使用的接口
handlers用于将日志记录发送到指定的目的位置
filters提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略)
formatters用于控制日志信息的最终输出格式

这些组件之间的关系:

  • 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
  • 不同的处理器(handler)可以将日志输出到不同的位置;
  • 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
  • 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
  • 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方;

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

5.logging模块基本使用

logging 使用非常简单,使用 basicConfig() 方法就能满足基本的使用需要,如果方法没有传入参数,会根据默认的配置创建Logger 对象,默认的日志级别被设置为 WARNING,默认的日志输出格式如上图,该函数可选的参数如下:

参数名称参数描述
filename保存日志记录的文件名
filemode文件模式,'r'、'w'、'a'
format日志输出的格式
datefat日志附带日期时间的格式
style格式占位符,默认为 "%" 和 “{}”
level设置日志输出级别
stream定义输出流,用来初始化StreamHandler对象,不能和filename参数一起使用,否则会抛出ValueError异常
handles定义处理器,用来创建Handler对象,不能和filename、stream参数一起使用,否则会抛出ValueError异常

logging.basicConfig()函数使用默认参数打印日志记录到控制台示例如下:

import logging

logging.basicConfig()
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')

logging.basicConfig()函数的level 默认是WARNING,所以只会打印出严重级别大于等于WARNING的日志记录,打印日志记录如下:

WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical message

 上面输出结果中每行日志记录的各个字段含义分别是:

日志级别:日志器名称:日志内容

 logging.basicConfig()函数设置filename和level参数后输出日志记录到log文件示例如下:

import logging

logging.basicConfig(filename="test.log", filemode="w", format="%(asctime)s %(name)s:%(levelname)s:%(message)s", datefmt="%d-%m-%Y %H:%M:%S", level=logging.DEBUG)
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')

 生成日志文件 test.log ,日志记录内容如下:

29-06-2021 20:26:30 root:DEBUG:This is a debug message
29-06-2021 20:26:30 root:INFO:This is an info message
29-06-2021 20:26:30 root:WARNING:This is a warning message
29-06-2021 20:26:30 root:ERROR:This is an error message
29-06-2021 20:26:30 root:CRITICAL:This is a critical message

但是当发生异常时。直接使用无参数的debug()、info()、warning()、error()、critical()、方法并不能记录异常信息,需要设置exc_info参数为True才可以,或者使用exception()方法,还可以使用log()方法,但要设置日志级别和exc_info参数,三种方法示例如下:

import logging

logging.basicConfig(filename="test.log", filemode="w", format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
                    datefmt="%d-%M-%Y %H:%M:%S", level=logging.DEBUG)
a = 5
b = 0
try:
    c = a / b
except Exception as e:
    # 下面三种方式三选一,推荐使用第一种
    logging.exception(e)
    logging.error(e, exc_info=True)
    logging.log(level=logging.DEBUG, msg=e, exc_info=True)

输出到test.log文件中的错误日志记录内容如下:

29-49-2021 20:49:21 root:DEBUG:division by zero
Traceback (most recent call last):
  File "F:/proxyPool/3.py", line 7, in <module>
    c = a / b
ZeroDivisionError: division by zero

 在上面的基础上,再来设置一下日志格式和日期/时间格式

import logging

LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"

logging.basicConfig(filename='test.log', level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)

logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")

test.log日志文件中看到如下输出内容:

06/29/2021 21:19:30 PM - DEBUG - This is a debug log.
06/29/2021 21:19:30 PM - INFO - This is a info log.
06/29/2021 21:19:30 PM - WARNING - This is a warning log.
06/29/2021 21:19:30 PM - ERROR - This is a error log.
06/29/2021 21:19:30 PM - CRITICAL - This is a critical log.

6. logging日志模块相关类及其常用方法介绍

下面介绍与logging四大组件相关的类:Logger, Handler, Filter, Formatter

Logger类

Logger对象有3个任务要做:

  1. 向应用程序代码暴露几个方法,使应用程序可以在运行时记录日志消息;
  2. 基于日志严重等级(默认的过滤设施)或filter对象来决定要对哪些日志进行后续处理;
  3. 将日志消息传送给所有感兴趣的日志handlers;

Logger对象常用的方法分为两类:配置方法 和 消息发送方法

最常用的配置方法如下:

方法描述
Logger.setLevel()设置日志器将会处理的日志记录的最低严重级别
Logger.addHandler()和Logger.removeHandler()为该logger对象添加和移除一个handler对象
Logger.addFilter()和Logger.removeFilter()为该logger()对象添加和移除一个filter对象

logger对象配置完成后,可以使用下面的方法来创建日志记录:

方法描述
Logger.debug()、Logger.info()、Logger.warning、Logger.error()、Logger.critical()创建一个与他们的方法名对应严重级别的日志记录
Logger.exception()创建一个类似于Logger.error()的日志记录
Logger.log需要传入一个明确的日志level参数来创建一个日志记录

使用logging.getLogger()来获取Logger对象:logging.getLogger()方法有一个可选参数name,该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为’root’。若以相同的name参数值多次调用getLogger()方法,将会返回指向同一个logger对象的引用。

Handler类

Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:

  1. 把所有日志都发送到一个日志文件中;
  2. 把所有严重级别大于等于error的日志发送到stdout(标准输出);
  3. 把所有严重级别为critical的日志发送到一个email邮件地址;

这种场景就需要3个不同的handler,每个handler负责发送一个特定严重级别的日志记录到一个特定的位置。

handler配置方法如下:

方法描述
Handler.setLevel()设置handler将会处理的日志记录的最低严重级别
Handler.setFormatter()为handler设置一个格式器对象
Handler.addFilter()和Handler.removeFilter()为handler添加和删除一个过滤器对象

常用的Handler类如下:

Handler描述
logging.StreamHandler把日志记录输出到Stream,如std.out,std.err,或任何file-like对象
logging.FileHandler把日志记录输出到磁盘文件,默认情况下文件大小会无限增长
logging.handlers.RotatingFileHandler把日志记录输出到磁盘文件,并支持日志文件按大小切割
logging.handlers.TimedRotatingFileHandler把日志记录输出到磁盘文件,并支持日志文件按时间切割
logging.handlers.HTTPHandler把日志记录以GET或POST的请求方式发送给一个HTTP服务器
logging.handlers.SMTPHandler把日志记录发送给一个指定的email地址
logging.NullHandler该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免 'No handlers could be found for logger XXX' 信息的出现

常用的handler是TimedRotatingFileHandler( filename [, when [, interval [, backupCount] ] ] )根据时间来切割日志文件,参数解释如下:

filename 是输出日志的文件名

when 是一个字符串,定义了日志切分的间隔时间单位,这是一个枚举类,可选参数如下:

"S":Second 秒
"M":Minutes 分钟
"H":Hour 小时
"D":Days 天
"W":Week day(0 = Monday)
"midnight":Roll over at midnight(凌晨进行切割)

interval 是间隔时间单位的个数,指等待多少个 when 的时间后 Logger 会自动重建日志文件继续进行日志记录
这里需要注意的一点是,如果创建的文件和已有文件存在重名的情况,则会对历史的文件进行覆盖操作,所以使用好 suffix 避免文件名称重复,如果修改了suffix也同时要修改extMatch(正则匹配规则)

backupCount 是保留日志的文件个数
默认的参数是0,这种设置下是不会自动删除文件的。如果设置为 N(正整数),则会在创建新的日志文件时会检查日志文件个数是否到达 N,达到了的话就会从最先创建的开始删除,从而达到维持日志文件个数为 N 的目标

Formater类

Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。

Formatter类的构造方法定义如下:

logging.Formatter(fmt=None, datefmt=None, style='%')

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

  1. fmt:指定消息格式化字符串,如果不指定该参数则默认使用message的原始值
  2. datefmt:指定日期格式字符串,如果不指定该参数则默认使用"%Y-%m-%d %H:%M:%S"
  3. style:Python 3.2新增的参数,可取值为 '%'、'{}' 和 '$',如果不指定该参数则默认使用 '%'

Filter类 

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

class logging.Filter(name='')
    filter(record)

        比如,一个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的值为空字符串,则允许所有的日志事件通过过滤。

filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。

说明:

  • 如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性。
  • 我们还可以通过filter做一些统计工作,比如可以计算下被一个特殊的logger或handler所处理的record数量等。

7.使用logging四大组件记录日志 

现在,我们对logging模块的重要组件及整个日志流处理流程都应该有了一个比较全面的了解,下面我们来看一个例子。

  • 需求
  1. 要求将所有级别的所有日志都写入磁盘文件中;
  2. all.log文件中记录所有的日志信息,日志格式为:日期和时间 - 日志级别 - 日志信息;
  3. error.log文件中单独记录error及以上级别的日志信息,日志格式为:日期和时间 - 日志级别 - 文件名[:行号] - 日志信息;
  4. 要求all.log在每天凌晨进行日志切割;
  • 分析 
  1. 要记录所有级别的日志,因此日志器的有效level需要设置为最低级别–DEBUG;
  2. 日志需要被发送到两个不同的目的地,因此需要为日志器设置两个handler;另外,两个目的地都是磁盘文件,因此这两个handler都是与FileHandler相关的;
  3. all.log要求按照时间进行日志切割,因此他需要用logging.handlers.TimedRotatingFileHandler; 而error.log没有要求日志切割,因此可以使用FileHandler;
  4. 两个日志文件的格式不同,因此需要对这两个handler分别设置格式器;
  • 代码实现

import logging
import logging.handlers

logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)

rf_handler = logging.handlers.TimedRotatingFileHandler(filename='all.log', when='midnight', interval=1, backupCount=7)
rf_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))

f_handler = logging.FileHandler('error.log')
f_handler.setLevel(logging.ERROR)
f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))

logger.addHandler(rf_handler)
logger.addHandler(f_handler)

logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
logger.critical('critical message')

all.log文件输出

2021-06-30 10:25:27,531 - DEBUG - debug message
2021-06-30 10:25:27,532 - INFO - info message
2021-06-30 10:25:27,532 - WARNING - warning message
2021-06-30 10:25:27,532 - ERROR - error message
2021-06-30 10:25:27,532 - CRITICAL - critical message

error.log文件输出

2021-06-30 10:25:27,532 - ERROR - 3.py[:20] - error message
2021-06-30 10:25:27,532 - CRITICAL - 3.py[:21] - critical message

 了解更多关于python和爬虫的知识欢迎关注微信公众号:丸子打豆豆

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值