当前位置: 首页 > 大杂烩 > 正文

Python的日志处理模块

Python的日志处理模块

1. logging模块介绍

从Python2.3起,Python的标准库加入了logging模块.logging模块给运行中的应用提供了一个标准的信息输出接口.

Logging是非常有用的,一个程序的健壮性也这个有关,当一个程序包含很多的调试信息时,可以方便我们发现问题,发现错误。

典型的logging机制实现是把要输出的数据简单地写到一个txt文件中去。logging模块的功能更加强大,它可以把输出信息输出到所有类文件的对象中去,甚至TCP和UDP的sockets、email服务器、Unix的syslog系统、NT系列的事件log系统、内存的buffer和HTTP服务器等,当然还有”真正的”文件中去。

Logging库被设计成模块的方式,它提供了以下4个子模块:

  • logger:Logger把应用需要直接调用的接口暴露出来
  • handler:Handler把log记录发到相应的目的地
  • filter:Filter决定哪些记录需要发给handler
  • formatter:Formatter定义了log记录的输出格式

使用步骤

  1. 首先创建一个logger,用setLevel设置严重程度级别然后放那儿先
  2. 可选)然后,创建并设置设置filter(如果需要的话),把创建好的这个filter add到logger上去,logger用filter来过滤哪些出错信息要记录;
  3. 创建一个handler,用setLevel设置严重程度级别(可选)。不同的handler负责输出到不同的输出终端,最常用的是输出到文件、stdout、stderr.
  4. 可选)创建并配置formatter,用它来定义handler的输出字符串的格式。把formatter add到handler上
  5. 把设置好的handler add到logger上.

在程序中可以使用 loger.debug() 函数来记录或输出日志了。

默认情况下,logging将日志打印到屏幕,日志级别为WARNING;
日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET

logger和handler默认的级别都是WARNING级,默认的handler是StreamHandler,就是输出到console。

下面是两个最简单的记录日志到控制台的程序:

代码1:

import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

屏幕上打印:
WARNING:root:This is warning message

代码2:

# -*- coding: utf-8 -*-
import logging
import sys

logger = logging.getLogger("my_log")

handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)

logger.addHandler(handler)

#logger.setLevel(logging.DEBUG)
logger.warn("dddd")

2. Logger子模块

Logger对象扮演了3重角色:

  • 首先,它暴露给应用几个方法以便应用可以在运行时写log
  • 其次,Logger对象按照log信息的严重程度或者根据filter对象来决定如何处理log信息(默认的过滤功能)
  • 最后,logger还负责把log信息传送给相关的loghandlers.

Logger中最常使用的方法分成如下两部分:

  • configuration
    • setLevel(level):setLevel()方法定义了一个logger处理的最底严重程度(比如说中/高/底三种,我定义为中,那么只有严重程度为中或者高的log才会被处理).debug级别是内置的最低级别,critical是最高级别.举例来说,如果严重级别设为info级,logger仅仅处理info,warning,error和critical级的log,而debug级别的则忽略掉.
    • addFilter(filter)
    • removeFilter(filter)
    • addHandler(handler)
    • removeHandler(handler)
  • message sending
    • 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]])

debug(),info(),warning(),error()和critical()方法用一个log_message格式字符串和与之对应的各个参数来生成log信息.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根据需要继承就行了.

3 Handler子模块

Handler对象负责分配合适的log信息(基于log信息的严重程度)到handler指定的目的地.Logger对象可以用addHandler()方法添加零个或多个handler对象到它自身.一个常见的场景是,一个应用可能希望把所有的log信息都发送到一个log文件中去,所有的error级别以上的log信息都发送到stdout,所有critical的log信息通过email发送.这个场景里要求三个不同handler处理,每个handler负责把特定的log信息发送到特定的地方.

标准库里面包括以下的handlers(由于StreamHandler和FileHandler是常用的日志处理方式,所以直接包含在logging模块中,而其他方式则包含在logging.handlers模块中):

  • StreamHandler
  • FileHandler
  • RotatingFileHandler
  • TimedRotatingFileHandler
  • SocketHandler
  • DatagramHandler
  • SysLogHandler
  • NTEventLogHandler
  • SMTPHandler
  • MemoryHandler
  • HTTPHandler

带说明:

  • 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: 远程输出日志到UDP sockets
  • logging.handlers.SMTPHandler: 远程输出日志到邮件地址
  • logging.handlers.SysLogHandler: 日志输出到syslog
  • logging.handlers.NTEventLogHandler: 远程输出日志到Windows NT/2000/XP的事件日志
  • logging.handlers.MemoryHandler: 日志输出到内存中的制定buffer
  • logging.handlers.HTTPHandler: 通过”GET”或”POST”远程输出到HTTP服务器

