今天来总结下python中保存log的方法
从Python2.3起Python的标准库加入了logging模块,logging模块给运行中的应用提供了一个标准的信息输出接口。典型的logging机制实现是把要输出的数据简单地写到一个txt文件中,写log文件的方式是一种常见的打log的方式,而logging模块提供的更多,它可以把输出信息输出到所有类文件的对象中去,包括TCP和UDP的sockets,email服务器,Unix的syslog系统,NT系列的事件log系统,内存的buffer和HTTP服务器,当然还有”真正的”文件中。
Logging库被设计成模块的方式,它提供了以下几个子模块:loggers,handlers,filters和formatters。
- Loggers把应用需要直接调用的接口暴露出来。
- Handlers把log记录发到相应的目的地。
- Filters决定哪些记录需要发给handler。
- Formatters定义了log记录的输出格式。
Loggers
Logger对象扮演了三重角色
首先,它提供给应用几个方法以便应用可以在运行时写log。
其次,Logger对象按照log信息的严重程度或者根据filter对象来决定如何处理log信息(默认的过滤功能)。
最后,logger还负责把log信息传送给相关的loghandlers。
Logger中最常使用的方法分成两部分中:configuration和message sending。
用于Configuration的方法:
setLevel(level)
addFilter(filter)
removeFilter(filter)
addHandler(handler)
removeHandler(handler)
setLevel()方法定义了一个logger处理的最低严重程度(比如说中/高/低三种,我定义为中,那么只有严重程度为中或者高的log才会被处理)。
Logging有如下级别: DEBUG,INFO,WARNING,ERROR,CRITICAL
DEBUG级别是内置的最低级别,CRITICAL是最高级别。
例如,如果严重级别设为INFO级,logger仅仅处理INFO,WARNING,ERROR和CRITICAL级的log,而DEBUG级别的则忽略掉。
根据logger对象的设置,以下的方法用来写log,方法定义如下:
debug(log_message, [*args[, **kwargs]])
info(log_message, [*args[, **kwargs]])
warning(log_message, [*args[, **kwargs]])
error(log_message, [*args[, **kwargs]])
critical(log_message, [*args[, **kwargs]])
exception(message[, *args])
log(log_level, log_message, [*args[, **kwargs]])
注:log_message实际上是一个格式字符串,它可以包含诸如%s,%d,%f此类的替换符号。*args是实际要替换%s,%d,%f参数的列表。**kwargs关键字参数,logging只处理一个关键字exc_info,这个关键字决定是否对异常信息打log。
exception()和error()方法基本一样,不同之处是exception()多出一个stack trace用于转储,exception()方法只能从一个exception handler里面调用。
log()方法显式的带一个level参数,用这个可以得到比使用上面所列举的方法更为详细的log信息,这属于自定义log信息的范畴了。
Logging.getLogger([name])方法返回一个logger实例的引用,如果name参数给出则用这个参数的值作为名字,如果没有则用root做默认值。
名字是以点号分割的命名方式命名的(a.b.c)
对同一个名字的多个调用logging.getLogger()方法会返回同一个logger对象.
这种命名方式里后面的loggers是前面logger的子。例如有一个名字是foo的logger,那么诸如foo.bar,foo.bar.baz和foo.bam这样的logger都是foo这个logger的子,子loggers自动继承父loggers的log信息,正因如此,没有必要把一个应用的所有logger都配置一遍,只要把顶层的logger配置好了,然后子logger根据需要继承就行了。
例子:Log 类,用来记录log信息到文件中
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import inspect
import traceback
class Log:
ERROR = 'Error'
WARNING = 'Warning'
INFO = "Info"
def __init__(self, logger_name, logfile):
self.__logger_name = logger_name
self.__logfile = logfile
self.__get_logger()
self.error_stack = []
self.warning_stack = []
def __get_logger(self):
logger = logging.getLogger(self.__logger_name)
logger.setLevel(logging.INFO)
#create console handler
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
#create file handle
fh = logging.FileHandler(self.__logfile, 'a')
fh.setLevel(logging.INFO)
#create formatter
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)
self.__logger = logger
#如果 tag 是 Error,显示函数调用的堆栈信息
#如果 tag 是 WARNIN, 显示函数的行号和调用方法信息。
#如果 tag 是 INFO, 只显示message信息
def info(self, tag, message=''):
if tag == Log.ERROR:
self.error_stack.append(message)
frame = inspect.currentframe()
stack_trace = traceback.format_stack(frame)
self.__logger.info('[%s] %s' % (tag, message))
self.__logger.info(''.join(stack_trace[:-1]))
elif tag == Log.WARNING:
self.warning_stack.append(message)
frame = inspect.currentframe(1)
callinfo = inspect.getframeinfo(frame)
filename = callinfo[0]
line_num = callinfo[1]
function = callinfo[2]
self.__logger.info('[%s] %s. File "%s", line %d, in %s'
% (tag, message, filename, line_num, function))
else:
self.__logger.info('[%s] %s' % (tag, message))
def summary(self):
self.__count(Log.WARNING, self.warning_stack)
self.__count(Log.ERROR, self.error_stack)
def __count(self, name, stack):
num = len(stack)
if num != 0:
self.__logger.info("Total %d %s" % (num, name))
for item in stack:
self.__logger.info("[%s] %s" % (name, item))