日志级别

日志级别Level数值
CRITICAL50
ERROR40
WARNING30,默认级别
INFO20
DEBUG10
NOSET0

日志级别指的是产生日志的事件的严重程度.

设置一个级别后,严重程度低于设置值的日志消息将被忽略

格式化字符串

属性名格式描述
日志消息内容%(message)s当调用Formatter.format是设置
asctime%(asctime)s创建LogRecord时的可读时间, 默认格式:2021-06-17 16:33:45.145
函数名%(funcName)s日志调用所在函数名
日志级别名称%(levelname)sDEBUG, INFO, WARNING, ERROR, CRITICAL
级别数字%(levelno)s消息级别的数字:DEBUG, INFO, WARNING, ERROR, CRITICAL
行号%(lineno)d日志调用说在源码行号
模块%(module)s模块, filename的名字部分
进程ID%(process)d进程ID
线程ID%(thread)d线程ID
进程名称%(processName)s进程名称
线程名称%(threadName)s线程名称
logger名称%(name)logger名称
import logging
import threading

# 设置日志输出格式
FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s'
logging.basicConfig(level=logging.INFO,
                    format=FORMAT,
                    datefmt='%Y-%m-%d %H:%M:%S')

def add(x, y):
    logging.warning('{}'.format(threading.current_thread()))
    logging.info('%s %s %s', x, y, x + y)
    # 这里可以使用C风格的 info('%s %s %s', x, y, x + y)
  

自定义字段

FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s %(school)s'
# 添加了自定义school
logging.basicConfig(level=logging.INFO,
                    format=FORMAT,
                    datefmt='%Y-%m-%d %H:%M:%S')
# 日志输出, 通过字典传入
logging.info('This Test Log', extra={'school': 'Beijixs'})

输出到文件

FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s'
logging.basicConfig(level=logging.INFO,
                    format=FORMAT,
                    filemode='a',        # 输出文件模式, a追加(默认), w覆盖
                    filename='test.log',    # 输出到文件
                    datefmt='%Y-%m-%d %H:%M:%S')
logging.info('This is test log')

logger类

构造

使用工厂方法构造一个logger

import logging

logger = logging.getLogger(name="Main")
# getLogger(name=名称)
print(logger.name)

logger是层次结构的, 使用.号分割, 如a, a.b

import logging

logger = logging.getLogger(name="Main")
# getLogger(name=名称)
print(logger.name)

logger.info('Main 记录日志')
logger.parent.info('root 记录日志')

logger 的属性和方法

方法

  • getEffectiveLevel(): 获取当前logger的有效级别
  • setLevel(int): 设置当前logger的级别
logger = logging.getLogger(__name__)
logger.setLevel(logging.WARN)


def add(x, y):
    logger.warning('{}'.format(threading.current_thread()))
    logger.info('%s %s %s', x, y, x + y)
    logger.debug('DEBUG log')
    logger.error('ERROR log')

Handler

Handler控制日志信息的输出目的地,可以是控制台, 文件.

可以单独设置level

可以单独设置格式

可以设置过滤器

举例

import time
import logging
import threading

FORMAT = '%(asctime)s %(name)s %(levelname)s %(thread)d %(message)s'

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

# 终端输出处理器
hdl = logging.StreamHandler()
hdl.setFormatter(logging.Formatter(FORMAT, datefmt='%Y-%m-%d %H:%M:%S'))
hdl.setLevel(logging.INFO)
# 文件输出处理器
f_hdl = logging.FileHandler('test.log', encoding='utf8')
f_hdl.setLevel(logging.DEBUG)
f_hdl.setFormatter(logging.Formatter(FORMAT, datefmt='%Y-%m-%d %H:%M:%S'))

logger.addHandler(hdl)    # 可以添加多个handler
logger.addHandler(f_hdl)


def add(x, y):
    logger.warning('{}'.format(threading.current_thread()))
    logger.info('%s %s %s', x, y, x + y)
    logger.debug('DEBUG log')
    logger.error('ERROR log')
    logger.critical('CRITICAL log')


add(54, 89)

# logger的日志信息会向上传递
# 父logger如果有处理该级别日志的能力将会继续处理
"""
当前logger能够处理级别的日志, 当前logger会把消息发送给自己的handler, 然后将该消息传递给父logger, 父logger如果能够处理就继续处理并传递给父,直到不能处理
"""

handler的日志级别受到logger的级别限制, 假如: logger的级别为INFO, handler最高也就只能输出到INFO级别的日志, 就算设置为DEBUG,handler也只能记录到INFO

总结

  1. 每一个Logger实例的level如同入口,让水流进来,如果这个门槛太高,信息就进不来
  2. 如果level没有设置, 就使用父logger的, 以此类推.直到root都还没有找到级别,就直接继承root的,默认是WARNING
  3. 在某个logger上产生某种级别的消息, 首先和loggerlevel检查, 如果消息level低于loggerEffectiveLevel有效级别, 消息丢弃. 不会继续传递给父logger.如果通过(级别大于等于)检出后, 且propagateTrue, 消息交给logger的所有的handler进行处理, 如果没有handler或以及被handler处理过的, 该消息会向上传递给父logger处理
  4. logger拿到消息, 会重复第三天的过程, 直至消息被丢弃或到root
  5. logger实例化的propagate属性为True即允许向父传递logger消息

Formatter

loggingFromatter类, 它允许指定某个格式的字符串. 如果提供None, 那么%(message)s会被作为默认值.

formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(thread)d %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

hdl.setFromatter(formatter)

Filter

可以为Handler添加一个过滤器, 所以过滤器会影响某一个handler, 不会影响整个流程

filter = logging.Filter(__name__)   # logging.Filter(name=logger名称)
# 如果name为空, 那么所有消息都可以通过
# 如果设置了name, 那么就只有设置的logger name会通过
logger.addFilter(filter)    # 可以多添加几个filter

logging是线程安全的.

最后修改:2021 年 06 月 18 日 10 : 01 AM
如果觉得我的文章对你有用,请随意赞赏