python-logging.config【日志模块】

1,logging模块简介

 Python的logging模块提供了通用的日志系统,熟练使用longgong模块可以方便开发者开发第三方模块或者是自己的Python应用。同样这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP、GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式。下文我将主要介绍如何使用文件方式记录log

        logging模块包括 loggerhandlerfilterformatter这四个基本概念。
        logger提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
        handler将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。Handler 是处理器, 可以把log记录到文件系统中, 输出到终端设备, 或者网络sockt或者邮件等。
StreamHandler
FileHandler
RotatingFileHandler
TimedRotatingFileHandler
SocketHandler
DatagramHandler
SysLogHandler
NTEventLogHandler
SMTPHandler
MemoryHandler
HTTPHandler

        filter提供一种优雅的方式决定一个日志记录是否发送到handler。

        formatter指定日志记录输出的具体格式。使用这个可以更容易的根据错误检错。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。

%(name)s            Name of the logger (logging channel)
%(levelno)s         Numeric logging level for the message (DEBUG, INFO,
                    WARNING, ERROR, CRITICAL)
%(levelname)s       Text logging level for the message ("DEBUG", "INFO",
                    "WARNING", "ERROR", "CRITICAL")
%(pathname)s        Full pathname of the source file where the logging
                    call was issued (if available)
%(filename)s        Filename portion of pathname
%(module)s          Module (name portion of filename)
%(lineno)d          Source line number where the logging call was issued
                    (if available)
%(created)f         Time when the LogRecord was created (time.time()
                    return value)
%(asctime)s         Textual time when the LogRecord was created
%(msecs)d           Millisecond portion of the creation time
%(relativeCreated)d Time in milliseconds when the LogRecord was created,
                    relative to the time the logging module was loaded
                    (typically at application startup time)
%(thread)d          Thread ID (if available)
%(process)d         Process ID (if available)
%(message)s         The result of record.getMessage(), computed just as
                    the record is emitted

2,基本方法

事实上,不管用最简单的logging模块的basicConfig函数,还是用配置文件形式,只要log文件一样,不过多少程序,都会以增加的方式往里写。

2.1,程序1

一些小型的程序我们不需要构造太复杂的log系统,可以直接使用 logging模块的basicConfig函数即可,代码如下:

#test.py
import logging
LOG_FILENAME="./mylog.log"
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
logging.debug("this is a debugmsg!")  
logging.info("this is a infomsg!")  
logging.warn("this is a warn msg!")  
logging.error("this is a error msg!")  
logging.critical("this is a critical msg!") 
这样会生成一个mylog.log的日志文件,每运行一次,里面都增加如下内容:

DEBUG:root:this is a debugmsg!
INFO:root:this is a infomsg!
WARNING:root:this is a warn msg!
ERROR:root:this is a error msg!
CRITICAL:root:this is a critical msg!

需要说明的是我将level设定为DEBUG级别,所以log日志中只显示了包含该级别及该级别以上的log信息。信息级别依次是:notset、debug、info、warn、error、critical。如果在多个模块中使用这个配置的话,只需在主模块中配置即可,其他模块会有相同的使用效果。

2.2,程序2

上述的基础配置比较简单,下面我们看一个更标准的程序,我们需要依次设置logger、handler、formatter等配置。

# -* - coding: UTF-8 -* - 
import logging  
  
log_file = "./nomal_logger.log"  
log_level = logging.DEBUG  


#建立【logger】
#logger = logging.getLogger()
logger = logging.getLogger("loggingmodule.NomalLogger")  
logger.setLevel(log_level) 


#建立【文件句柄】和【流句柄】并分别设置级别
filehandler = logging.FileHandler(log_file)  
filehandler.setLevel(logging.ERROR)
streamhandler = logging.StreamHandler()
streamhandler.setLevel(logging.ERROR)
#建立【格式串】
formatter = logging.Formatter("[%(levelname)s][%(funcName)s][%(asctime)s]%(message)s")   
#【文件句柄】和【流句柄】使用【格式串】  
filehandler.setFormatter(formatter)  
streamhandler.setFormatter(formatter)
#【logger】连接【句柄】
logger.addHandler(filehandler)  
logger.addHandler(streamhandler) 
   
#test  
logger.debug("this is a debug msg!")  
logger.info("this is a info msg!")  
logger.warn("this is a warn msg!")
logger.error("this is a error msg!")
logger.critical("this is a error msg!")  
这样会生成一个Log_test.txt的日志文件,每运行一次,里面都增加2行:
[ERROR][<module>][2012-09-04 22:41:19,546]this is a error msg!
[CRITICAL][<module>][2012-09-04 22:41:19,562]this is a error msg!
上面程序首先生成一个日志对象logger,用它来控制日志的输入。然后生成了一个handler,logging支持很多种Handler,像FileHandler,SocketHandler等待,这里由于我们要写文件,所以用了FileHandler,它的参数就是filename,默认当前路径,当然我们可以自己指定路径。后面还设置日志信息输出的级别。

2.3,程序3

可以用“python test.py debug”的方式来控制输入级别,代码如下:

#test.py
import logging
import sys
LEVELS={'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARNING,
        'error':logging.ERROR,
        'critical':logging.CRITICAL}

