如何在 Python 中更优雅地记录日志

本文介绍了Python中使用logging模块进行日志记录的最佳实践,包括配置日志记录器、选择适当日志级别、添加上下文信息以及使用日志处理器。同时,推荐了第三方库Loguru,它提供更简洁的语法和额外的功能,如日志格式化、日志文件管理和异常追踪。
摘要由CSDN通过智能技术生成

日志记录是软件开发中不可或缺的一部分,可以帮助开发人员在应用程序运行过程中跟踪问题、调试代码和监控系统状态。在Python中,有多种方式可以记录日志。本篇博客将介绍一些优雅的日志记录最佳实践,帮助您在Python应用程序中实现可维护、可扩展和易于调试的日志记录。

常用的日志记录方式如下:

  1. 使用标准库logging模块:
  • Python的标准库提供了logging模块,它是Python中广泛使用的日志记录工具。以下是一些使用logging模块进行日志记录的最佳实践:

    • 配置日志记录器:在应用程序的入口处配置日志记录器,设置日志级别、输出格式、日志文件等。
    • 使用适当的日志级别:选择适当的日志级别(如DEBUG、INFO、WARNING、ERROR),以便在不同情况下记录不同级别的信息。
    • 利用格式化字符串:使用格式化字符串将日志消息与其他信息(如时间戳、模块名)结合起来,提供更丰富的日志内容。
    • 处理异常信息:使用异常处理机制记录和处理异常信息,包括异常栈轨迹等。
    • 使用日志记录器层次结构:通过设置不同的日志记录器和处理程序,实现更灵活的日志记录和过滤。
  1. 添加上下文信息:

    • 在日志记录中添加上下文信息可以帮助我们更好地理解日志消息的背景和上下文环境。以下是一些添加上下文信息的方法:
      • 记录请求ID或会话ID:对于Web应用程序或分布式系统,记录请求ID或会话ID可以帮助在日志中跟踪特定请求的日志消息。
      • 记录用户信息:在用户登录时,记录用户信息,如用户名、用户ID等,可以帮助在日志中了解不同用户的操作和行为。
      • 记录函数/方法调用信息:在函数或方法的入口和出口处记录日志消息,包括函数名、参数信息和返回值,可以追踪函数调用流程。
  2. 使用日志记录库:
    虽然标准库的logging模块足够强大,但有时可能需要更高级的功能和更丰富的配置选项。以下是一些流行的第三方日志记录库:

    • Loguru:提供简单且易于使用的语法,支持更强大的日志格式化、日志旋转和过滤等功能。
    • structlog:具有可扩展性和可配置性,支持结构化日志记录和日志事件

前面三种为对 logging 模块的封装,最后一种是 Loguru 库的使用。

方式一

#! /usr/bin/python3
# -- coding:UTF-8 --


import os
import time
import logging
from logging.handlers import RotatingFileHandler


def log(name):
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)          # 设置日志级别

    log_path = 'logs'
    if os.path.exists(log_path) and os.path.isdir(log_path):
        pass
    else:
        os.mkdir(log_path)

    path = 'logs/%s' % time.strftime('%Y-%m-%d', time.localtime())      # 日志文件名

    # fh = logging.FileHandler(filename=path)

    fh = RotatingFileHandler(path, maxBytes=1024*1024*100, backupCount=5, encoding='utf-8')
    fh.namer = lambda x: "backup." + x.split(".")[-1]

    fmt = logging.Formatter("%(asctime)s %(levelname)s %(funcName)s:%(lineno)d  %(pathname)s  %(message)s")     # 日志输出格式
    fh.setFormatter(fmt)
    logger.addHandler(fh)

    return logger

使用:

from logHander import log


log.info('%s start run restart_handle' % net_name)

if __name__ == '__main__':
    # 初始化日志模块
    log = log(__name__)         # 不加 __name__ 会导致日志重复写入问题

方式二

# coding: utf-8
import os
import logging


