Python-Log

示例代码

import logging

LOG_FORMAT = "%(asctime)s====%(levelname)s++++%(message)s"
logging.basicConfig(filename="tulingxueyuan.log", level=logging.DEBUG, format=LOG_FORMAT)
logging.debug("This is a debug log .")
logging.info("This is a info log .")
logging.warning("This is a warning log .")
logging.error("This is a error log .")
logging.critical("This is a critical log .")

# 另一种写法
logging.log(logging.DEBUG, "This is a debug log .")
logging.log(logging.INFO, "This is a info log .")
logging.log(logging.WARNING, "This is a warning log .")
logging.log(logging.ERROR, "This is a error log .")
logging.log(logging.CRITICAL, "This is a critical log .")

logging模块的使用方式

logging模块提供两种记录日志的方式:

  • 第一种 使用logging提供的模块级别的函数
  • 第二种 使用logging日志系统的四大组件


    常用函数

其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息,其他几个都是用于记录各个级别日志的函数。

logging.basicConfig函数说明

关键字参数:

  • filename,指定日志输目标文件的文件名,指定后日志不会在控制台输出。
  • filemode,指定日志文件的打开模式,默认为‘a’,此项必须在filename指定才有效。
  • format,指定日志格式字符串。
  • datefmt,指定日期时间格式。
  • level,指定日志器的日志级别。
  • stream,指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常。
  • style,指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%'。
  • handlers,该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。
logging模块定义的格式字符串字段
format格式字段

logging模块的处理流程

四大组件

  • 日志器(Logger):产生日志的一个接口
  • 处理器(Handler):把产生的日志发送到相应的目的地
  • 过滤器(Filter):更精细的控制那些日志输出
  • 格式器(Formatter):对输出信息进行格式化

组件直接的关系如下:

  • 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
  • 不同的处理器(handler)可以将日志输出到不同的位置;
  • 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
  • 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
  • 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。

日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。

logging模块相关类及常用方法

下面介绍下与logging四大组件相关的类:Logger, Handler, Filter, Formatter。

Logger类

Logger对象有3个任务:

  • 使应用程序可以在运行时记录日志消息
  • 基于日志严重等级或filter对象决定对哪些日志进行后续处理
  • 将日志消息传给所有感兴趣的handlers

logger对象最常用的方法分为两类:
配置方法和消息发送方法。
常用配置方法:

方法 描述
Logger.setLevel() 设置日志器将会处理的日志消息的最低严重级别
Logger.addHandler() 和 Logger.removeHandler() 为该logger对象添加 和 移除一个handler对象
Logger.addFilter() 和 Logger.removeFilter() 为该logger对象添加 和 移除一个filter对象

创建日志方法:

方法 描述
Logger.debug(), Logger.info()等 用来创建指定等级的日志记录
Logger.exception() 创建一个类似于Logger.error()的日志消息
Logger.log() 需要获取一个明确的日志level参数来创建一个日志记录
  • Logger.exception()与Logger.error()的区别在于:Logger.exception()将会输出堆栈追踪信息,另外通常只是在一个exception handler中调用该方法。
  • Logger.log()与Logger.debug()、Logger.info()等方法相比,虽然需要多传一个level参数,显得不是那么方便,但是当需要记录自定义level的日志时还是需要该方法来完成。

通过logging.getLogger方法来得到Logger对象,logging.getLogger()方法有一个可选参数name,该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为'root'。若以相同的name参数值多次调用getLogger()方法,将会返回指向同一个logger对象的引用。

Handler类

Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:

  • 把所有日志都发送到一个日志文件中;
  • 把所有严重级别大于等于error的日志发送到stdout(标准输出);
  • 把所有严重级别为critical的日志发送到一个email邮件地址。这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。
    配置方法:
方法 描述
Handler.setLevel() 设置handler将会处理的日志消息的最低严重级别
Handler.setFormatter() 为handler设置一个格式器对象
Handler.addFilter() 和 Handler.removeFilter() 为handler添加 和 删除一个过滤器对象

需要说明的是,应用程序代码不应该直接实例化和使用Handler实例。因为Handler是一个基类,它只定义了素有handlers都应该有的接口,同时提供了一些子类可以直接使用或覆盖的默认行为。
常用的Handler:

Handler 描述
logging.StreamHandler 将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。
logging.FileHandler 将日志消息发送到磁盘文件,默认情况下文件大小会无限增长
logging.handlers.RotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按大小切割
logging.hanlders.TimedRotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按时间切割
logging.handlers.HTTPHandler 将日志消息以GET或POST的方式发送给一个HTTP服务器
logging.handlers.SMTPHandler 将日志消息发送给一个指定的email地址
logging.NullHandler 该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免'No handlers could be found for logger XXX'信息的出现。
Formater类

Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
Formatter类构造方法如下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
Filter类

定义如下:

class logging.Filter(name=“”)
      filter(record)

比如,一个filter实例化时传递的name参数值为'A.B',那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录通过过滤:'A.B','A.B,C','A.B.C.D','A.B.D',而名称为'A.BB', 'B.A.B'的loggers产生的日志则会被过滤掉。如果name的值为空字符串,则允许所有的日志事件通过过滤。
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。

使用logging四大组件记录日志

1.需求
  • 将所有级别的所有日志写入磁盘文件
  • all.log中记录所有的日志信息,格式为:日期时间-级别-内容
  • error.log单独记录error及以上的日志信息,日期和时间 - 日志级别 - 文件名[:行号] - 日志信息
  • all.log在每天凌晨进行日志切割
2.分析
  • 记录所有级别的日志,level设置为DEBUG
  • 日志被发送给两个不同的目的地,需要设置两个handler,都需要写入磁盘,都跟filehandler有关
  • all.log要求按照时间进行日志分割,需要用到logging.handlers.TimedRotatingFileHandler,而error.log没有要求日志分割,可以使用FileHandler
  • 两个日志文件格式不同,设置不同的格式器
3.代码实现
import logging
import logging.handlers
import datetime


logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)

rf_handler = logging.handlers.TimedRotatingFileHandler('all.log', when='midnight',
                                                       interval=1, backupCount=7,
                                                       atTime=datetime.time(0, 0, 0, 0))
rf_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))

f_handler = logging.FileHandler('error.log')
f_handler.setLevel(logging.ERROR)
f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))

logger.addHandler(rf_handler)
logger.addHandler(f_handler)

logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
logger.critical('critical message')

配置logging的几种方式

作为开发者,我们可以通过以下3中方式来配置logging:

  • 使用python代码显式的创建loggers,handlers和formatters并分别调用他们的配置函数。
  • 创建日志配置文件,然后使用fileConfig函数来读取该文件的内容
  • 创建一个包含配置信息的dict,然后把它传递给dictConfig函数

可以参考博客《Python之配置日志的几种方式》

向日志输出中添加上下文信息

除了传递给日志记录函数的参数外,有时候我们还想在日志输出中包含一些额外的上下文信息。比如,在一个网络应用中,可能希望在日志中记录客户端的特定信息,如:远程客户端的IP地址和用户名。这里我们来介绍以下几种实现方式:

  • 通过日志记录函数传递一个extra参数引入上下文信息
  • 使LoggerAdapter引入上下文信息
  • 使用Filters引入上下文信息

具体说明请参考另一篇博文《Python之向日志输出中添加上下文信息》

你可能感兴趣的:(Python-Log)