官方文档:html
https://docs.python.org/2/library/logging.htmlpython
logging模块提供了两种记录日志的方式:程序员
其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。网络
logging模块定义的模块级别的经常使用函数:app
函数 | 说明 |
---|---|
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)
函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息,其余几个都是用于记录各个级别日志的函数。socket
具体以下:函数
参数名称性能 |
描述测试 |
filenamethis |
将日志信息写入文件中,指定该设置项后日志信息就不会被输出到控制台了 |
filemode |
指定日志文件的打开模式,默认为'a'。须要注意的是,该选项要在filename指定时才有效 |
format |
指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。 |
datefmt |
指定日期/时间格式。须要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效。 |
level |
指定日志级别 |
stream |
指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。须要说明的是,stream和filename不能同时提供,不然会引起 ValueError异常 |
style |
Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%' |
handlers |
Python 3.3中新添加的配置项。该选项若是被指定,它应该是一个建立了多个Handler的可迭代对象,这些handler将会被添加到root logger。须要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,不然会引起ValueError异常。 |
上面的时间须要使用format中包含时间段,过于format还有以下参数:
字段/属性名称 |
使用格式 |
描述 |
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)s |
pathname的文件名部分,包含文件后缀 |
module |
%(module)s |
filename的名称部分,不包含后缀 |
lineno |
%(lineno)d |
调用日志记录函数的源代码所在的行号 |
funcName |
%(funcName)s |
调用日志记录函数的函数名 |
process |
%(process)d |
进程ID |
processName |
%(processName)s |
进程名称,Python 3.1新增 |
thread |
%(thread)d |
线程ID |
threadName |
%(thread)s |
线程名称 |
1、使用logging提供的模块级别的函数记录日志
logging的日志级别由低到高分为 debug(), info(), warning(), error() and critical() 5个级别
CRITICAL(50) > ERROR(40) > WARNING(30) > INFO(20) > DEBUG(10)
简单使用示例:
import logging logging.basicConfig(filename="E:\\logging\\abc.log", format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %I:%M:%S %p', level=logging.WARNING) logger = logging.getLogger()
logger.debug("The debug.") logger.info("The info.") logger.warning("The warning.") logger.error("The error.") logger.critical("The critical.") print(logger.level)
运行结果:
查看E:\\logging\\abc.log文件中的内容,以下:
能够看到,因为设置的日志级别为WARNING,因此只打印了比WARNING级别更高的日志。
2、使用logging四大组件记录日志
logger:提供日志接口,供应用代码使用。logger最长用的操做有两类:配置和发送日志消息。能够经过logging.getLogger(name)获取logger对象,
若是不指定name则返回root对象,屡次使用相同的name调用getLogger方法返回同一个logger对象 handler:将日志记录(log record)发送到合适的目的地(destination),好比文件,socket等。一个logger对象能够经过addHandler方法添加多个handler,
每一个handler又能够定义不一样日志级别,以实现日志分级过滤显示 filter:提供方式决定一个日志记录是否发送到handler formatter:指定日志记录输出的具体格式。formatter的构造方法须要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的
如上面所说,logging.basicConfig()函数中可经过具体参数来更改logging模块的行为
日志同时打印到屏幕和文件:
import logging # 建立一个日志对象
logg = logging.getLogger("测试日志") # 定义一个模板
FORMATTER = logging.Formatter("%(asctime)s - %(name)s - [%(lineno)d] - %(message)s") # 建立一个屏幕流
p_stream = logging.StreamHandler() # 建立一个文件流
f_stream = logging.FileHandler("log.log", mode="a", encoding="utf-8") # 将流绑定到模板
p_stream.setFormatter(FORMATTER) f_stream.setFormatter(FORMATTER) # 将日志和流进行绑定
logg.addHandler(p_stream) logg.addHandler(f_stream) # 设置日志记录等级
logg.setLevel(logging.DEBUG) # 打印日志信息
logg.debug("this is Debug") logg.info("this is info") logg.warning("this is warning") logg.error("this is error") logg.critical("this is critical")
运行结果:
若是想为多个用户建立不一样的日志,只须要建立流时建立不一样的流便可,而不须要建立多个日志对象,若是状况特殊考虑单独在建立一个对象。其实咱们能够在建立流的时候直接指定日志等级。流的等级是优先于日志对象的。
以下建立两个流:
import logging # 建立一个日志对象
logg = logging.getLogger("测试日志") # 建立一个程序员模板和老板模板
CORE_FORMATTER = logging.Formatter("%(asctime)s - %(name)s - [%(lineno)d] - %(message)s") BOOS_FORMATTER = logging.Formatter("%(asctime)s - %(message)s") # 建立一个程序员的流和一个老板的流
core_stream = logging.FileHandler("core.log", mode="a", encoding="utf-8") boos_stream = logging.FileHandler("boos.log", mode="a", encoding="utf-8") # 设置日志等级(老板的日志等级设置WARNING)
boos_stream.setLevel(logging.WARNING) # 将流绑定到模板
core_stream.setFormatter(CORE_FORMATTER) boos_stream.setFormatter(BOOS_FORMATTER) # 将日志和流进行绑定
logg.addHandler(core_stream) logg.addHandler(boos_stream) # 设置日志记录等级
logg.setLevel(logging.DEBUG) # 打印日志信息
logg.debug("this is Debug") logg.info("this is info") logg.warning("this is warning") logg.error("this is error") logg.critical("this is critical")
运行结果:
这样咱们便建立了两种不一样的日志
三、日志分割
将日志信息输出到一个单一的文件中,随着应用程序的持续使用,该日志文件会愈来愈庞大,进而影响系统的性能。所以,有必要对日志文件按某种条件进行切分。
分割日志的触发条件:大小、日期,或者大小加上日期。
说是切分,其实是,当一个日志文件达到触发条件后,对日志文件进行重命名,以后再新建原来名称的日志文件(此时就是空文件了),新产生的日志就写入新的日志文件。
为啥叫回滚呢?当分割的日志文件达到指定数目的上限个数时,最老的日志文件就会被删除。
logging库提供了2个能够用于日志滚动的class,一个是RotatingFileHandler,它主要是根据日志文件的大小进行滚动;另外一个是TimeRotatingFileHandler,它主要是根据时间进行滚动。在实际应用中,一般根据时间进行滚动。
TimedRotatingFileHandler的构造函数定义以下:
TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]]) filename 是输出日志文件名的前缀,好比log/myapp.log when 的定义以下: “S”: Seconds “M”: Minutes “H”: Hours “D”: Days “W”: Week day (0=Monday) “midnight”: Roll over at midnight interval:指等待多少个单位when的时间后,Logger会自动重建文件,固然,这个文件的建立取决于filename+suffix,若这个文件跟以前的文件有重名,则会自动覆盖掉之前的文件,因此有些状况suffix要定义的不能由于when而重复。 backupCount:保留日志个数。默认的0是不会自动删除掉日志。若设3,则在文件的建立过程当中库会判断是否有超过这个3,若超过,则会从最早建立的开始删除。
按秒切分示例:
import time import logging import logging.handlers import os # 若是日志文件夹不存在,则建立
log_dir = "log-second" # 日志存放文件夹名称
log_path = os.getcwd() + os.sep + log_dir if not os.path.isdir(log_path): os.makedirs(log_path) # logging初始化工做
logging.basicConfig() # 初始化loggger
test = logging.getLogger('test') test.setLevel(logging.INFO) # 添加TimedRotatingFileHandler # 定义一个1秒换一次log文件的handler # 保留3个旧log文件
timefilehandler = logging.handlers.TimedRotatingFileHandler( log_dir + os.sep + "log", when='S', interval=1, backupCount=3 ) # 设置后缀名称,跟strftime的格式同样
timefilehandler.suffix = "%Y-%m-%d_%H-%M-%S.log" formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s') timefilehandler.setFormatter(formatter) test.addHandler(timefilehandler) n = 6
while n > 0: test.info("这是一个时间分割的测试程序") time.sleep(1) n -= 1
运行结果:
注意:
timefilehandler.suffix的设置必定要和时间单位相符,不如按秒切分,就必须设置timefilehandler.suffix= "%Y-%m-%d_%H-%M-%S.log",不然就不能删除旧文件了。按天、按分钟切分也是如此。
RotatingFileHandler基于文件大小切分
示例:
import time # import logging
import os import logging.handlers # 若是日志文件夹不存在,则建立
log_dir = "log-size" # 日志存放文件夹名称
log_path = os.getcwd() + os.sep + log_dir if not os.path.isdir(log_path): os.makedirs(log_path) # logging初始化工做
logging.basicConfig() # 初始化loggger
test_02 = logging.getLogger('test_02') test_02.setLevel(logging.INFO) # 写入文件,若是单个文件超过100个Bytes,则写入下一个文件,最多保留5个文件
handler = logging.handlers.RotatingFileHandler( 'log-size/test_02.log', maxBytes=100, backupCount=5) formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s') handler.setFormatter(formatter) # 设置后缀名称,跟strftime的格式同样
test_02.addHandler(handler) n = 6
while n > 0: test_02.info("这是一个大小分割的测试程序") time.sleep(1) n -= 1
运行结果:
-----------------------------------------------------------------------------
推荐: