python之logging模块

来源:互联网 发布:知乎精彩回答 编辑:程序博客网 时间:2024/05/16 01:46

import logging# create a loggerlogger = logging.getLogger('mylogger')logger.setLevel(logging.INFO)# create a handler, output to filefh = logging.FileHandler('/tmp/test.log')# formatformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')fh.setFormatter(formatter)  # add handler to loggerlogger.addHandler(fh)# outputlogger.debug('logger debug message')  logger.info('logger info message')  logger.warning('logger warning message')  logger.error('logger error message')  logger.critical('logger critical message')

输出:

2016-04-22 17:23:11,388 - mylogger - INFO - logger info message2016-04-22 17:23:11,389 - mylogger - WARNING - logger warning message2016-04-22 17:23:11,389 - mylogger - ERROR - logger error message2016-04-22 17:23:11,389 - mylogger - CRITICAL - logger critical message

以上代码包含了logging模块的Logger,Handler,Formatter.

Logger

Logger是一个树形层级结构,输出信息之前都要获得一个Logger.首先必须通过.get_Logger(name)获得一个logger对象,如果没有指定name,则默认返回一个root logger.此时还没有设置日志级别,默认的日志级别是logging.WARN.日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET只有日志等级大于或等于设置的日志级别的日志才会被输出。logger.setLevel(...)用来设置日志级别.

Handler

Handler对象负责发送相关的信息到输出.输出可以是流,也可以是文件.

logging.StreamHandler(stream=None)是流,stream可以是sys.stdout和sys.stderr,默认是sys.stderr.

logging.FileHandler(filename, mode='a', encoding=None, delay=0), 设置输出的文件,可以使用绝对地址,也可以使用相对地址.

logging.handlers.RotatingFileHandler和logging.handlers.TimedRotatingFileHandler不做介绍,都是FileHandler的扩展.

然后可以通过addHandler()方法为Logger添加多个Handler.比如可以同时把文件句柄和流句柄同时add到logger中,这样输出的内容就既可以打印到文件中,也可以打印到终端.当然,文件句柄和流句柄的日志级别可以分别设置.

Formatter

Formatter对象设置日志信息的规则、结构和内容.

%(name)s

Logger的名字

%(levelno)s

数字形式的日志级别

%(levelname)s

文本形式的日志级别

%(pathname)s

调用日志输出函数的模块的完整路径名,可能没有

%(filename)s

调用日志输出函数的模块的文件名

%(module)s

调用日志输出函数的模块名

%(funcName)s

调用日志输出函数的函数名

%(lineno)d

调用日志输出函数的语句所在的代码行

%(created)f

当前时间,用UNIX标准的表示时间的浮点数表示

%(relativeCreated)d

输出日志信息时的,自Logger创建以来的毫秒数

%(asctime)s

字符串形式的当前时间。默认格式是“2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d

线程ID。可能没有

%(threadName)s

线程名。可能没有

%(process)d

进程ID。可能没有

%(message)s

用户输出的消息

注:上表来自http://blog.csdn.net/ghostfromheaven/article/details/8249444, 若有版权冲突,请原博主告知.


logging模块的日志结构是一个树型结构.所有的日志都继承自root logger,即所有的logger都是root logger的子日志.

而日志的继承关系也很简单,就看logging.get_Logger(name)中的name来区分,比如开头的例子,mylogger日志是root logger的子日志,mylogger日志输出到test.log中,如果我在创建一个日志mylogger.1,那么mylogger.1就是mylogger的子日志,同理,mylogger.1.child就是mylogger.1的子日志.父日志和子日志的输出文件名并没有任何关系.比如父日志输出文件叫test.log,子日志输出文件可以叫test2.log.


import logging# create a loggerlogger = logging.getLogger('mylogger')logger.setLevel(logging.INFO)# create a handler, output to filefh = logging.FileHandler('/tmp/test.log')# formatformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')fh.setFormatter(formatter)  # add handler to loggerlogger.addHandler(fh)# another loggerchild_logger = logging.getLogger('mylogger.1')child_logger.setLevel(logging.DEBUG)ch = logging.FileHandler('/tmp/test2.log')formatter = logging.Formatter('%(asctime)s %(filename)s(%(lineno)d) %(levelname)s - %(message)s')ch.setFormatter(formatter)child_logger.addHandler(ch)# outputlogger.debug('logger debug message')  logger.info('logger info message')   child_logger.debug('child logger debug message')  child_logger.info('child logger info message')
输出:

/tmp/test2.log

2016-04-22 17:52:16,813 log_test.py(29) DEBUG - child logger debug message2016-04-22 17:52:16,813 log_test.py(30) INFO - child logger info message
/tmp/test.log

2016-04-22 17:52:16,813 - mylogger - INFO - logger info message2016-04-22 17:52:16,813 - mylogger.1 - DEBUG - child logger debug message2016-04-22 17:52:16,813 - mylogger.1 - INFO - child logger info message
可以看到,子日志会将消息分发给他的handler进行处理也会传递给所有的祖先Logger处理。而父日志并不会输出到子日志文件中.同时,子日志的输出级别往父日志输出时,会覆盖父日志的输出级别.比如本例,子日志的输出级别为DEBUG的日志也可以输出到父日志级别为INFO的日志中.


  • logging.basic_Config(...)作用于root logger, 所有的logger自动继承root logger的各项设置,但随后可以自己根据以上的一些函数进行定制.
  • logging模块是线程安全的.同时,在同一个python解释器下,在不同的模块或线程中使用get_Logger(name)获得logger,如果name相同的话,实际上获取到的是同一个日志,如果分别在不同的地方为该日志addHandler了,则在所有的地方打印到的日志信息会打印到所有该logger的handler中.


有兴趣可以看一下如下代码:

import loggingclass log_request(object):def __init__(self, name):handler = logging.FileHandler(name)fm = logging.Formatter('%(asctime)s %(filename)s(%(lineno)d) %(levelname)s - %(message)s')handler.setFormatter(fm)self.logger = logging.getLogger(name)self.logger.addHandler(handler)self.logger.setLevel(logging.DEBUG)console = logging.StreamHandler()console.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s %(filename)s(%(lineno)d) %(levelname)s - %(message)s')console.setFormatter(formatter)self.logger.addHandler(console)class log_record(object):def __init__(self, name):lh = logging.handlers.RotatingFileHandler(name, maxBytes=10*1024*1024, backupCount=3)fm = logging.Formatter('%(asctime)s %(filename)s(%(lineno)d) %(levelname)s - %(message)s')lh.setFormatter(fm)lh.suffix = '%Y-%m-%d'self.logger = logging.getLogger('%s'%name)self.logger.addHandler(lh)self.logger.setLevel(logging.DEBUG)console = logging.StreamHandler()console.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s %(filename)s(%(lineno)d) %(levelname)s - %(message)s')console.setFormatter(formatter)self.logger.addHandler(console)record = log_record('record')request = log_request('request')record.logger.info('hello world')request.logger.info('test python logging')


0 0