深入理解Python的logging模块:从基础到高级

发布时间:2023年12月24日

在Python编程中,日志记录是一种重要的调试和错误追踪工具。Python的logging模块提供了一种灵活的框架,用于发出日志消息,这些消息可以被发送到各种输出源,如控制台、文件、HTTP GET/POST位置等。本文将深入探讨Python的logging模块,包括其基本用法、高级特性以及如何将其应用到实际项目中。

首先,我们来看一下logging模块的基本用法。logging模块的主要功能是提供一种灵活的框架,用于发出日志消息。这些消息可以被发送到各种输出源,如控制台、文件、HTTP GET/POST位置等。logging模块的核心是Logger类,它提供了应用程序可直接使用的接口。Logger实例化后,可以设置其日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL),并可以通过其方法来发出日志消息。

例如,以下是一个简单的logging模块的使用示例:

import logging

# 创建一个logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
fh.setLevel(logging.DEBUG)

# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)

# 给logger添加handler
logger.addHandler(fh)

# 记录一条日志
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')

在这个示例中,我们首先创建了一个名为’my_logger’的logger,并设置了其日志级别为DEBUG。然后,我们创建了一个handler,用于将日志消息写入到’test.log’文件中。我们还定义了handler的输出格式,包括时间戳、logger的名字、日志级别和日志消息。最后,我们将这个handler添加到logger中,并发出了几条不同级别的日志消息。

除了基本的用法,logging模块还提供了许多高级特性,如过滤器、格式化器、处理器等。过滤器可以根据日志消息的内容或级别来决定是否应该处理这条消息。格式化器可以定义日志消息的输出格式。处理器则负责将日志消息发送到指定的输出源。

例如,以下是如何使用过滤器和格式化器的示例:

import logging

# 创建一个logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
fh.setLevel(logging.DEBUG)

# 创建一个过滤器,只处理INFO级别及以上的日志消息
class MyFilter(logging.Filter):
    def filter(self, record):
        return record.levelno >= logging.INFO
filter = MyFilter()
fh.addFilter(filter)

# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)

# 给logger添加handler
logger.addHandler(fh)

# 记录一条INFO级别的日志消息和一条DEBUG级别的日志消息
logger.info('This is an info message')
logger.debug('This is a debug message')  # 这条消息不会被处理,因为它的级别低于INFO

在这个示例中,我们首先创建了一个名为’my_logger’的logger,并设置了其日志级别为DEBUG。然后,我们创建了一个handler,用于将日志消息写入到’test.log’文件中。我们还创建了一个过滤器,只处理INFO级别及以上的日志消息。最后,我们将这个handler添加到logger中,并发出了两条不同级别的日志消息。由于我们的过滤器只处理INFO级别及以上的日志消息,所以DEBUG级别的日志消息不会被处理。

本专栏封装日志工具类供外部使用:

配置文件

BASE:
  log_level: "debug"
  fh_file_log_level: "debug"  #生产环境换成warning
  log_extension: ".log"
  test:
    url: "http://119.3.246.198:64644"

配置文件调用代码更新

import os
from utils.YamlUtil import YamlReader

current = os.path.abspath(__file__)

BASE_DIR = os.path.dirname(os.path.dirname(current))

_config_path = BASE_DIR + os.sep + "config"
_config_file = _config_path + os.sep + 'conf.yml'

_log_path = BASE_DIR + os.sep + "logs"
def get_config_path():
    return _config_path


def get_config_file():
    return _config_file

def get_log_path():
    return _log_path
class ConfigYaml:
    def __init__(self):
        self.config = YamlReader(get_config_file()).data()

    def get_conf_url(self):
        return self.config['BASE']['test']['url']

    def get_conf_log_level(self):
        #获取日志级别
        return self.config['BASE']['log_level']
    def get_conf_fh_file_log_level(self):
        #获取日志文件级别
        return self.config['BASE']['fh_file_log_level']

    def get_conf_log_extension(self):
        #获取日志文件扩展名
        return self.config['BASE']['log_extension']

日志工具类封装

import logging
import datetime,os
from config import Conf
from config.Conf import ConfigYaml

log_levels = {
    "info": logging.INFO,
    "debug": logging.DEBUG,
    "warning": logging.WARNING,
    "error": logging.ERROR,
}


class Logger:
    def __init__(self, log_file, log_name, log_level, fh_file_log_level):
        self.log_file = log_file
        self.log_name = log_name
        self.log_level = log_level
        self.fh_file_log_level = fh_file_log_level

        self.logger = logging.getLogger(self.log_name)
        self.logger.setLevel(log_levels[self.log_level])
        if not self.logger.handlers:
            fh_stream = logging.StreamHandler()
            fh_stream.setLevel(log_levels[self.log_level])
            formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
            fh_stream.setFormatter(formatter)
            fh_file = logging.FileHandler(self.log_file,encoding='utf-8')  
            #注意,此处不写encoding='utf-8',会出现导出日志中的中文乱码。
            fh_file.setLevel(log_levels[self.fh_file_log_level])
            fh_file.setFormatter(formatter)
            self.logger.addHandler(fh_stream)
            self.logger.addHandler(fh_file)


