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
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!