if len(sys.argv)>1:
        level_name=sys.argv[1]
        level=LEVELS.get(level_name,logging.NOTSET)
        logging.basicConfig(level=level)

        logging.debug("This is a debug message")
        logging.info("This is an info message")
        logging.warning("This is a warning message")
        logging.error("This is an error message")


2.4,程序4

使用配置文件形式:Python的logging.config.

Python的logging模块接口仿log4j,概念上一致,使用上相当方便。利用logging.config.fileConfig(),可以将日志的配置用文件来描述,简化了日志的初始化。


例程:
#  test.py
import  logging
import  logging.config

logging.config.fileConfig(
" logging.conf " )

# create logger
logger  =  logging.getLogger( " example " )

# "application" code
logger.debug( " debug message " )
logger.info(
" info message " )
logger.warn(
" warn message " )
logger.error(
" error message " )
logger.critical(
" critical message " )

logHello 
=  logging.getLogger( " hello " )
logHello.info(
" Hello world! " )



配置文件示例如下:
# logging.conf

[ loggers ]
keys
= root , example

[ handlers ]
keys
= consoleHandler , rotateFileHandler

[ formatters ]
keys
= simpleFormatter

[ formatter_simpleFormatter ]
format
= [ %(asctime)s ] (%(levelname)s)%(name)s : %(message)s

[ logger_root ]
level
= DEBUG
handlers
= consoleHandler , rotateFileHandler

[ logger_example ]
level
= DEBUG
handlers
= consoleHandler , rotateFileHandler
qualname
= example
propagate
= 0

[ handler_consoleHandler ]
class
= StreamHandler
level
= DEBUG
formatter
= simpleFormatter
args
= (sys.stdout , )

[ handler_rotateFileHandler ]
class
= handlers.RotatingFileHandler
level
= DEBUG
formatter
= simpleFormatter
args
= ('test.log' ,  'a' ,   200000 ,   9 )



这样,会生成test.log.


2.5,程序5【多文件共用一个log文件】

这里叙述的是我工作中遇到的问题,需要将多个文件的log信息输入到一个文件中去。我的理解是,在A文件中设置了譬如log文件位置、log文件名字、格式化信息等等,然后在A文件末尾可能用os.system("python B.py")这样又调用了B文件,那么在B文件中要也输出到之前指定的那个log文件,必须重新设置一遍刚才的log信息。这是因为,os.system()相当于系统调用了。与import不一样,import可以理解为将代码插到这个位置。

A.py

import os,sys,time

def xixi():
    gLogger.info("xixi")

def mylog():
    import logging.config
    gLogger = logging.getLogger()
    logdir = "log/"
    logfile = "verify.log"
    os.system("mkdir -p " + logdir)
    log_file = "./%s/%s"%(logdir,logfile)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.handlers.RotatingFileHandler(log_file)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    gLogger.setLevel(logging.INFO)
    return gLogger

if __name__ == "__main__":
    gLogger = mylog()
    xixi()
    gLogger.info("A.py")
    os.system("python B.py")

B.py

import os,sys,time
import logging.config

gLogger = logging.getLogger()
logdir = "log/"
logfile = "verify.log"
os.system("mkdir -p " + logdir)
log_file = "./%s/%s"%(logdir,logfile)
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
gLogger.addHandler(handler)
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
handler = logging.handlers.RotatingFileHandler(log_file)
handler.setFormatter(formatter)
gLogger.addHandler(handler)
gLogger.setLevel(logging.INFO)

gLogger.info("B1.py")
if __name__ == "__main__":
    gLogger.info("B2.py")

命令

[admin@r42h06016.xy2.aliyun.com]$python A.py

输出

[2012-09-18 23:13:28,301][INFO] xixi
[2012-09-18 23:13:28,301][INFO] A.py
[2012-09-18 23:13:28,344][INFO] B1.py
[2012-09-18 23:13:28,344][INFO] B2.py
分析

首先,python A.py 这时,运行到main,调用函数mylog初始化log信息。这时可以用gLogger来输出信息。调用xixi,之所以可以用,因为函数相当于将代码贴过来,这时gLogger已经定义过了。然后再输出A.py的信息。然后系统调用B,B已经事先初始化了。这时gLogger必然处处可用。

2.6 我的习惯

我一般是将logging等相关内容写在一个文件里,如下所示:

module_mylog.py

import os,sys
def mylog():
    import logging.config
    gLogger = logging.getLogger()
    logdir = "log/"
    logfile = "load.log"
    os.system("mkdir -p " + logdir)
    log_file = "./%s/%s"%(logdir,logfile)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.handlers.RotatingFileHandler(log_file)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    gLogger.setLevel(logging.INFO)
    return gLogger
gLogger = mylog()
其他任何文件要公用这个log时,都只需import就可以:

A.py

from module_myverifylog import gLogger

if __name__ == "__main__":
    gLogger.info("A.py")

B.py

from module_myverifylog import gLogger

if __name__ == "__main__":
    gLogger.info("B.py")

不用担心其他文件都import它都会重新运行,实际上只会运行一次,这是当做全局变量来做的。这样A.py和B.py的log都会在一个日志里了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值