logging模块
日志基础
日志级别(从低到高):
-
logging.NOTSET:不设置
-
loging.debug:最详细的日志信息,通常用于问题诊断
-
logging.info:信息的详细程度仅次于debug,通常记录关键节点的信息,用于确认一别都是按照预期的那样进行工作
-
logging.warning:当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
-
logging.error:由于一个更严重的问题导致某些功能不能正常运行时记录的信息
-
logging.critical:致命错误,导致程序不能继续运行时记录的信息
注意:logging的默认级别为warning
日志包含的内容
-
事件发生的时间
-
事件发生的位置
-
事件的严重程度(日志的级别)
-
事件的内容
logging模块提供的两种记录日志的方式
-
使用logging提供的模块级别的函数(其实也是对logging日志系统相关类的封装而已)
-
使用logging日志系统的四大组件
logging模块定义的模块级别的常用函数
import logging
#创建不同严重级别的的日志记录
logging.debug(msg, *args, **kwargs)
logging.info(msg, *args, **kwargs)
logging.warning(msg, *args, **kwargs)
logging.error(msg, *args, **kwargs)
logging.critical(msg, *args, **kwargs)
logging.log(level, *args, **kwargs) #创建一条严重级别为level的日志记录
logging.basicConfig(**kwargs) #对root logger进行一次性配置
`其中logging.basicConig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息
logging.basicConfig()函数说明
该方法用于为logging日志系统做一些基本配置,方法定义如下:
logging.basicConfig(**kwargs)
filename:指定日志输出目标文件的文件名,指定后日志内容就不会输出到控制台
filemode:指定日志文件的打开模式,默认为“a”,即追加。需要在指定filename时才有效
format:指定日志格式字符串,即指定日志输出时所包含的字段信息以及他们的顺序。
datefmt:dateformat的缩写。指定日期/时间格式。需要在format中包含时间字段%(asctime)s时才有效
level:指定日志器的日志级别
stream:指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。stream和filename不能同时提供,否则引发ValueError错误
style:指定format格式字符串的风格,可取值为"%"、"{"、和"$",默认为"%"
handlers:该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。filename、stream、handlers这三个配置只能有一个存在,否则引发ValueError异常
logging模块定义的格式字符串(format参数)字段
-
%(asctime)s:日志发生的时间,人类可读时间,如:2019-06-29
-
%(created)f:日志事件发生的时间——时间戳,即调用time.time()函数返回的值
-
%(relativeCreated)d:日志事件发生的时间相对于logging模块加载时间的相对毫秒数
-
%(msecs)d:日志事件发生的毫秒部分
-
%(levelname)s:该日志记录的文字形式的日志级别(DEBUG,INFO,WARNING,ERROR,CRITICAL)
-
%(levelno)s:该日志记录的数字形式的日志级别(10,20,30,40,50)
-
%(name)s:所使用的日志器的名称,默认是"root",因为默认使用的root logger
-
%(message)s:日志记录的文本内容,通过
msg % args
计算得到 -
%(pathname)s:调用日志记录函数的源码文件的全部路径
-
%(filename)s:pathname的文件名部分,包含文件后缀
-
%(module)s:filename的名称部分,不包含后缀
-
%(lineno)d:调用日志记录函数的源代码所在的行号
-
%(funcName)s:调用日志记录函数的函数名
-
%(process)d:进程ID
-
%(processName)s:进程名称
-
%(thread)d:线程ID
-
%(threadName)s:线程名称
其他说明
-
logging.basicConfig()函数是一个一次性的简单配置工具,即:只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作,多次调用的设置不是累加操作
-
日志器(logger)是有层级关系的,上面调用的logging模块级别的函数所使用的日志器是RootLogger类的实例,其名称为“root”,处于日志器层级关系最顶层,且以单例模式存在
-
如果要记录的日志中包含变量数据,可使用一个格式字符串作为这个事件的描述信息(logging.debug、logging.info等函数的第一个参数),然后将变量数据作为第二个参数*args的值进行传递,eg:logging.warning("%s is %d years old"%, "Tom",23)
-
logging.debug()、logging.info()等方法的定义中,除了msg和args参数外,还有一个**kwargs参数,他们支持3个关键兹参数:exc_info,stack_info,extra
-
exc_info:值为布尔类型,如果为True,就会将异常信息添加到日志消息中,如果没有异常信息则添加None到日志信息中
-
stack_info:值为布尔类型,默认为False,如果参数设置为True,栈信息会被添加到日志信息中
-
extra:这是一个字典(dict)参数,可以用来自定义消息格式所包含的字段,但是他的key不能与logging模块定义的字段冲突
-
logging模块的四大组件
-
loggers:提供应用程序代码直接使用的接口
-
handlers:用于将日志记录发送到指定的目的位置
-
filters:提供更详细的日志过滤功能,用于决定哪些日志记录将会被输出(其他的日志了会被忽略)
-
formatters:控制日志信息的最终输出格式
四大组件的关系:
-
日志器(logger)需要通过处理器(handler)将日志新出目标位置,如:文件、sys.stdout、网络等
-
不同的处理器(handler)可以将日志输出到不同的位置
-
日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置
-
每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志
即:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作
logging的使用
可以通过logging模块定义的模块级别的方法去完成简单的日志记录
只有级别大于或等于日志记录器指定级别的日志记录才会被输出,小于该级别的日志记录将会 被丢弃
logging日志模块相关类及其常用方法介绍
- 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参数来创建一个日志记录
如何得到一个Logger对象?:logging.getLogger(name = "root"),如果以相同的name参数多次调用getLogger方法,将会返回指向同一个Logger对象的引用
关于logger的层级结构与有效等级的说明:
logger的名称是一个以"."分割的层级结构,每个"."后面的logger都是"."前面的loggerd children,例如:有一个名称为foo的logger,foo.bar,foo.bar.baz都是foo的后代
logger有一个“有效等级(effective level)”的概念。如果一个logger上没有被明确设置一个level,那么该logger 会使用他parent的level,root logger总是会有一个明确的level设置(默认为warning)
child loggers在完成对耳垂处理后,默认会将日志消息传递给他们的祖先loggers相关的handlers,因此,我们不必为一个应用程序中所使用的所有loggers定义和配置handlers,只需要为一个顶层的logger配置handlers,然后按照需要创建child loggers就可足够。我们也可通过将一个logger的propagate属性设置为False来关闭这种传递机制
- Handler类:
Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件)。Logger对象可以通过addHandler来为自己添加0个或多个handler对象。如:一个应用程序要想实现以下几个日志需求:
-
把所有日志都发送到一个日志文件中
-
把所有严重级别大于等于error的日志发送到stdout(标准输出)
-
把所有严重级别软critical的日志发送到一个email邮件地址
这种场景就需要3个不同的handlers,每个handlers负责发送一个特定严重级别的日志到一个特定位置
hanlder常用配置方法:
-
Handler.setLevel():设置handler将会处理的日志消息的最低严重级别
-
Handler.setFormatter():为handler设置一个格式器对象
-
Handler.addFilter()和Handler.removeFilter():为handler添加和删除一个过滤器对象
注意:应用程序代码不应该直接实例化和使用Handler实例。因为Handler是一个基类,它只定义了所有handlers都应该有的接口,痛楚提供了一些子类可以直接使用或覆盖的默认行为。
常用Handler:
-
logging.StreamHandler:将日志消息发送Stream,如:std.out,std,err或任何file-like对象
-
logging.FileHandler:将日志消息发送到磁盘文件,默认情况下文件大小会无限增长
-
logging.handlers.RotationFileHandler:将日志消息发送到磁盘,并支持日志文件按大小切割
-
logging.hanlders.TimedRotatingFileHandler:将日志消息发送到磁盘文件,并支持日志文件按时间切割
-
logging.handlers.HTTPHandler:将日志消息发送给一个指定的HTTP服务器
-
logging.handlers.SMTPHandler:将日志消息发送给一个指定的email地址
-
logging.NullHandler:该Handler会忽略error messages,通常被想使用logging的library开发者用来避免"No handlers could be found for logger xxx"信息的出现
- Formater类
Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成
Formatter类的构造方法定义如下:logging.Foratter.__init__(fmt=None, datefmt = None, style = '%')
-
fmt:指定消息格式化字符串,如果不制定该参数则默认使用message的原始值
-
datefmt:指定日期格式字符串,默认:"%Y-%m-%d- %H:%M:%S"
-
style:可取值为"%`、%{、$",如果不指定则默认使用"%"
- 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.BB"的loggers产生的日志则会被过滤掉。如果name的值为空字符串,则允许所有的日志事件通过过滤
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0,表示不能通过过滤,返回值非0表示可以通过过滤。
ps:如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性。
最简单的日志输出
法一:
import logging
log_format = "%(asctime)s-%(levelname)s-%(message)s" #注意小括号及其后的s
date_formate = "%m-%d-%Y %H:%M:%S%p"
logging.basicConfig(level=logging.DEBUG,filename="test.log",
datefmt=date_formate,format=log_format)
#以不同的级别输出
logging.debug("This is a debug...")
logging.info("This is a info...")
logging.warning("This is a warning...")
logging.error("This is a error...")
logging.critical("This is a critical...")
以上代码在Test.log文件的输出结果如下
06-29-2019 20:44:47PM-DEBUG-This is a debug...
06-29-2019 20:44:47PM-INFO-This is a info...
06-29-2019 20:44:47PM-WARNING-This is a warning...
06-29-2019 20:44:47PM-ERROR-This is a error...
06-29-2019 20:44:47PM-CRITICAL-This is a critical...
法二:
import logging
log_format = "%(asctime)s-%(levelname)s-%(message)s" #注意小括号及其后的s
date_formate = "%m-%d-%Y %H:%M:%S%p"
logging.basicConfig(level=logging.DEBUG) #从debug输出,由于没有设置filename,所以从控制台输出
logging.log(logging.DEBUG,"This is a debug")
logging.log(logging.INFO,"This is a info")
logging.log(logging.WARNING,"This is a warning")
logging.log(logging.ERROR,"This is a error")
logging.log(logging.CRITICAL,"This is a critical")
控制台输出内容如下:
DEBUG:root:This is a debug #日志级别:日志器名称:日志内容
INFO:root:This is a info
WARNING:root:This is a warning
ERROR:root:This is a error
CRITICAL:root:This is a critical
使用四大组件记录日志
import logging
import logging.handlers
import datetime
logger = logging.getLogger("my_logger")
logger.setLevel(logging.DEBUG)
rf_handler = logging.handlers.TimedRotatingFileHandler("all.log", when="midnight", interval=1,
backupCount=7, atTime=datetime.time(0, 0, 0, 0))
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("This is a debug...")
logger.info("This is a info...")
logger.warning("This is a warning...")
logger.error("This is a error...")
logger.critical("This is a critical...")
在all.log中的输出内容如下:
2019-06-30 15:32:21,707-DEBUG-This is a debug...
2019-06-30 15:32:21,707-INFO-This is a info...
2019-06-30 15:32:21,708-WARNING-This is a warning...
2019-06-30 15:32:21,708-ERROR-This is a error...
2019-06-30 15:32:21,708-CRITICAL-This is a critical...
在error.log中的输出内容如下:
2019-06-30 15:32:21,708-ERROR-python高级功能之日志处理.py[:135]-This is a error...
2019-06-30 15:32:21,708-CRITICAL-python高级功能之日志处理.py[:136]-This is a critical...
网友评论