Python中 logging 模块 详解

1. 概述

Python中 logging 模块 是记录程序在运行过程中的日志,主要为了开发人员检查程序运行的情况,当然也可以为用户提醒一些信息。
以下内容一部分参考于一位前辈,做了部分修改,感谢!

2. 日志的级别

python中日志一共分成5个等级,从低到高分别是:DEBUG、INFO、 WARNING、ERROR、CRITICAL

  1. DEBUG:详细的信息,通常只出现在诊断问题上;
  2. INFO:确认一切按预期运行;
  3. WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如:磁盘空间低);目前这个软件还能按预期工作;
  4. ERROR:比较严重的问题,软件或程序没能执行一些功能;
  5. CRITICAL:十分严重的错误,这表明程序本身可能无法继续运行。

这5个等级,也分别对应5种打印日志的方法: debug 、info 、warning 、error 、critical。默认的是打印的日志是 WARNING,当在 WARNING 或之上时才被跟踪。

3. 日志的输出方式

有两种方式记录跟踪,一种输出到控制台,另一种是记录到文件中,比如日志文件。

3.1 将日志输出到控制台

比如,编写一个叫做 log.py 的文件,如下:

# coding=utf-8
import logging  # 导入logging模块

logging.basicConfig(level=logging.WARNING,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
# 配置logging的基本信息, level=logging.WARNING,记录WARNING及以上的日志,format 记录格式及内容

# use logging
logging.debug('this is a loggging debug message')
logging.info('this is a loggging info message')
logging.warning('this is loggging a warning message')
logging.error('this is an loggging error message')
logging.critical('this is a loggging critical message')

打印结果如下:

2019-01-08 16:05:53,983 - log.py[line:11] - WARNING: this is loggging a warning message
2019-01-08 16:05:53,984 - log.py[line:12] - ERROR: this is an loggging error message
2019-01-08 16:05:53,984 - log.py[line:13] - CRITICAL: this is a loggging critical message

通过 logging.basicConfig 函数对日志的输出格式及方式做相关配置,上面代码设置日志的输出等级是WARNING级别,意思是WARNING级别以上的日志才会输出。

3.2 将日志输出到文件中

我们还可以将日志输出到文件,只需要在 logging.basicConfig 函数中设置好输出文件的文件名和写文件的模式。

# coding=utf-8
import logging

logging.basicConfig(level=logging.WARNING,
                    filename='./log/log.txt',   # 注意需要提前新建一个log文件加,log.txt会自动创建的
                    filemode='w',   # 写文件
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
# use logging
logging.info('this is a loggging info message')
logging.debug('this is a loggging debug message')
logging.warning('this is loggging a warning message')
logging.error('this is an loggging error message')
logging.critical('this is a loggging critical message')

打开log下的log.txt文件,结果如下:
在这里插入图片描述

3.3 将日志输出到控制台同时写入日志文件

这就需要一个叫作 Logger 的对象来帮忙,下面将对它进行详细介绍,现在这里先学习怎么实现把日志既要输出到控制台又要输出到文件的功能。

# coding=utf-8
import logging

# 第一步,创建一个logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Log等级总开关

# 第二步,创建一个handler,用于写入日志文件
logfile = './log/logger.txt'
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关

# 第三步,再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)  # 输出到console的log等级的开关

# 第四步,定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 第五步,将logger添加到handler里面
logger.addHandler(fh)
logger.addHandler(ch)

# 日志
logger.debug('this is a logger debug message')
logger.info('this is a logger info message')
logger.warning('this is a logger warning message')
logger.error('this is a logger error message')
logger.critical('this is a logger critical message')

执行代码,控制台打印结果:

2019-01-08 16:16:50,176 - log.py[line:29] - WARNING: this is a logger warning message
2019-01-08 16:16:50,176 - log.py[line:30] - ERROR: this is a logger error message
2019-01-08 16:16:50,176 - log.py[line:31] - CRITICAL: this is a logger critical message

在logger.txt中,结果为:
在这里插入图片描述
可以发现,实现这个功能一共分5步:

代码简析:
第一步,创建一个logger;第二步,创建一个handler,用于写入日志文件;第三步,再创建一个handler,用于输出到控制台;第四步,定义handler的输出格式;第五步,将logger添加到handler里面。这段代码里面提到了好多概念,包括:Logger,Handler,Formatter。后面讲对这些概念进行讲解。

3.4 多个模块中日志输出顺序

通常我们的工作中会有多个模块都需要输出日志。那么,具有调用关系的模块之间,它门的日志输出顺序是怎么样的?我们来演示下:假设有两个文件,分别是util.py

# util.py
import logging


def fun():
    logging.info('this is a log in util module')

和main.py

# coding=utf-8
import logging
import util

logging.basicConfig(level=logging.INFO,
                    filename='./log/log.txt',
                    filemode='w',
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')


def main():
    logging.info('main module start')
    util.fun()
    logging.info('main module stop')


if __name__ == '__main__':
    main()

运行后打开log.txt,结果如下:
在这里插入图片描述
可以看出,日志的输出顺序就是模块的执行顺序。

4. 日志格式说明

logging.basicConfig 函数中,可以指定日志的输出格式 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  #  打印日志信息

在工作中给的常用格式在前面已经看到了。就是:

format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'

这个格式可以输出日志的打印时间,是哪个模块输出的,输出的日志级别是什么,以及输入的日志内容。

5. 高级进阶

接下来学习一些日志组件以及一些高级部分。
日志组件包括:loggers、handlers、filters、formatters.

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

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

filter: 细致化,选择哪些日志输出。

format: 设置显示格式

5.1 logging.basicConfig([**kwargs]):
Does basic configuration for the logging system by creating a StreamHandler with a defaultFormatter and adding it to the root logger. The functionsdebug(),info(),warning(),error() andcritical() will callbasicConfig() automatically if no handlers are defined for the root logger.

This function does nothing if the root logger already has handlers configured for it.

为日志模块配置基本信息;kwargs 支持如下几个关键字参数:
filename :日志文件的保存路径,如果配置了些参数,将自动创建一个FileHandler作为Handler;
filemode :日志文件的打开模式。 默认值为’a’,表示日志消息以追加的形式添加到日志文件中;如果设为’w’, 那么每次程序启动的时候都会创建一个新的日志文件;
format :设置日志输出格式;
datefmt :定义日期格式;
level :设置日志的级别.对低于该级别的日志消息将被忽略;
stream :设置特定的流用于初始化StreamHandler。
示例

import logging
import os
FILE=os.getcwd()

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 = os.path.join(FILE,'log.txt'),
                    filemode='w')
logging.info('msg')
logging.debug('msg2')

代码会自动在当前路径下创建一个 log.txt ,打印结果如下:
在这里插入图片描述

5.2 logging.getLogger([name])

用于创建Logger对象;日志记录的工作主要由Logger对象来完成;在调用 getLogger 时要提供 Logger 的名称(注:多次使用相同名称 来调用getLogger,返回的是同一个对象的引用),Logger 实例之间有层次关系,这些关系通过Logger名称来体现,如:

p = logging.getLogger("root")
c1 = logging.getLogger("root.c1")
c2 = logging.getLogger("root.c2")

例子中,p是父 logger , c1、c2 分别是p的子logger。
c1、 c2 将继承 p 的设置,如果省略了 name 参数,getLogger 将返回日志对象层次关系中的根Logger。

import logging
# 命名
log2 = logging.getLogger('BeginMan')  # 生成一个日志对象
print(log2)  # <Logger BeginMan (WARNING)>

# 不命名
log3 = logging.getLogger()
print(log3)  # <RootLogger root (WARNING)> 如果没有指定name,则返回RootLogger

# 推荐的方式
log = logging.getLogger(__name__)  # __name__ is the module’s name in the Python package namespace.
print(log)   # <Logger __main__ (WARNING)>  Logger对象
print(__name__)  # __main__

打印结果如下:

<Logger BeginMan (WARNING)>
<RootLogger root (WARNING)>
<Logger __main__ (WARNING)>
__main__
5.3 Logger对象

通过logging.getLogger(nam)来获取Logger对象,Logger对象有如下属性和方法。

5.3.1Logger.propagate

log.propagate 这是一个布尔标志, 用于指示消息是否传播给父记录器。

import logging

log = logging.getLogger()  # 生成一个日志对象
print(log.propagate)

打印结果

True # 表示传播给父记录器

具体参考:http://docs.python.org/2.7/library/logging.html

5.3.2 Logger.setLevel(lvl)

设置日志的级别;对于低于该级别的日志消息将被忽略.

import logging
import os

logging.basicConfig(format="%(levelname)s,%(message)s",filename=os.path.join(os.getcwd(), 'log.txt'), level=logging.DEBUG)
log = logging.getLogger('root.set')   # Logger对象
log.setLevel(logging.WARN)  # 日志记录级别为WARNNING
log.info('msg')             # 不会被记录
log.debug('msg')            # 不会被记录
log.warning('msg')
log.error('msg')

log.txt 结果如下:
在这里插入图片描述

5.3.3 Logger.debug(msg [ ,*args [, **kwargs]])

记录DEBUG级别的日志信息。参数msg是信息的格式,args与kwargs分别是格式参数。

import logging
import os

logging.basicConfig(filename = os.path.join(os.getcwd(), 'log.txt'), level = logging.DEBUG)
log = logging.getLogger('root')
log.debug('%s, %s, %s', *('error', 'debug', 'info'))
log.debug('%(module)s, %(info)s', {'module': 'log', 'info': 'error'})

log.txt 结果如下:
在这里插入图片描述

5.3.4 同5.3.3,只是记录的类型不同
Logger.info(msg[ , *args[ , **kwargs] ] )
Logger.warnning(msg[ , *args[ , **kwargs] ] )
Logger.error(msg[ , *args[ , **kwargs] ] )
Logger.critical(msg[ , *args[ , **kwargs] ] )
5.3.5 Logger.log(lvl, msg[ , *args[ , **kwargs]] )

记录日志,参数 lvl 用户设置日志信息的级别;参数msg, *args, **kwargs的含义与Logger.debug一样。

import logging
import os

logging.basicConfig(filename = os.path.join(os.getcwd(), 'log.txt'), level = logging.DEBUG)
log = logging.getLogger('root')
log.log(logging.ERROR,'%(module)s %(info)s',{'module':'log日志','info':'error'}) #ERROR,log日志 error
log.log(logging.ERROR,'再来一遍:%s,%s',*('log日志','error'))  #ERROR,再来一遍:log日志,error

log.txt 结果如下:
在这里插入图片描述

5.3.6 Logger.exception(msg[, *args])

以ERROR级别记录日志消息,异常跟踪信息将被自动添加到日志消息里。Logger.exception通过用在异常处理块中,如:

import logging
import os
logging.basicConfig(format="%(levelname)s,%(message)s",filename=os.path.join(os.getcwd(),'log.txt'),level=logging.DEBUG)
log = logging.getLogger('root')   #Logger对象
try:
    raise Exception(u'错误异常')
except:
    log.exception('exception')  #异常信息被自动添加到日志消息中

log.txt 结果如下:
在这里插入图片描述

5.3.7 Logger.addFilter(filt)

指定过滤器

5.3.8 Logger.removeFilter(filt)

移除指定的过滤器

5.3.9 Logger.filter(record)

猜你喜欢

转载自blog.csdn.net/qq_41800366/article/details/86080010