Python 日志logging实例
日志级别优先级
CRITICAL = FATAL > ERROR > WARNING = WARN > INFO > DEBUG > NOTSET
Python logging 源码定义
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
1. 简单的将日志打印到屏幕
示例代码
import logging # 默认打印日志到控制台 def test_1(): logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') # WARNING:root:logging info
运行结果,在控制台打印:
WARNING:root:logging warn
默认情况下,logging将日志打印到屏幕,日志默认级别为WARNING,因此在控制台只输出了warn,而debug和info被过滤掉了。
日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。
2. 通过logging.basicConfig函数配置日志输出格式
示例代码
# 配置日志写入到文件 def test_2(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # datefmt='%Y-%m-%d %H:%M:%S.%f', filename='test_logging2.log', filemode='a') logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn')
运行结果,在日志文件 test_logging2.log 写入日志:
2015-01-08 11:24:57,195 test_logger.py[line:26] DEBUG logging debug
2015-01-08 11:24:57,195 test_logger.py[line:27] INFO logging info
2015-01-08 11:24:57,195 test_logger.py[line:28] WARNING logging warn
2015-01-08 11:25:03,581 test_logger.py[line:26] DEBUG logging debug
2015-01-08 11:25:03,581 test_logger.py[line:27] INFO logging info
2015-01-08 11:25:03,581 test_logger.py[line:28] WARNING logging warn
logging.basicConfig 函数参数说明
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式'w'或'a','w'为覆盖写入,'a'为追加写入
format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
<%(levelno)s: 打印日志级别的数值
<%(levelname)s: 打印日志级别名称
<%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
<%(filename)s: 打印当前执行程序名
<%(funcName)s: 打印日志的当前函数
<%(lineno)d: 打印日志的当前行号
<%(asctime)s: 打印日志的时间
<%(thread)d: 打印线程ID
<%(threadName)s: 打印线程名称
<%(process)d: 打印进程ID
<%(message)s: 打印日志信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr, sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
3. 将日志同时输出到文件和屏幕
示例代码:
# 配置日志写入到文件和打印到控制台 def test_3(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', filename='test_logging3.log', filemode='a') # 定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象 console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn')
运行结果
在控制台打印:
2015-01-08 11:56:41,264 test_logger.py[line:45] INFO logging info
2015-01-08 11:56:41,265 test_logger.py[line:46] WARNING logging warn
在日志文件 test_logging3.log 输出:
2015-01-08 11:32:22,334 test_logger.py[line:44] DEBUG logging debug
2015-01-08 11:32:22,334 test_logger.py[line:45] INFO logging info
2015-01-08 11:32:22,335 test_logger.py[line:46] WARNING logging warn
2015-01-08 11:56:41,264 test_logger.py[line:44] DEBUG logging debug
2015-01-08 11:56:41,264 test_logger.py[line:45] INFO logging info
2015-01-08 11:56:41,265 test_logger.py[line:46] WARNING logging warn
说明:文件日志输出级别设置为logging.DEBUG,控制台日志输出级别设置为logging.INFO,因此控制台只输出两条日志,把DEBUG日志过滤掉了。
4. logging日志回滚
示例代码:
# 配置日志回滚 def test_4(): # import logging.handlers # ok from logging.handlers import RotatingFileHandler # ok rhandler = logging.handlers.RotatingFileHandler(filename='test_logging4.log', maxBytes=10*1024*1024, backupCount=5) rhandler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') rhandler.setFormatter(formatter) logging.getLogger('').addHandler(rhandler) logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') logging.error('logging error')
运行结果,在日志文件 test_logging4.log 输出:
2015-01-08 12:01:58,271 test_logger.py[line:60] WARNING logging warn
2015-01-08 12:01:58,271 test_logger.py[line:61] ERROR logging error
2015-01-08 12:02:20,244 test_logger.py[line:60] WARNING logging warn
2015-01-08 12:02:20,244 test_logger.py[line:61] ERROR logging error
从上例和本例可以看出,logging有一个日志处理的主对象,其它处理方式都是通过addHandler添加进去的。
logging的几种handle方式如下
logging.StreamHandler: 日志输出到流,可以是sys.stderr、sys.stdout或者文件
logging.FileHandler: 日志输出到文件
日志回滚方式,实际使用时用RotatingFileHandler和TimedRotatingFileHandler
logging.handlers.BaseRotatingHandler
logging.handlers.RotatingFileHandler
logging.handlers.TimedRotatingFileHandler
logging.handlers.SocketHandler: 远程输出日志到TCP/IP sockets
logging.handlers.DatagramHandler:
logging.handlers.SMTPHandler:
logging.handlers.SysLogHandler: 日志输出到syslog
logging.handlers.NTEventLogHandler: 远程输出日志到Windows NT/2000/XP的事件日志
logging.handlers.MemoryHandler: 日志输出到内存中的制定buffer
logging.handlers.HTTPHandler: 通过"GET"或"POST"远程输出到HTTP服务器
由于StreamHandler和FileHandler是常用的日志处理方式,所以直接包含在logging模块中,而其他方式则包含在logging.handlers模块中
5. 通过logging.config模块配置日志
test_logger.conf 日志配置文件 :
# test_logger.conf [loggers] keys = root, logging_file, logging_rotate ########## logger ########## [logger_root] level = DEBUG handlers = consoleHandler [logger_logging_file] handlers = consoleHandler, fileHandler qualname = logging_file propagate = 0 [logger_logging_rotate] handlers = consoleHandler, rotateHandler qualname = logging_rotate propagate = 0 ########## handlers ########## [handlers] keys = consoleHandler, fileHandler, rotateHandler [handler_consoleHandler] class = StreamHandler level = INFO formatter = form02 args = (sys.stdout,) [handler_fileHandler] class = logging.FileHandler level = DEBUG formatter = form01 args = ('logging_file.log', 'a') [handler_rotateHandler] class = logging.handlers.RotatingFileHandler level = DEBUG formatter = form02 args = ('logging_rotate.log', 'a', 10 * 1024 * 1024, 5) ########## formatter ########## [formatters] keys = form01, form02 [formatter_form01] format = %(asctime)s %(filename)s[line: %(lineno)d] %(levelname)s %(message)s datefmt = %Y-%m-%d %H:%M:%S [formatter_form02] format = %(asctime)s %(filename)s[line: %(lineno)d] %(levelname)s %(message)s #datefmt = %Y-%m-%d %H:%M:%S
5.1 通过配置文件,实现上述示例 test_3
示例代码
def test_5_3(): ''' test_3 配置文件conf实现 ''' import logging.config logging.config.fileConfig(fname="test_logger.conf") logger = logging.getLogger('logging_file') logger.debug('logging debug') logger.info('logging info') logger.warn('logging warn') logger.error('logging error')
运行结果
在控制台打印:
2015-01-08 12:10:21,847 test_logger.py[line: 73] INFO logging info
2015-01-08 12:10:21,847 test_logger.py[line: 74] WARNING logging warn
2015-01-08 12:10:21,847 test_logger.py[line: 75] ERROR logging error
在日志文件 logging_file.log 输出:
2015-01-08 12:08:46 test_logger.py[line: 72] DEBUG logging debug
2015-01-08 12:08:46 test_logger.py[line: 73] INFO logging info
2015-01-08 12:08:46 test_logger.py[line: 74] WARNING logging warn
2015-01-08 12:08:46 test_logger.py[line: 75] ERROR logging error
2015-01-08 12:10:21 test_logger.py[line: 72] DEBUG logging debug
2015-01-08 12:10:21 test_logger.py[line: 73] INFO logging info
2015-01-08 12:10:21 test_logger.py[line: 74] WARNING logging warn
2015-01-08 12:10:21 test_logger.py[line: 75] ERROR logging error
5.2 通过配置文件,实现上述示例 test_4
示例代码
def test_5_4(): ''' test_4 配置文件conf实现 ''' import logging.config logging.config.fileConfig(fname="test_logger.conf") logger = logging.getLogger('logging_rotate') logger.debug('logging debug') logger.info('logging info') logger.warn('logging warn') logger.error('logging error')
运行结果
在控制台打印:
2015-01-08 12:12:58,278 test_logger.py[line: 84] INFO logging info
2015-01-08 12:12:58,279 test_logger.py[line: 85] WARNING logging warn
2015-01-08 12:12:58,280 test_logger.py[line: 86] ERROR logging error
在日志文件 logging_rotate.log 输出:
2015-01-08 12:12:27,473 test_logger.py[line: 83] DEBUG logging debug
2015-01-08 12:12:27,473 test_logger.py[line: 84] INFO logging info
2015-01-08 12:12:27,473 test_logger.py[line: 85] WARNING logging warn
2015-01-08 12:12:27,474 test_logger.py[line: 86] ERROR logging error
2015-01-08 12:12:58,278 test_logger.py[line: 83] DEBUG logging debug
2015-01-08 12:12:58,278 test_logger.py[line: 84] INFO logging info
2015-01-08 12:12:58,279 test_logger.py[line: 85] WARNING logging warn
2015-01-08 12:12:58,280 test_logger.py[line: 86] ERROR logging error
说明:
5.1 和 5.2 示例中,控制台和日志文件输出的日志级别不同,是因为在日志配置文件 test_logger.conf 中,配置的控制台输出日志级别为 level = INFO,配置的文件输出日志级别为 level = DEBUG
6. logging是线程安全的
logging 有关线程安全的源码:
#--------------------------------------------------------------------------- # Thread-related stuff #--------------------------------------------------------------------------- # #_lock is used to serialize access to shared data structures in this module. #This needs to be an RLock because fileConfig() creates and configures #Handlers, and so might arbitrary user threads. Since Handler code updates the #shared dictionary _handlers, it needs to acquire the lock. But if configuring, #the lock would already have been acquired - so we need an RLock. #The same argument applies to Loggers and Manager.loggerDict. # if thread: _lock = threading.RLock() else: _lock = None def _acquireLock(): """ Acquire the module-level lock for serializing access to shared data. This should be released with _releaseLock(). """ if _lock: _lock.acquire() def _releaseLock(): """ Release the module-level lock acquired by calling _acquireLock(). """ if _lock: _lock.release()
总结
Python logging日志的配置和使用,跟其他平台的日志(例如如 log4j)都相似,下面附上本文示例的完整代码,其中引用的配置文件 test_logger.conf,请见上述示例5
示例的完整代码:
# !/usr/bin/env python # -*- coding:utf-8 -*- # http://www.mimvp.com ''' CRITICAL = FATAL > ERROR > WARNING = WARN > INFO > DEBUG > NOTSET ''' import logging # 默认打印日志到控制台 def test_1(): logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') # WARNING:root:logging info # 配置日志写入到文件 def test_2(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # datefmt='%Y-%m-%d %H:%M:%S.%f', filename='test_logging2.log', filemode='a') logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') # 配置日志写入到文件和打印到控制台 def test_3(): logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', filename='test_logging3.log', filemode='a') # 定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象 console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') # 配置日志回滚 def test_4(): # import logging.handlers # ok from logging.handlers import RotatingFileHandler # ok rhandler = logging.handlers.RotatingFileHandler(filename='test_logging4.log', maxBytes=10*1024*1024, backupCount=5) rhandler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') rhandler.setFormatter(formatter) logging.getLogger('').addHandler(rhandler) logging.debug('logging debug') logging.info('logging info') logging.warn('logging warn') logging.error('logging error') # 通过配置文件写入日志到控制台,日志文件,回滚日志文件 def test_5_3(): ''' test_3 配置文件conf实现 ''' import logging.config logging.config.fileConfig(fname="test_logger.conf") logger = logging.getLogger('logging_file') logger.debug('logging debug') logger.info('logging info') logger.warn('logging warn') logger.error('logging error') def test_5_4(): ''' test_4 配置文件conf实现 ''' import logging.config logging.config.fileConfig(fname="test_logger.conf") logger = logging.getLogger('logging_rotate') logger.debug('logging debug') logger.info('logging info') logger.warn('logging warn') logger.error('logging error') if __name__ == '__main__': test_1() test_2() test_3() test_4() test_5_3() test_5_4()
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2015-01-08 12:25:08
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!