python日志: logging

        在 Python 中,怎样才能算作一个比较标准的日志记录过程呢?或许很多人会使用 print 语句输出一些运行信息,然后再在控制台观察,运行的时候再将输出重定向到文件输出流保存到文件中,这样其实是非常不规范的,在 Python 中有一个标准的 logging 模块,我们可以使用它来进行标注的日志记录,利用它我们可以更方便地进行日志记录,同时还可以做更方便的级别区分以及一些额外日志信息的记录,如时间、运行模块信息等。

 logging模块简介

logging模块是Python的一个标准库模块,开发过程中,可以通过该模块,灵活的完成日志的记录。

logging模块提供了两种记录日志的方式:
    1)使用logging提供的模块级别的函数(logging.basicConfig,logging.debug,logging.info…)
    2)使用logging模块的组件(loggers,handlers,filters,formatters)

这里建议使用第二种方式

 logging模块的日志级别

        DEBUG < INFO < WARNING < ERROR < CRITICAL 

日志级别(level) 描述
DEBUG 调试级别,一般用于问题的排查,日志的信息最为详细
INFO 仅记录普通的信息,日志信息的详细程度仅次于DEBUG
WARNING 警告信息,一般这类信息不会影响程序的正常运行
ERROR 错误信息, 出现错误信息时,程序一般已不能正常运行
CRITICAL 更严重的错误信息,程序不能继续运行

 

import logging

logging.info('This is a log info')
logging.debug('Debugging')
logging.warning('Warning exists')
logging.info('Finish')

我们发现 DEBUG 的信息是没有输出的,这是因为我们在全局配置的时候设置了输出为 INFO 级别,所以 DEBUG 级别的信息就被过滤掉了。 这时如果我们将输出的日志级别设置为 DEBUG,就可以看到 DEBUG 级别的日志输出了:

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

 basicConfig是logging模块的全局配置方法

basicConfig方法接收的参数
关键字 描述
filename 创建一个FileHandler,使用指定的文件名,而不是使用StreamHandler。
filemode 如果指明了文件名,指明打开文件的模式(如果没有指明filemode,默认为'a')。
format handler使用指明的格式化字符串。
datefmt 使用指明的日期/时间格式。
level 指明根logger的级别。
stream 使用指明的流来初始化StreamHandler。该参数与'filename'不兼容,如果两个都有,'stream'被忽略。
format 的格式
格式 描述
%(levelno)s 打印日志级别的数值
%(levelname)s 打印日志级别名称
%(pathname)s 打印当前执行程序的路径
%(filename)s 打印当前执行程序名称
%(funcName)s 打印日志的当前函数
%(lineno)d 打印日志的当前行号
%(asctime)s 打印日志的时间
%(thread)d 打印线程id
%(threadName)s 打印线程名称
%(process)d 打印进程ID
%(message)s 打印日志信息

 

import logging

logging.basicConfig(level=logging.DEBUG,
                    filename='output.log',
                    datefmt='%Y/%m/%d %H:%M:%S',
                    format='%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(module)s - %(message)s')

logging.info('This is a log info')
logging.debug('Debugging')
logging.warning('Warning exists')
logging.info('Finish')

四大组件

 

组件名称 功能描述
Logger 日志器,提供了应用程序可一直使用的接口
Handler 负责日志记录的传输目的地,比如有FileHandler(写入目标为文件)和StreamHandler(写入目标为流,默认为标准输出流)
Filter 负责过滤哪些日志是要输出的,若有多个 Logger,可根据名称过滤出指定的 Logger 来记录日志
Formatter 负责对日志输出格式的格式化

1. Logger

1)logging.getLogger(name)  指定name,返回一个名称为name的Logger实例。如果再次使用相同的名字,是实例化一个对象。未指定name,返回Logger实例,名称是root,即根Logger。
2)创建一个或多个 handler,用于指定日志信息的输出流向
3)创建一个或多个 formatter,指定日志的格式,并分别将 formatter 绑定到 上
4)将 handler 绑定到 logger对象 上
5)logger.setLevel(logging.DEBUG) 设置日志级别

 

import logging

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.WARN)

# Log
logger.debug('Debugging')
logger.critical('Critical Something')
logger.error('Error Occurred')
logger.warning('Warning exists')
logger.info('Finished')

2.Handler

        

  • StreamHandler:logging.StreamHandler;日志输出到流,可以是 sys.stderr,sys.stdout 或者文件。
  • FileHandler:logging.FileHandler;日志输出到文件。
  • BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志回滚方式。
  • RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚。
  • TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件。
  • SocketHandler:logging.handlers.SocketHandler;远程输出日志到 TCP/IP sockets。
  • DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到 UDP sockets。
  • SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址。
  • SysLogHandler:logging.handlers.SysLogHandler;日志输出到 syslog。
  • NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到 Windows NT/2000/XP 的事件日志。
  • MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定 buffer。
  • HTTPHandler:logging.handlers.HTTPHandler;通过”GET” 或者”POST” 远程输出到 HTTP 服务器。

 

import logging

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.DEBUG)

# StreamHandler
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(level=logging.DEBUG)
logger.addHandler(stream_handler)

# FileHandler
file_handler = logging.FileHandler('output.log')
file_handler.setLevel(level=logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)


# Log
logger.info('This is a log info')
logger.debug('Debugging')
logger.warning('Warning exists')
logger.info('Finish')

 3.Formatter

        在进行日志格式化输出的时候,我们可以不借助于 basicConfig 来全局配置格式化输出内容,可以借助于 Formatter 来完成,下面我们再来单独看下 Formatter 的用法:

import logging

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.WARN)
formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)

# Log
logger.debug('Debugging')
logger.critical('Critical Something')
logger.error('Error Occurred')
logger.warning('Warning exists')
logger.info('Finished')

 在这里我们指定了一个 Formatter,并传入了 fmt 和 datefmt 参数,这样就指定了日志结果的输出格式和时间格式,然后 handler 通过 setFormatter () 方法设置此 Formatter 对象即可

设置format中特殊字符asctime(日期时间)的输出格式

  • 特殊字符:
    • %y 两位数的年份表示(00-99)
    • %Y 四位数的年份表示(000-9999)
    • %m 月份(01-12)
    • %d 月内中的一天(0-31)
    • %H 24小时制小时数(0-23)
    • %I 12小时制小时数(01-12)
    • %M 分钟数(00=59)
    • %S 秒(00-59)

使用自己想要的分隔符和顺序来定义日期时间的格式,例如:

datefmt='%m/%d/%Y %I:%M:%S %p'

 

 4.Filter

        决定一个日志记录是否发送到handler。

        

import logging

logger1 = logging.getLogger('aaa')
logger2 = logging.getLogger('bbb')

# 定义一个 filter
filter = logging.Filter(name='bbb')

# 定义一个 handler
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)

# 若两个 logger对象 的日志级别相同,且都是用通过一个 handler,可以在这个 handler 上设置日志级别
ch.setLevel(logging.ERROR)

# 在 handler 上放置过滤器
ch.addFilter(filter)

logger1.addHandler(ch)
logger2.addHandler(ch)
logger1.error('logger1 error message')
logger2.error('logger2 error message')

因为对handler增加一个过滤器,过滤器就像一个筛子,只筛选出我们想要的日志,上图代码中的过滤器只接收名为bbb的loger产生的日志

上一篇:装饰器使用-记录日志


下一篇:自动化框架之Python日志模块二次封装技巧分享