日志一共分成5个等级,从低到高分别是:
说明:
这5个等级,也分别对应5种打日志的方法:debug,info,warning,error,critical,默认的是warning,当在warning或之上时才被跟踪。
2、日志输出
有两种方式记录跟踪 ,一种输出控制台,另一种是记录到文件中,如日志文件。
2.1、将日志输出到控制台
比如:log1.py如下:
__author__ = 'Administrator'
import logging
"""
将日志信息向终端打印信息
"""
logging.basicConfig(level=logging.WARNING,format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logging.debug("这是 logging debug message")
logging.info("这是 logging info message")
logging.warning("这是 logging warning messgae")
logging.error("这是 logging error messgae")
logging.critical("这是 logging critical message")
比如:log2.py如下:
__author__ = 'Administrator'
import logging
"""
将日志信息输出到文件
"""
logging.basicConfig(level=logging.WARNING,
filename ="./log.txt",
filemode="w",
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logging.debug("这是 logging debug message")
logging.info("这是 logging info message")
logging.warning("这是 logging warning messgae")
logging.error("这是 logging error messgae")
logging.critical("这是 logging critical message")
比如log.py
__author__ = 'Administrator'
import logging
"""
将日志信息即可是输出到终端也可以输出到文件
"""
# 第一步 创建一个日志器logger并设置其日志级别为INFO
logger = logging.getLogger("rxz")
logger.setLevel(logging.INFO) #log等级总开关
#第二步 创建一个 handler ,用于写入日志文件
logfile = "./log.txt"
fh = logging.FileHandler(logfile,mode="a",encoding='utf-8') #用open的打开模式这里可以进行参考
fh.setLevel(logging.DEBUG) #输出到file的Log等级的开关
#第三步,在创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING) #输出到console的Log等级的开关
#第四步,定义handler输出格式
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
fh.setFormatter(formatter)
ch.setFormatter(formatter)
#第五步,将logger添加到handler里面
logger.addHandler(fh)
logger.addHandler(ch)
# 日志输出
logger.debug('这是 debug message')
logger.info('这是 info message')
logger.warn('这是 warn message')
logger.error('这是 error message')
logger.critical('这是 critical message')
三、详解python之配置日志的几种方式
作为开发者,我们可以通过以下3中方式来配置logging:
1)使用Python代码显式的创建loggers, handlers和formatters并分别调用它们的配置函数;
2)创建一个日志配置文件,然后使用fileConfig()函数来读取该文件的内容;
3)创建一个包含配置信息的dict,然后把它传递个dictConfig()函数;
需要说明的是,logging.basicConfig()
也属于第一种方式,它只是对loggers, handlers和formatters的配置函数进行了封装。另外,第二种配置方式相对于第一种配置方式的优点在于,它将配置信息和代码进行了分离,这一方面降低了日志的维护成本,同时还使得非开发人员也能够去很容易地修改日志配置。
一、使用Python代码实现日志配置
__author__ = 'rxz'
import sys
import logging
# 创建一个日志器logger并设置其日志级别为DEBUG
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 创建一个流处理器handler并设置其日志级别为DEBUG
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.DEBUG)
filename="./log.txt"
file_handler = logging.FileHandler(filename,mode="a",encoding="utf-8")
file_handler.setLevel(logging.DEBUG)
# 创建一个格式器formatter并将其添加到处理器handler
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 为日志器logger添加上面创建的处理器handler
logger.addHandler(console_handler)
logger.addHandler(file_handler)
#日志输出
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
二、使用配置文件和fileConfig()函数实现日志配置
现在我们通过配置文件的方式来实现与上面同样的功能:
配置文件logging.conf内容如下:
[loggers]
keys=root,simpleExample
[handlers]
keys=fileHandler,consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=fileHandler
[logger_simpleExample]
level=DEBUG
#handlers (选择是终端输出还是文件输出) 运行时把这个注释去掉
#或者propagate=1就是终端和文件输出都打开,默认0只打开你选择的哪一端
#handlers=consoleHandler
handlers=fileHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter=simpleFormatter
[handler_fileHandler]
class=FileHandler
args=('logging.log', 'a')
level=DEBUG
formatter=simpleFormatter
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
主代码:
__author__ = 'rxz'
import logging
import logging.config
# 读取日志配置文件内容
logging.config.fileConfig('logging.conf')
# 创建一个日志器logger
logger = logging.getLogger('simpleExample')
# 日志输出
logger.debug('debug message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
1.关于fileConfig()函数的说明:
该函数实际上是对configparser
模块的封装,关于configparser
模块的介绍请参考<。
函数定义:
该函数定义在loging.config模块下:
logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)
参数:
2. 配置文件格式说明:
上面提到过,fileConfig()
函数是对ConfigParser/configparser
模块的封装,也就是说fileConfig()
函数是基于ConfigParser/configparser
模块来理解日志配置文件的。换句话说,fileConfig()
函数所能理解的配置文件基础格式是与ConfigParser/configparser
模块一致的,只是在此基础上对文件中包含的section
和option
做了一下规定和限制,比如:
1)配置文件中一定要包含loggers、handlers、formatters这些section,它们通过keys这个option来指定该配置文件中已经定义好的loggers、handlers和formatters,多个值之间用逗号分隔;另外loggers这个section中的keys一定要包含root这个值;
2)loggers、handlers、formatters中所指定的日志器、处理器和格式器都需要在下面以单独的section进行定义。seciton的命名规则为[logger_loggerName]、[formatter_formatterName]、[handler_handlerName]
3)定义logger的section必须指定level和handlers这两个option,level的可取值为DEBUG、INFO、WARNING、ERROR、CRITICAL、NOTSET,其中NOTSET表示所有级别的日志消息都要记录,包括用户定义级别;handlers的值是以逗号分隔的handler名字列表,这里出现的handler必须出现在[handlers]这个section中,并且相应的handler必须在配置文件中有对应的section定义;
4)对于非root logger来说,除了level和handlers这两个option之外,还需要一些额外的option,其中qualname是必须提供的option,它表示在logger层级中的名字,在应用代码中通过这个名字得到logger;propagate是可选项,其默认是为1,表示消息将会传递给高层次logger的handler,通常我们需要指定其值为0,这个可以看下下面的例子;另外,对于非root logger的level如果设置为NOTSET,系统将会查找高层次的logger来决定此logger的有效level。
5)定义handler的section中必须指定class和args这两个option,level和formatter为可选option;class表示用于创建handler的类名,args表示传递给class所指定的handler类初始化方法参数,它必须是一个元组(tuple)的形式,即便只有一个参数值也需要是一个元组的形式;level与logger中的level一样,而formatter指定的是该处理器所使用的格式器,这里指定的格式器名称必须出现在formatters这个section中,且在配置文件中必须要有这个formatter的section定义;如果不指定formatter则该handler将会以消息本身作为日志消息进行记录,而不添加额外的时间、日志器名称等信息;
6)定义formatter的sectioin中的option都是可选的,其中包括format用于指定格式字符串,默认为消息字符串本身;datefmt用于指定asctime的时间格式,默认为'%Y-%m-%d %H:%M:%S';class用于指定格式器类名,默认为logging.Formatter;
说明:
配置文件中的class
指定类名时,该类名可以是相对于logging模块的相对值,如:FileHandler
、handlers.TimeRotatingFileHandler
;也可以是一个绝对路径值,通过普通的import机制来解析,如自定义的handler类mypackage.mymodule.MyHandler
,但是mypackage需要在Python可用的导入路径中--sys.path。
3. 对于propagate属性的说明
实例1:
我们把logging.conf中simpleExample这个handler定义中的propagate属性值改为1,或者删除这个option(默认值就是1):
?
1 2 3 4 5 |
|
现在来执行同样的代码:
?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
我们会发现,除了在控制台有输出信息时候,在logging.log文件中也有内容输出:
?
1 2 |
|
这说明simpleExample这个logger在处理完日志记录后,把日志记录传递给了上级的root logger再次做处理,所有才会有两个地方都有日志记录的输出。通常,我们都需要显示的指定propagate的值为0,防止日志记录向上层logger传递。
实例2:
现在,我们试着用一个没有在配置文件中定义的logger名称来获取logger:
?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
运行程序后,我们会发现控制台没有任何输出,而logging.log文件中又多了两行输出:
?
1 2 |
|
这是因为,当一个日志器没有被设置任何处理器是,系统会去查找该日志器的上层日志器上所设置的日志处理器来处理日志记录。simpleExample1在配置文件中没有被定义,因此logging.getLogger(simpleExample1)这行代码这是获取了一个logger实例,并没有给它设置任何处理器,但是它的上级日志器--root logger在配置文件中有定义且设置了一个FileHandler处理器,simpleExample1处理器最终通过这个FileHandler处理器将日志记录输出到logging.log文件中了。