Python 日志

文章介绍了如何在Python中实现日志功能,包括通过函数调用栈获取信息,改变print函数的输出颜色,以及使用logging库进行日志记录,特别讨论了自定义句柄和默认句柄的使用方法。

欢迎访问我的博客首页


1. 通过函数调用栈实现


  traceback 库记录着 Python 的调用栈。使用 traceback,不仅可以输出日志位置,还可以输出函数调用栈。

import traceback, time, os

def selfLog(*logs, toFile=True):
    tracebackinfo = str(traceback.extract_stack()[-2])
    begin = tracebackinfo.index('file')
    end = tracebackinfo.rindex(' in')
    tracebackinfo = tracebackinfo[begin:end]
    times = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
    if toFile:
        tracebackinfo = 'file ' + os.path.basename(tracebackinfo)
        handle = open('log.txt', 'a')
        handle.write('-- log: %s, %s\n' % (tracebackinfo, times))
        handle.write('    ')
        for log in logs[:-1]:
            handle.write('%s ' % log)
        handle.write('%s\n' % logs[-1])
        handle.close()
        return
    print('-- log: %s, %s' % (tracebackinfo, times))
    print('   ', end='')
    for log in logs[:-1]:
        print('%s' % log, end=' ')
    print(logs[-1])

  假如上面的代码在 selfLog.py 中,调用者代码:

from selfLog import selfLog
selfLog('abcd')
selfLog('abc', 'def')

  可以看出,我们可以像使用 print 语句一样使用 selfLog:输出单个对象、逗号隔开的多个对象、格式化输出对象。

2. 改变 print 函数输出字体的颜色


  python 可以指定 print 字体颜色,代码 selfLog.py:

import config
import time, traceback
from colorama import init

init(autoreset=True)

def getColor(rank):
    manner = 1
    foreground = 30  # [30, 37]
    background = 47  # [40, 47]
    foreground += rank % 8
    background -= rank % 8
    # color = '\033[%d;%d;%dm' % (manner, foreground, background)
    color = '\033[%d;%dm' % (manner, foreground)
    return color

def selfLog(rank, *logs):
    if rank < config.selfLogRank:
        return
    tracebackinfo = str(traceback.extract_stack()[-2])
    begin = tracebackinfo.index('file')
    end = tracebackinfo.rindex(' in')
    tracebackinfo = tracebackinfo[begin:end]
    times = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
    print('-- %s, %s' % (tracebackinfo, times))
    color = getColor(rank)
    for log in logs:
        print('   %s%s' % (color, log), end=' ')
    print()

config.py:

selfLogRank = 0

main.py:

from selfLog import selfLog

if __name__ == '__main__':
    selfLog(1, 'Reading image...', 'info_1', 'info_2')
    selfLog(3, 'Failed to read image!', 'info_1')

  调用时第一个参数 rank 不小于 config.selfLogRank 才会输出。

3. 使用 logging


  logging 是 Python 的日志库,可以很方便地把日志输出到控制台或文件中。

  使用 logging 库,可以输出单个字符串、数字、变量等对象,但不能输出逗号隔开的多个对象。如果想输出多个对象,需要使用格式化输出。

3.1 自定义名称的句柄


  标准库 logging 有一个 logger,该 logger 有一个名称为 root 的默认句柄。句柄负责输出日志,可以通过 logger 添加句柄。

import time
import logging

def init_log():
    # 1.变量。
    date_fmt = '%Y/%m/%d %H:%M:%S'
    masg_fmt = '%(name)s %(pathname)s, line %(lineno)d, %(asctime)s %(levelname)-5.5s: %(message)s'
    path_log = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.log'
    # 2.名称为 root 的默认日志。
    logging.basicConfig(filename='root_' + path_log, filemode='w', format=masg_fmt, datefmt=date_fmt,
                        level=logging.NOTSET)
    # 3.自定义名称的日志。
    logger = logging.getLogger('阿尔法公司')
    # 3.1 控制台。
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.WARNING)
    console_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
    logger.addHandler(console_handler)
    # 3.2 文件。
    file_handler = logging.FileHandler(filename=path_log, mode='a', encoding='utf-8')
    file_handler.setLevel(logging.ERROR)
    file_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
    logger.addHandler(file_handler)
    return logger

if __name__ == '__main__':
    logger = init_log()
    logging.info('logging 信息')
    logging.debug('logging 调试')
    logging.warning('logging 警告')
    logging.error('logging 错误')
    logging.critical('logging 严重错误')
    logger.info('logger 信息')
    logger.debug('logger 调试')
    logger.warning('logger 警告')
    logger.error('logger 错误')
    logger.critical('logger 严重错误')

  basicConfig 用于配置默认名为 root 的句柄。在这里配置文件名时日志将会被输出到文件,否则输出到控制台。无论使用 logging.info/debug/warning/error/critical 还是 logger.info/debug/warning/error/critical 输出,都会按 basicConfig 的配置输出到文件或控制台。

  上面使用 logger 添加的两个自定义句柄,分别把日志输出到控制台和文件。这两个句柄只能响应 logger.info/debug/warning/error/critical,不能响应 logging.info/debug/warning/error/critical。