Handler里面提供给应用开发者的只有很少的几个方法可用.对使用内置的handler(就是说不是自定义的handlers)的开发者可用的配置方法如下:

  • setLevel(level)
  • setFormatter(formatter)
  • addFilter(filter)
  • removeFilter(filter)

setLevel()方法跟logger对象里面的setLevel()一样,也是用于设定一个最低分发log信息的级别.为什么有两个setLevel()呢?logger的严重等级用于决定那个级别的log信息可以分发到它的handlers.handler里面的level设置用于控制那些个log信息是handler需要转寄的.setFormatter()方法选定一个格式化对象给它自己用.addFilter()和removeFilter()分别用于为handler增加一个filter和删除一个filter.

应用里面Handler不应该被直接实例化.相反,应该用logging.Handler类作所有Handlers的基类,在它里面定义所有自Handler用到的接口并且创建一些默认的方法让子类来用(或者继承).

4. Formatters子模块

Formatter对象定义了最终log信息的顺序,结构和内容.

于基本的logging.Handler类不同,应用可以直接实例化formatter类,当然,如果需要你也可以子例化formatter以便定制它的一些行为.

构造函数接受两个可选参数:一个信息格式字符串和一个日期格式字符串.

如果没有信息格式字符串,直接输出log信息.如果没有日期格式字符串,默认的格式是:

%Y-%m-%d %H:%M:%S

下面的信息格式字符串会输出一个可读格式的串,严重级别和log信息内容以下面的格式给出:

“%(asctime)s – %(levelname)s – %(message)s”

代码示例

通过logging.basicConfig函数对日志的输出格式及方式做相关配置

import logging

logging.basicConfig(level=logging.DEBUG,
                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                datefmt='%a, %d %b %Y %H:%M:%S',
                filename='myapp.log',
                filemode='w')

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

./myapp.log文件中内容为:
Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message
Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message
Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message

logging.basicConfig函数各参数:

  • filename: 指定日志文件名
  • filemode: 和file函数意义相同,指定日志文件的打开模式,’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被忽略

同时将日志输出到文件和终端

将日志同时输出到文件和屏幕

import logging

logging.basicConfig(level=logging.DEBUG,
                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                datefmt='%a, %d %b %Y %H:%M:%S',
                filename='myapp.log',
                filemode='w')

#定义一个StreamHandler,将INFO级别或更高的日志信息打印
#到标准错误,并将其添加到当前的日志处理对象#
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

屏幕上打印:
root        : INFO     This is info message
root        : WARNING  This is warning message
./myapp.log文件中内容为:
Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message
Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message
Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message

日志回滚

import logging
from logging.handlers import RotatingFileHandler

#定义一个RotatingFileHandler,最多备份5个日志文件,每个日志文件最大10M
Rthandler = RotatingFileHandler('myapp.log', maxBytes=10*1024*1024,backupCount=5)
Rthandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
Rthandler.setFormatter(formatter)
logging.getLogger('').addHandler(Rthandler)

通过logging.config模块配置日志

配置文件如下:

#logger.conf
###############################################

[loggers]
keys=root,example01,example02

[logger_root]
level=DEBUG
handlers=hand01,hand02

[logger_example01]
handlers=hand01,hand02
qualname=example01
propagate=0

[logger_example02]
handlers=hand01,hand03
qualname=example02
propagate=0

###############################################

[handlers]
keys=hand01,hand02,hand03

[handler_hand01]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stderr,)

[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form01
args=('myapp.log', 'a')

[handler_hand03]
class=handlers.RotatingFileHandler
level=INFO
formatter=form02
args=('myapp.log', 'a', 10*1024*1024, 5)

###############################################
[formatters]
keys=form01,form02

[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S

[formatter_form02]
format=%(name)-12s: %(levelname)-8s %(message)s
datefmt=

示例程序1:

import logging
import logging.config

logging.config.fileConfig("logger.conf")
logger = logging.getLogger("example01")

logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')

示例程序2:

import logging
import logging.config

logging.config.fileConfig("logger.conf")
logger = logging.getLogger("example02")

logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')

本文固定链接: http://sdnhub.cn/index.php/python-logging/ | 软件定义网络SDN

该日志由 sdnhub 于2015年05月27日发表在 大杂烩 分类下, 通告目前不可用,你可以至底部留下评论。
原创文章转载请注明: Python的日志处理模块 | 软件定义网络SDN
关键字:

Python的日志处理模块:等您坐沙发呢!

发表评论

*

快捷键:Ctrl+Enter