log_path = Conf.get_log_path()
current_time = datetime.datetime.now().strftime("%Y-%m-%d")
conf_read = ConfigYaml()
log_extention = conf_read.get_conf_log_extension()
log_file =os.path.join(log_path,current_time+log_extention)
log_level = conf_read.get_conf_log_level()
fh_file_log_level = conf_read.get_conf_fh_file_log_level()

def tester_log(log_name = __file__):
    return Logger(log_file=log_file, log_name=log_name, log_level=log_level, fh_file_log_level=fh_file_log_level).logger

这段代码是一个Python日志记录模块的实现。它使用了logging库来创建和管理日志记录器,并提供了自定义的日志级别和格式。

首先,导入了必要的模块:

  • logging:用于创建和管理日志记录器。
  • datetimeos:用于获取当前时间和构建文件路径。
  • ConfConfigYaml:从配置文件中读取配置信息。

然后,定义了一个名为Logger的类,用于创建和管理日志记录器。该类接受以下参数:

  • log_file:日志文件的路径。
  • log_name:日志记录器的名称。
  • log_level:日志记录器的级别。
  • fh_file_log_level:文件处理器的日志级别。

在类的构造函数中,首先根据传入的参数创建一个日志记录器对象,并设置其级别。然后,如果日志记录器没有处理程序(handler),则创建一个流处理器(StreamHandler)和一个文件处理器(FileHandler)。流处理器将日志输出到控制台,而文件处理器将日志写入指定的文件中。

接下来,定义了一些变量和常量:

  • log_path:日志文件所在的目录路径。
  • current_time:当前时间的字符串表示形式,格式为"YYYY-MM-DD"。
  • conf_read:一个ConfigYaml对象,用于读取配置文件中的配置信息。
  • log_extention:日志文件的扩展名。
  • log_file:完整的日志文件路径。
  • log_level:日志记录器的级别。
  • fh_file_log_level:文件处理器的日志级别。

最后,定义了一个名为tester_log的函数,用于创建并返回一个日志记录器对象。该函数接受一个可选参数log_name,默认值为当前文件的名称。

使用这个模块,你可以创建一个日志记录器对象,并通过调用其方法来记录不同级别的日志消息。例如,可以使用logger.info()logger.debug()logger.warning()logger.error()来记录不同级别的日志消息。

工具类应用

在requests封装类中对requests添加日志

import requests
from utils.LogUtil import tester_log
class Request:

    def __init__(self):
        self.log = tester_log()
    def requests_api(self, url, data=None, json=None, headers=None, cookies=None, method="get"):
        if method == "get":
            self.log.debug("发送get请求")
            r = requests.get(url, data=data, json=json, headers=headers, cookies=cookies)
        elif method == "post":
            self.log.debug("发送post请求")
            r = requests.post(url, data=data, json=json, headers=headers, cookies=cookies)

        code = r.status_code
        try:
            body = r.json()
        except Exception as e:
            body = r.text
        res = dict()
        res["code"] = code
        res["body"] = body
        return res
    def get(self, url, **kwargs):
        return self.requests_api(url, method="get", **kwargs)
    def post(self, url, **kwargs):
        return self.requests_api(url, method="post", **kwargs)

调用效果

def login():
    conf_y = ConfigYaml()
    r = Request()
    url_path = conf_y.get_conf_url()

    url = url_path+'/prod-api/login'
    data = {
        "username":"test",
        "password":"49e881218a48a363c35c5215fdc80d3f48d6a17ba0a1f9242c66aebc7ea29c626b26d7ef3bdae00ee9fde85bbf837dcce9f9e4e8f4371d74ff6eaf98ab53d7715996761ef56bff06461e74eb4b3f582949fb3b5281a89fc997a1de35f86a9aad35b87980dcf94e43191293"
    }
    res=r.requests_api(url,json=data,method="post")
    # r = requests.post(url,json=data)
    print(res)
 if __name__ == '__main__':

    login()

在这里插入图片描述在这里插入图片描述

总的来说,Python的logging模块提供了一种灵活的框架,用于发出日志消息。通过使用logging模块,我们可以方便地记录和管理程序的运行情况,从而更好地进行调试和错误追踪。虽然logging模块的基本用法相对简单,但其高级特性却非常强大,可以帮助我们更有效地使用日志记录。因此,对于任何使用Python进行开发的程序员来说,理解和掌握logging模块都是非常必要的。

文章来源:https://blog.csdn.net/python_jeff/article/details/135178382
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。