【简单】Logging模块的简单使用
转载自:http://blog.donews.com/limodou/archive/2005/02/16/278699.aspx
以前看过,但一直认为很复杂。象 NewEdit 都是自已写的日志处理。其实 logging 做得很好,也不是很复杂,只要看明白例子。在新发布的crawl 2.1.1中使用了logging,下面把它的使用代码写出来,很简单:
def InitLogger():
global LOGGER, LOGFILE, LOGLEVEL
if LOGLEVEL == logging.CRITICAL or not os.access(os.path.dirname(LOGFILE),os.W_OK):
LOGGER = EmptyLogger()
return
LOGGER = logging.getLogger()
hdlr = logging.FileHandler(LOGFILE)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
LOGGER.addHandler(hdlr)
LOGGER.setLevel(LOGLEVEL)
这个函数用来返回一个日志对象。
第4行生成一个日志对象,可以带一个名字,可以缺省。
第5行生成一个Handler。logging支持许多Handler,象FileHandler, SocketHandler, SMTPHandler等,我由于要写文件就使用了FileHandler。logfile是一个全局变量,它就是一个文件名,如:’crawl.log’。
第6行生成一个格式器,用于规范日志的输出格式。如果没有这行代码,那么缺省的格式就是:”%(message)s”。也就是写日志时,信息是什么日志中就是什么,没有日期,没有信息级别等信息。logging支持许多种替换值,详细请看Formatter的文档说明。这里有三项:时间,信息级别,日志信息。
第7行将格式器设置到处理器上。
第8行将处理器加到日志对象上。
第9行设置日志信息输出的级别。logging提供多种级别的日志信息,如:NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL等。每个级别都对应一个数值。如果不执行此句,缺省为30(WARNING)。可以执行:logging.getLevelName(logger.getEffectiveLevel())来查看缺省的日志级别。日志对象对于不同的级别信息提供不同的函数进行输出,如:info(), error(), debug()等。当写入日志时,小于指定级别的信息将被忽略。因此为了输出想要的日志级别一定要设置好此参数。这里我设为NOTSET(值为0),也就是想输出所有信息。
有了日志对象,输出就非常简单了:
logger.error(message)
logger.info(message)
【详细】Python标准模块logging
转载自:http://blog.csdn.net/fxjtoday/article/details/6307285
开发Python, 一直以来都是使用自己编写的logging模块. 比较土......
今天发现python的标准模块的这个功能做的挺好, 记录一下, 以后使用模块来进行logging.
对于这个模块的介绍网上也很多, 我也不用自己写了, 比较好的如下,
http://crazier9527.iteye.com/blog/290018 Python的标准logging模块
http://blog.endlesscode.com/2010/06/03/python-logging-module/ Python的logging模块
http://docs.python.org/library/logging.html 官方文档
下面就对于在项目中比较需要用到的部分摘录一些,
简单的例子
import logging
import sys
logger = logging.getLogger("endlesscode")
formatter = logging.Formatter('%(name)-12s %(asctime)s %(levelname)-8s %(message)s', '%a, %d %b %Y %H:%M:%S',)
file_handler = logging.FileHandler("test.log")
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler(sys.stderr)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
#logger.setLevel(logging.ERROR)
logger.error("fuckgfw")
logger.removeHandler(stream_handler)
logger.error("fuckgov")
上面这段代码基本包含logging模块的基本feature
GetLogger
GetLogger() returns a reference to a logger instance with the specified name if it is provided, or root if not. The names are period-separated hierarchical structures. Multiple calls to getLogger() with the same name will return a reference to the same logger object.
后面会看到这种以'.'分隔的hierarchical structures有什么用.
Formatter
Formatter对象定义了最终log信息的顺序,结构和内容, 后面会详细解释.
Handler
这儿用到了StreamHandler和FileHandler, 用于向不同的输出端打log.
SetLevel
Logging有如下级别: DEBUG,INFO,WARNING,ERROR,CRITICAL
默认级别是WARNING, logging模块只会输出指定level以上的log
这样的好处, 就是在项目开发时debug用的log, 在产品release阶段不用一一注释, 只需要调整logger的级别就可以了, 很方便的.
Formatter
Formatter对象定义了最终log信息的顺序,结构和内容.于基本的logging.Handler类不同,应用可以直接实例化formatter类,当然,如果需要你也可以子例化formatter以便定制它的一些行为.构造函数接受两个可选参数:一个信息格式字符串和一个日期格式字符串.如果没有信息格式字符串,直接输出log信息.如果没有日期格式字符串,默认的格式是:%Y-%m-%d %H:%M:%S
上面的代码给出了Formatter的例子, 下面表格给出所有可以使用的format,
Handler
Logging包含很多handler, 可能用到的有下面几种
- StreamHandler instances send error messages to streams (file-like objects).
- FileHandler instances send error messages to disk files.
- RotatingFileHandler instances send error messages to disk files, with support for maximum log file sizes and log file rotation.
- TimedRotatingFileHandler instances send error messages to disk files, rotating the log file at certain timed intervals.
- SocketHandler instances send error messages to TCP/IP sockets.
- DatagramHandler instances send error messages to UDP sockets.
- SMTPHandler instances send error messages to a designated email address.
最常用的也就是StreamHandler和FileHandler
Handler
Logging包含很多handler, 可能用到的有下面几种
- StreamHandler instances send error messages to streams (file-like objects).
- FileHandler instances send error messages to disk files.
- RotatingFileHandler instances send error messages to disk files, with support for maximum log file sizes and log file rotation.
- TimedRotatingFileHandler instances send error messages to disk files, rotating the log file at certain timed intervals.
- SocketHandler instances send error messages to TCP/IP sockets.
- DatagramHandler instances send error messages to UDP sockets.
- SMTPHandler instances send error messages to a designated email address.
最常用的也就是StreamHandler和FileHandler
Configuration
- Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above.
- Creating a logging config file and reading it using the fileConfig() function.
- Creating a dictionary of configuration information and passing it to the dictConfig() function.
第一种配置方法前面的code里面已经有了
第二种配置方法, 我觉得在项目里面是比较实用的, 通过编写配置文件, 在code里面只需要用fileConfig配置一下logging, 显得比较简洁.
这个可以参照http://crazier9527.iteye.com/blog/290026 或 官方文档.
Multiple handlers and formatters
Loggers是一个简单的Python对象.addHandler()方法没有最多或者最少配额,当你的应用需要在把所有的log信息打到一个txt文件中去,同时又需要把errors级别一上的错误信息打到console时,你就会体会到这个特性的好处.只要简单的配置一下合适的handlers就可以实现这个功能.应用对logging的调用用不着修改.以下是对前一个基于module的配置例子的改进:
import logging
logger = logging.getLogger("simple_example")
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler("spam.log")
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)
# "application" code
logger.debug("debug message")
logger.info("info message")
logger.warn("warn message")
logger.error("error message")
logger.critical("critical message")
多module使用Logging(只要在同一个Python interpreter process)
上面我曾提到过,所有的对logging.getLogger(‘someLogger’)的调用都会返回同一个对象.这个规则不仅仅在同一个module有效,而且对在同一个Python的解释器进程里面的多个module也有效.而且,应用代码可以在一个module里面定义一个父logger,而在另一个module里面继承这个logger,所有对这个子logger的调用都会转到父logger里面去,如下所示:
下面这个是主模块的代码,
import logging
import auxiliary_module
# create logger with "spam_application"
logger = logging.getLogger("spam_application")
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler("spam.log")
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)
logger.info("creating an instance of auxiliary_module.Auxiliary")
a = auxiliary_module.Auxiliary()
logger.info("created an instance of auxiliary_module.Auxiliary")
logger.info("calling auxiliary_module.Auxiliary.do_something")
a.do_something()
logger.info("finished auxiliary_module.Auxiliary.do_something")
logger.info("calling auxiliary_module.some_function()")
auxiliary_module.some_function()
logger.info("done with auxiliary_module.some_function()")
这个是子模块的代码,
import logging
# create logger
module_logger = logging.getLogger("spam_application.auxiliary")
class Auxiliary:
def __init__(self):
self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary")
self.logger.info("creating an instance of Auxiliary")
def do_something(self):
self.logger.info("doing something")
a = 1 + 1
self.logger.info("done doing something")
def some_function():
module_logger.info("received a call to /"some_function/"")
可以看到, 我们在主模块里面定义了一个logger 'spam_application', 并对他进行了配置.
那么在这个解释器进程里面的任何地方去通过getLogger('spam_application')得到的对象都是一样的, 不需要从新定义配置, 可以直接使用.
更方便的是, 你定义任意该logger的子logger, 都可以共享父logger的定义和配置
所谓的父子logger只是简单的通过命名来识别, 任意以'spam_application.'开头的logger都是他的子logger, 例如'spam_application.auxiliary'
这个在实际的开发中, 还是很方便的, 对于一个application,
首先通过logging配置文件编写好这个application所对应的log策略, 可以只生成一个根logger, 比如叫'Project'
然后在Main函数里面, 通过fileConfig加载logging的配置
接着在appliction的任意地方, 不同的模块中, 可以使用Project的子logger, 如Project.UI, Project.Core, 来进行log, 并且不需要反复的定义和配置各个logger.