一 前言
Python 的logging 模块定义的函数和类为应用程序和库实现了一个灵活的事件日志系统。该模块提供多种日志级别并且支持多种记录日志的方式比如 终端,文件等等。在编写一个软件系统的时候 ,使用日志系统十分有必要 记录函数的执行过程和异常报错信息。本文算是一个学习笔记,对于跨文件引用的初学者有一定帮助。
二 入门
talk is cheap ,show me the code.
1 例子 logt.py
运行该脚本
看到这个输出 ,有人可能会有疑问 为什么 logging.debug()和logging.info()没有输出内容? 恩,这个是个好问题,莫慌,且看下文分析。
2. logging 的日志级别
logging :提供了完整的日志体系,支持五种日志级别以便记录程序的执行过程。
DEBUG :详细信息,典型地调试问题的时候会使用。
INFO :证明事情按预期工作。
WARNING :表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
ERROR :由于更严重的问题,软件已不能执行一些功能了。
CRITICAL :严重错误,表明软件已不能继续运行了。 以上五种日志级别从低到高分别是:DEBUG < INFO < WARNING < ERROR < CRITICAL 。默认的是WARNING,只有日志级别高于WARNING的日志信息才会输出,而输出有两种方式 一种输出控制台,也是默认的方式,另一种是记录到文件中,如日志文件。
3 logging的配置
python提供了多种配置方式控制日志的显示格式,内容,目的等。如上述例子中的日志输出“WARNING:root:this is awarn message”。
显式创建记录器Logger、处理器Handler和格式化器Formatter,并进行相关设置;
通过简单方式进行配置,使用basicConfig()函数直接进行配置;
通过配置文件进行配置,使用fileConfig()函数读取配置文件;
通过配置字典进行配置,使用dictConfig()函数读取配置信息;
本文使用basicConfig()方式作为例子。
basicConfig()支持下列关键字参数。
格式 描述
filename:创建一个FileHandler,使用指定的文件名,而不是使用StreamHandler。
filemode:如果指明了文件名,指明打开文件的模式(如果没有指明filemode,默认为'a',即append方式)。
format :handler使用指明的格式化字符串。详细的请参考 官方文档
datefmt:使用指明的日期/时间格式 比如 '%Y-%m-%d %H:%M:%S' 2017-11-21 23:10:00。
level 指定logger的日志级别。
stream 使用指明的流来初始化StreamHandler。该参数与'filename'不兼容,如果两个都有,'stream'将被忽略。
三 进阶介绍
logging模块提供四个组件logger,handler,filter,formatter
logger:记录器,为应用代码提供日志接口。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name 获取logger对象,如果不指定name则返回root对象,如第一个例子。多次使用相同的name调用getLogger方法返回同一个logger对象。
调用方法:
logger = logging.getLogger(logger_name) #如果不指定 logger_name ,则默认创建一个root logger,见第一个例子。
logger.setLevel(logging.ERROR) #设置日志级别为ERROR,即只有日志级别大于等于ERROR的日志才会输出
logger.addHandler(handler_name) #为logger实例增加一个处理器
logger.removeHandler(handler_name) # 为logger实例删除一个处理器
handler:将日志内容发送到合适的目的,比如文件,终端等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。
详细信息请移步 官方文档
调用方法
StreamHandler
FileHandler
返回FileHandler类的实例。指明的文件会被打开,并用作日志流。如果没有指明mode,使用'a'。如果encoding不为None,会用指定的编码来打开文件。如果delay为真,只到第一次调用emit()的时候才打开文件。默认情况下,文件会一直增长。 filter:提供一种优雅的方式决定一个日志记录是否发送到handler。 formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。 现在我们测试另外一个例子 logconfig.py ,该文件定义了一个init_log 函数,通过传入的参数显示的配置logging。函数里面创建一个logging 实例,分别将日志输出到文件和。当然有兴趣的朋友可以自己设置两个终端,将日志输入到文件的同时也打印到终端,不过线上的日志系统不推荐此类用法。
#!/usr/bin/env python
# coding:utf-8
import logging
import logging.handlers
import os
LOG_LEVELS = {'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL}
# 日志的输出的格式
LOGGING_FORMAT = "%(asctime)s [%(name)s] [%(levelname)s] [%(lineno)d] %(message)s"
STANDARD_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' # 时间格式 2016-06-14 10:10:00
DEFAULT_LOG_MAX_SIZE = 50 * 1024 * 1024 # 当达到50M就进行切分
def init_log(logger_name, level='DEBUG', logfile='',
formatter=LOGGING_FORMAT, max_size=DEFAULT_LOG_MAX_SIZE):
log_base = '/data/logs/'
if not logfile:
if not os.path.exists(log_base):
os.mkdir(log_base)
logfile = os.path.join(log_base, logger_name+'.log')
logger = logging.getLogger(logger_name) # 初始化一个logging 实例
logger.setLevel(LOG_LEVELS[level]) # 设置日志的级别
formatter = logging.Formatter(formatter)
fh = logging.handlers.RotatingFileHandler(
logfile, maxBytes=max_size, backupCount=3)
# 定义日志输出到文件的handler ,也可以定义 fh=logging.FileHandler(logfile)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
return logger
if __name__ == '__main__':
LOGGER = init_log('youzan', 'INFO', '0614.log')
LOGGER.info('info message')
LOGGER.warn('warn message')
LOGGER.error('error message')
LOGGER.critical('critical message')
执行该脚本
(agent)➜ utils git:(master) python log_utils.py (agent)➜ utils git:(master) cat 0614.log 2017-11-21 23:32:40,314 [youzan] [INFO] [41] info message 2017-11-21 23:32:40,315 [youzan] [WARNING] [42] warn message 2017-11-21 23:32:40,315 [youzan] [ERROR] [43] error message 2017-11-21 23:32:40,316 [youzan] [CRITICAL] [44] critical message
四 拓展
其实这才是本章的重点,在构建一个整套的程序时,怎么全局配置logging 模块,并在不同的程序中调用呢?例子如下:
root@rac4:~/python# >tree . . ├── log2.py — 引用 logconfig中的logging 配置 ├── logconfig.py —配置logging 输出格式
特别注意,如果是跨文件访问定义的logconfig 配置 ,必须在 logconfig.py 所在的目录创建 __init__.py 空文件
log2.py
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from logconfig import init_log
logger = init_log('logtest','INFO',logfile='666.log')
logger.info('this is a test %s'," yangyi@youzan.com")
logger.debug('debug message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
(agent)➜ test git:(master) python log2.py
(agent)➜ test git:(master) cat 666.log
2017-11-21 23:38:27,760 [logtest] [INFO] [7] this is a test yangyi@youzan.com
2017-11-21 23:38:27,760 [logtest] [WARNING] [9] warn message
2017-11-21 23:38:27,760 [logtest] [ERROR] [10] error message
2017-11-21 23:38:27,760 [logtest] [CRITICAL] [11] critical message
五 参考文章
1 http://www.jianshu.com/p/feb86c06c4f4
2 http://python.usyiyi.cn/python_278/library/logging.html#