3.2 使用默认句柄


  虽然自定义句柄可以指定名称,但我们必须获取 logger,才能使用它输出。在其它文件中使用 logger,必须先把它 import 进来。使用默认句柄时,只需在项目任意位置配置 logging,在其它文件只需 import logging 就能直接使用。

import time
import logging

def init_log():
    # 1.变量。
    date_fmt = '%Y/%m/%d %H:%M:%S'
    masg_fmt = '%(name)s %(pathname)s, line %(lineno)d, %(asctime)s %(levelname)-5.5s: %(message)s'
    path_log = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.log'
    # 2.名称为 root 的默认日志。
    # logging.basicConfig(filename='root_' + path_log, filemode='w', format=masg_fmt, datefmt=date_fmt,
    #                     level=logging.NOTSET)
    # 3.自定义名称的日志。
    # logger = logging.getLogger('阿尔法公司')
    # 3.1 控制台。
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.WARNING)
    console_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
    logging.getLogger().addHandler(console_handler)
    # 3.2 文件。
    file_handler = logging.FileHandler(filename=path_log, mode='a', encoding='utf-8')
    file_handler.setLevel(logging.ERROR)
    file_handler.setFormatter(fmt=logging.Formatter(fmt=masg_fmt, datefmt=date_fmt))
    logging.getLogger().addHandler(file_handler)

if __name__ == '__main__':
    init_log()
    logging.info('logging 信息')
    logging.debug('logging 调试')
    logging.warning('logging 警告')
    logging.error('logging 错误')
    logging.critical('logging 严重错误')

4. 参考


  1. print 颜色
  2. logging 级别,博客园,2019。
Python 日志的使用和配置可以从基础配置、高级配置、模块级配置等方面展开。 ### 日志基础与基本配置 Python日志功能可以通过 `logging` 模块实现。基础配置涵盖了日志级别、日志格式等内容。官方文档为 `logging — Python日志记录工具 — Python 3.12.6 文档` [^1]。 ### 模块级别的日志记录器配置 要实现灵活的日志配置策略,让日志记录器根据调用者或运行环境自动调整,可按以下步骤操作: - 定义模块级别的日志记录器:在 Python 文件中定义。 - 检查已有的处理器:在模块级别日志记录器配置时,检查是否已有处理器,即是否已由其他库配置了日志。 - 独立运行时配置默认日志:若没有已有的处理器,则添加默认的日志配置,如输出到控制台 [^2]。 示例代码如下: ```python import logging # 定义模块级别的日志记录器 logger = logging.getLogger(__name__) # 检查是否已有处理器 if not logger.hasHandlers(): # 添加默认的日志配置,输出到控制台 console_handler = logging.StreamHandler() logger.addHandler(console_handler) logger.setLevel(logging.DEBUG) # 示例使用 logger.debug('This is a debug message') ``` ### 高级配置与日志处理器 Python `logging` 模块的高级配置,重点在于使用不同的日志处理器来控制日志的输出位置和方式,同时使用日志格式器让日志信息更直观、易读,还可应用日志过滤器根据自定义规则过滤日志消息,提高日志的可控性和效率 [^3]。 常见的日志处理器如下: - `StreamHandler`:输出日志到流,如控制台。 - `FileHandler`:输出日志到文件。 - `RotatingFileHandler`:按文件大小进行日志分割。 - `TimedRotatingFileHandler`:按时间进行日志分割。 其中,`StreamHandler` 和 `FileHandler` 直接包含在 `logging` 模块中,其他方式包含在 `logging.handlers` 模块中 [^3][^4]。 示例代码使用 `FileHandler`: ```python import logging logger = logging.getLogger(__name__) file_handler = logging.FileHandler('app.log') formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.setLevel(logging.INFO) logger.info('This is an info message') ``` ### 日志配置文件 使用 `logging.config` 模块可以通过配置文件来配置日志。在配置文件中,`stream` 可指定日志输出目标流,如 `sys.stdout`、`sys.stderr` 以及网络流。需要注意的是,`stream` 和 `filename` 不能同时提供,否则会引发 `ValueError` 异常 [^4][^5]。 示例配置文件 `logging.conf`: ```ini [loggers] keys=root [handlers] keys=consoleHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s ``` 使用配置文件的代码: ```python import logging import logging.config logging.config.fileConfig('logging.conf') logger = logging.getLogger() logger.debug('This is a debug message from config file') ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值