class logger(object):
    """
    处理日志类
    """

    def __init__(self):
        # 配置输出格式
        self.LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s %(funcName)s"
        # 配置输出时间的格式
        self.DATE_FORMAT = '%Y-%m-%d  %H:%M:%S %a '
        # 配置日志输出位置
        import time
        self.path = os.path.split(os.path.realpath(__file__ + "/../../"))[0] + r"/logfile/" + time. \
            strftime("%Y-%m-%d", time.gmtime())
        self.setting()

    def setting(self):
        # 有了filename参数就不会直接输出显示到控制台,而是直接写入文件
        logging.basicConfig(level=logging.DEBUG,
                            format=self.LOG_FORMAT,
                            datefmt=self.DATE_FORMAT,
                            filename=self.path,
                            )

    def debug(self, msg):
        logging.debug(msg)

    def info(self, msg):
        logging.info(msg)

    def warning(self, msg):
        logging.warning(msg)

    def error(self, msg):
        logging.error(msg)

    def critical(self, msg):
        logging.critical(msg)


if __name__ == '__main__':
    logger = logger()

使用:

from LogHandler import logger
logger().info("上传文件格式错误,已成功删除!")

方式三

按照日期进行日志分割:

import logging
import os
import time
from logging.handlers import TimedRotatingFileHandler

loggers = {}
LOG_LEVEL = 'DEBUG'
LOG_PATH = os.path.dirname(__file__) + "/runtime.log"
LOG_FORMAT = "%(asctime)s %(levelname)s %(funcName)s:%(lineno)d  %(pathname)s  %(message)s"


def log(name=None):
    global loggers

    if not name: name = __name__

    if loggers.get(name):
        return loggers.get(name)

    logger = logging.getLogger(name)
    logger.setLevel(LOG_LEVEL)

    file_handler = TimedRotatingFileHandler(LOG_PATH, when='D', backupCount=3, encoding='utf-8')
    file_handler.suffix = "%Y-%m-%d"
    file_handler.setLevel(level=LOG_LEVEL)
    formatter = logging.Formatter(LOG_FORMAT)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    # 保存到全局 loggers
    loggers[name] = logger

    print('>>>', loggers)
    return logger


if __name__ == '__main__':
    while True:
        time.sleep(0.1)
        logger = log()
        logger.info('哈哈哈')

使用:

import log
logger = log()
logger.info('测试连接')

其中 when 是时间,D 为天,即按照天分割,还可以按照周(W)、秒(S)分割。生成的日志文件是:runtime.log.2020-01-19

loguru

更高级的第三方 logging 封装库,支持功能:

  • 按照日期分割日志文件
  • 定期清除等
  • 根据日志等级,定制颜色
  • 更易操作,配置简单
pip3 install loguru

使用

# 输出到终端
from loguru import logger

logger.debug('this is a debug message')

# 输出到文件
logger.add('runtime.log')
logger.debug('this is a debug')

# 定义输出格式
logger.add('runtime.log', format="{time} {level} {message}", filter="my_module", level="INFO")

# 配置日志大小,超过 500 MB,就进行切割,在配置 log 名字时加上了一个 time 占位符,这样在生成时可以自动将时间替换进去,生成一个文件名包含时间的 log 文件。
logger.add('runtime_{time}.log', rotation="500 MB")

# 每天零点创建日志文件
logger.add('runtime_{time}.log', rotation='00:00')

# 一周创建一个
logger.add('runtime_{time}.log', rotation='1 week')

# 保留日志最长时间,保留最新 10 天的日志
logger.add('runtime.log', retention='10 days')

# 日志格式
logger.add('runtime.log', compression='zip')

# 字符串格式化
logger.info('If you are using Python {}, prefer {feature} of course!', 3.6, feature='f-strings')

# traceback 追踪

@logger.catch
def my_function(x, y, z):

add 函数:

def add(
        self,
        sink,
        *,
        level=_defaults.LOGURU_LEVEL,
        format=_defaults.LOGURU_FORMAT,
        filter=_defaults.LOGURU_FILTER,
        colorize=_defaults.LOGURU_COLORIZE,
        serialize=_defaults.LOGURU_SERIALIZE,
        backtrace=_defaults.LOGURU_BACKTRACE,
        diagnose=_defaults.LOGURU_DIAGNOSE,
        enqueue=_defaults.LOGURU_ENQUEUE,
        catch=_defaults.LOGURU_CATCH,
        **kwargs
    ):
    pass

参考文章

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风老魔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值