- 一、logging 模块四个概念
- 二、创建日志步骤详细说明
- 1. 创建logger
- 2. 创建handler
- 3. 将handler加入logger
- 4. 在自己应用中使用logger
- 5. 一个完整的日志记录
- 三、 format 可选参数列表
- 四、根据文件大小切分日志
- 五、根据时间切分日志
- 六、多进程写日志
一、logging 模块四个概念
logging模块包括logger,handler,filter,formatter这四个基本概念。
- logger
提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。 - handler
将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。 - filter
提供一种优雅的方式决定一个日志记录是否发送到handler。 - formatter
指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。
二、创建日志步骤详细说明
1. 创建logger
- 创建logger
logger是最终使用在代码中的实例。logging.getLogger()
用于获取logger实例,如果参数为空则返回root logger。如果参数相同则获取的是同一个实例,比如logging.getLogger("AppName1")
和logging.getLogger("AppName1")
在不同的地方执行获取到的是同一个实例。
logger = logging.getLogger()
logger1 = logging.getLogger("AppName1")
logger2 = logging.getLogger("AppName2")
- 设置日志级别
日志级别也可以用数字代替,分别对应为{'DEBUG':10, 'INFO':20, 'WARNING':30, 'ERROR':40, 'CRITICAL':50}
。只有高于设置的日志级别才会被打印出来。
logger.setLevel(logging.DEBUG)
logger1.setLevel(logging.INFO)
logger2.setLevel(logging.WARNING)
2. 创建handler
- 创建handler
将日志记录发送到合适的目的地,比如文件、标准输出、标准错误。可以同时创建多个handler,将多个handler添加到同一个logger实例里面,这样这个logger就可以控制多个日志输出了(文件、控制台)。FileHandler 写入文件。StreamHandler 输入到控制台,可以是sys.stderr sys.stdout
file_handler = logging.FileHandler("app.log")
console_handler1 = logging.StreamHandler()
console_handler2 = logging.StreamHandler(sys.stderr)
console_handler3 = logging.StreamHandler(sys.stdout)
- 创建日志格式
fmt = logging.Formatter(
'%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(fmt)
console_handler1.setFormatter(fmt)
console_handler2.setFormatter(fmt)
console_handler3.setFormatter(fmt)
3. 将handler加入logger
将 handler 加入logger实例后上面的操作才会有效,且这几个handler是同时生效的。
logger.addHandler(file_handler)
logger.addHandler(console_handler1)
logger.addHandler(console_handler2)
logger.addHandler(console_handler3)
4. 在自己应用中使用logger
在需要的地方记录日志
logger.debug('This is debug message')
logger.info('This is info message')
logger.warn('This is warning message')
logger.error('This is warning error')
logger.critical('This is critical error')
5. 一个完整的日志记录
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import logging
logger = logging.getLogger("AppName")
logger.setLevel(logging.INFO)
fmt = logging.Formatter(
'%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
file_handler = logging.FileHandler("app.log")
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
logger.debug('This is debug message')
logger.info('This is info message')
logger.warn('This is warning message')
logger.error('This is warning error')
logger.critical('This is critical error')
三、 format 可选参数列表
%(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 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
format: 指定输出的格式和内容,format可以输出很多有用信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
四、根据文件大小切分日志
RotatingFileHandler 的构造函数定义如下:
logging.handlers.RotatingFileHandler(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0)
-
maxBytes=1024*1024*50
表示 50M 大小。 -
mode='a'
表示追加模式。 -
maxBytes
表示字节数。 backupCount
表示备份文件数。- 下面是一个根据文件大小来切分日志文件的例子
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import time
import logging
import logging.handlers
logger = logging.getLogger("AppName")
logger.setLevel(logging.INFO)
fmt = logging.Formatter(
'%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
file_handler = logging.handlers.RotatingFileHandler("app.log", mode="a", maxBytes=1000, backupCount=3)
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
while True:
logger.info('This is info message!')
time.sleep(0.5)
五、根据时间切分日志
如果需要对日志文件根据时间进行切分,使用 TimedRotatingFileHandler, 它的构造函数定义如下:
logging.handlers.TimedRotatingFileHandler(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False)
- filename 是输出日志文件名的前缀,比如 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,若这个文件跟之前的文件有重名,则会自动覆盖掉以前的文件。
- backupCount 是保留日志个数。默认的0是不会自动删除掉日志。若设3,则在文件的创建过程中库会判断是否有超过这个3,若超过,则会从最先创建的开始删除。
- 下面是一个根据时间来切分日志文件的例子。
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import time
import logging
import logging.handlers
logger = logging.getLogger("AppName")
logger.setLevel(logging.INFO)
fmt = logging.Formatter(
'%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
file_handler = logging.handlers.TimedRotatingFileHandler("app.log", when="M", interval=1, backupCount=10)
file_handler.suffix ="%Y-%m-%d_%H-%M"
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
while True:
logger.info('This is info message!')
time.sleep(0.5)
六、多进程写日志
多进程写日志、多进程写日志时的切分操作详情阅读 Python 日志模块应用