Python 标准库自带日志模块。python 程序的日志记录可直接调用标准库的日志模块。
日志的严重等级 严重等级为 NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL, 严重程度依次递增。

CRITICAL: 50
ERROR: 40
WARNING: 30
INFO: 20
DEBUG: 10
NOTSET: 0
基本用法
  1. 开发轻量级的应用,对日志要求简单,直接在相关代码逻辑中加入日志功能即可。
import logging

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

输出日志:

WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

默认情况下,日志级别在 WARNING 及以上的日志输出到标准输出。

  1. 日志输出到文件,需要使用logging.basicConfig()做简单的配置

代码示例如下:

import logging

# 配置日志文件和日志级别
logging.basicConfig(filename='logger.log', level=logging.INFO)

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

日志级别在 INFO 及以上的日志会输出到文件 logger.log。

更加完善的日志功能
1. 关键概念

LoggerHandlerFormatterFilter是日志模块的基本概念,其包含的成员和方法可以查看官方文档

1.1 Logger

Logging 不直接实例化 Logger 对象,通过调用logging.getLogger(name)创建 Logger 实例;若传入的参数name值相同,则返回同一个 Logger 对象实例的引用。

logger = logging.getLogger('simple_example')

若没有显式地创建 Logger 实例,默认创建一个root logger,默认的日志级别是WARNING,默认的处理器是StreamHandler(即日志信息输出到标准输出),默认的格式化器 Formatter(logging level:instance name:logging message)。

1.2 Handler

通过 Logger 对象的addHandler()方法为 Logger 对象添加 0 个或多个 Handler 的子类对象,将日志信息输出到设置的地方。比如,一个典型的应用场景:系统希望将所有的日志信息保存到 log 文件中,其中日志等级等于或高于ERROR的消息还要在屏幕标准输出上显示,日志等级为CRITICAL的还需要发送邮件通知;这种场景就需要 3 个独立的 handler 来实现需求。

需要注意的是,为 Logger 配置的 handler 不是 Handler 基类对象,而是 Handler 的子类对象,常用的 Handler 为StreamHandler, FileHandler, 和NullHandler

1.3 Formatter

Formatter 用于设置日志输出的格式,可直接初始化对象,即formatter=logging.Formatter(fmt=None, datefmt=None)。默认的日志格式fmt%(asctime)s - %(levelname)s - %(messages),默认的时间格式datefmt%Y-%m-%d %H:%M:%S

1.4 Filter

Filter 可用于 Logger 对象或 Handler 对象,用于提供比日志等级更加复杂的日志过滤方式。Filter 在日志功能配置中是非必须的,对日志消息过滤需求比较复杂时配置使用。

2. 日志产生流程

日志流程

3. 日志模块的使用

使用日志模块的关键在于日志的配置。开发者可以通过 3 种方法配置日志:
a. 在 Python 代码中显示创建 Logger,Handler,Formatter 和 Filter 对象,并调用各对象的配置函数进行日志配置
b. 将配置信息写到配置文件,通过读取配置文件进行日志配置
c. 将配置信息写到Dict,通过读取配置字典进行日志配置

3.1 通过代码配置并使用日志模块

通过代码配置日志模块,简单方便,但不建议在大型项目中使用这种方法。
1) 创建 Logger

import logging
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)

2) 创建 Handler

# create console handler and set level to warn
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)

3) 创建 Formatter

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

4) 配置 Logger

ch.setFormatter(formatter)

# add ch to logger
# The final log level is the higher one between the default and the one in handler
logger.addHandler(ch)

5) 使用日志模块

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

输出结果(输出 Warn 及其以上的日志);

2018-01-21 20:54:30,605 - simple_example - WARNING - warn message
2018-01-21 20:54:30,606 - simple_example - ERROR - error message
2018-01-21 20:54:30,606 - simple_example - CRITICAL - critical message
3.2 通过配置文件配置并使用日志模块

配置文件通常使用.ini格式。日志模块调用fileConfig()读取配置信息,完成日志配置,即logging.config.fileConfig('logging_config.ini')
文件logging_config.ini的内容如下:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=INFO
handlers=consoleHandler
qualname=simpleExample
propagate=0

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

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

使用日志模块的代码如下:

import logging
import logging.config

logging.config.fileConfig('logging_config.ini')

logger = logging.getLogger('root')

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
3.3 通过 Dict 对象配置并使用日志模块

基于 Dict 对象配置日志模块在 python 中应用广泛,比如 Django、Flask 项目采用这种方式。本文提供一个使用样例。

!/usr/local/bin/python
-- coding: utf-8 --

import logging
import logging.config

config = {
    'version': 1,
    'formatters': {
        'simple': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'simple'
        },
        'file': {
            'class': 'logging.FileHandler',
            'filename': 'logging.log',
            'level': 'DEBUG',
            'formatter': 'simple'
        },
    },
    'loggers':{
        'root': {
            'handlers': ['console'],
            'level': 'DEBUG',
            # 'propagate': True,
        },
        'simple': {
            'handlers': ['console', 'file'],
            'level': 'WARN',
        }
    }
}

logging.config.dictConfig(config)


print('logger:')
logger = logging.getLogger('root')

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


print('logger2:')
logger2 = logging.getLogger('simple')

logger2.debug('debug message')
logger2.info('info message')
logger2.warn('warn message')
logger2.error('error message')
logger2.critical('critical message')
其他

学习 Logging 过程中,个人认为比较好的资源:

特别感谢 Gevin 的Python 日志功能详解

[Mario Corchero] 的 A guide to logging in python

Python logging 模块和使用经验

Python 中的 logging 模块


↙↙↙阅读原文可查看相关链接,并与作者交流