万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置

在这里插入图片描述

万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置

前言

Pythonlogging模块中,它不仅提供了基础的日志功能,还拥有一系列高级配置选项来满足复杂应用的日志管理需求。

说到logging 模块的高级配置,必须提及日志分层logging.config配置日志异步操作等关键功能。它们每一项都为开发者提供了强大的调试和监控环境,对于构建可维护和高效的日志系统至关重要。

在接下来的三篇logging高级配置 文章中,我将为读者朋友们介绍 Pythonlogging 模块中的三个高级配置的具体应用:日志分层logging.config 以及 日志异步操作,探讨它们如何优化日志处理流程,并提升应用的整体性能。

本文将聚焦于 logging 模块中的日志文件配置概念,探讨如何通过配置文件灵活定义和调整日志记录器的行为。我们将详细解析如何利用配置文件来设置日志级别、格式、输出目的地等,以构建一个既灵活又可扩展的日志系统。

知识点📖📖

模块释义
loggingPython 的日志记录工具,标准库
logging.config日志文件配置函数

导入模块

import logging
import logging.config


文章脉络:

  • 点击直达:万字长文 - Python 日志记录器logging 百科全书 之 基础配置
  • 点击直达:Python 日志记录器logging 百科全书 之 日志回滚
  • 点击直达:万字长文 - Python 日志记录器logging 百科全书 之 日志过滤
  • 点击直达:万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志分层
  • 点击直达:万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置

理解文件配置 logging.config

logging.config 专门用于配置日志系统。它提供了灵活的配置方式,支持多种配置方法,包括基于文件的配置(如 INIJSONYAML文件等)。

作用和应用场景

logging.config 模块的主要作用是提供一种标准化、灵活的方法来配置 Python 应用程序中的日志记录。通过使用这个模块,开发者可以轻松定义日志的级别、格式、输出目标(如文件、控制台、网络服务等)以及其他高级功能,比如日志轮转和过滤。

它适用于各种规模的 Python 应用程序,从小型脚本到大型系统。在复杂的系统中,logging.config 可以立大功,因为它可以帮助管理和控制多个日志记录器和处理器。


下面是logging.config中常用的方法及其作用:

方法名作用
dictConfig(config_dict)使用字典配置日志记录器。
fileConfig(fname, defaults=None, disable_existing_loggers=True)从配置文件加载日志配置。
listen(port=DEFAULT_LOGGING_CONFIG_PORT)监听远程日志配置的更改。
stopListening()停止监听远程日志配置的更改。

下面只介绍关于 dictConfigfileConfig,因为listen不常用。

⚠️⚠️注意点

建议使用dictConfig,而不是 fileConfig

先说结论,

  • fileConfig 在某些方面(不支持filters,需要额外配置)显得不够灵活,适用于简单的日志配置需求。
  • dictConfig 提供了更高的灵活性和更全面的配置选项,更适合复杂的日志配置需求。

logging.config.dictConfig 较比 logging.config.fileConfig 可谓是遥遥领先!!

  • dictConfig 支持 JSONYAML格式,支持所有日志配置功能,可以更灵活地表示复杂的配置结构,包括过滤器、多个处理器和记录器等。
  • fileConfig 支持 INI 格式的文件,这种格式相对简单,在表达能力上不如 JSONYAML 强。不支持直接在配置文件中定义过滤器,只适合简单的日志配置需求。

logging.config.dictConfig

配置字典,支持字典, JSONYAML格式。

无论使用哪种格式,它们的主要区别在于数据格式和可读性。选择更加符合自己的开发习惯的即可。

JSON:

  • 格式更严格(例如,必须使用双引号,不能有注释)。
  • 在多数编程环境中广泛支持。
  • 可能更适合那些习惯于编程和处理结构化数据的用户。

YAML:

  • 可读性更好,容错性更好(例如,可以使用注释,对引号不敏感)。
  • 适合配置文件,因为它更易于读写,特别是对于较长或复杂的配置。
  • 需要额外的库来解析(Python 中需要安装 PyYAML)。

下面将使用 dict() 字典进行介绍(因为方便),JSONYAML格式自行学习~

方法:

logging.config.dictConfig(config)

基本示例

下面是一个使用 logging.config.dictConfig 的简单示例,这个示例配置了基本的日志记录功能,只包含一个将日志信息输出到控制台的处理器(handler)

  • 定义了一个名为 console 的处理器,它使用 logging.StreamHandler 将日志信息输出到控制台(标准输出)。
  • 设置了一个简单的日志格式,包括时间戳、日志级别和日志消息。
  • 配置了根日志记录器,将其日志级别设置为 INFO,这意味着只有 INFO 级别及以上(如 WARNING, ERROR, CRITICAL)的日志会被处理。
  • 使用 dictConfig 函数应用这个配置。

示例代码

import logging
from logging.config import dictConfig

# 日志配置字典
log_config = {
    'version': 1,
    'handlers': {
        'console': {  # 定义一个名为 "console" 的处理器
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'formatter': 'simple',
            'stream': 'ext://sys.stdout'  # 使用标准输出
        }
    },
    'formatters': {
        'simple': {  # 定义一个简单的格式器
            'format': '%(asctime)s - %(levelname)s - %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        }
    },
    'root': {  # 配置根日志记录器
        'level': 'INFO',
        'handlers': ['console']
    }
}

# 应用日志配置
dictConfig(log_config)

# 获取日志记录器
logger = logging.getLogger()

# 记录一些日志
logger.info("这是一个信息级别的日志")
logger.warning("这是一个警告级别的日志")

参数详解

下面的每一个参数都不是独立的,最终它们结合起来,便是一份完整的logging.config.dictConfig 的日志文件配置。

以下是 logging.config.dictConfig 方法中各个参数的整理:

参数名类型必需描述
versionint必需唯一一个必选项,必须设置为 1,表示配置字典的版本。
formattersdict可选定义日志的格式,键是格式器的名称,值是格式器的配置字典。
filtersdict可选定义过滤器,用于过滤日志记录。键是过滤器的名称,值是过滤器的配置字典。
handlersdict可选定义处理程序,决定日志如何输出。键是处理程序的名称,值是处理程序的配置字典。
loggersdict可选定义记录器,用于生成日志记录。键是记录器的名称,值是记录器的配置字典。
rootdict可选定义根记录器的配置,包含日志级别和处理程序列表。
incrementalbool可选默认False,用于指定是否应该增量地应用配置。
disable_existing_loggersbool可选默认True,用于指定是否禁用所有已存在的记录器。

1. version

应设为代表架构版本的整数值。 目前唯一有效的值是 1。

  • 唯一一个必选项,必须设置为 1,表示配置字典的版本。
logg_config = {
    'version': 1
}
2. formatters

对应的值是一个字典,其中每个键是一个格式器 ID 而每个值则是一个描述如何配置相应 Formatter 实例的字典

以下是 formatters 字典中全部的参数:

  • format: 定义日志消息的格式。这是一个字符串,可以包含各种日志记录属性的占位符,如 %(levelname)s, %(message)s, %(asctime)s 等。
  • datefmt: 定义日期和时间的格式。这是一个字符串,用于格式化日志记录中的时间戳,例如 %Y-%m-%d %H:%M:%S
  • style:指定format字符串的格式化风格。Python标准库的日志模块支持三种风格:‘%’(默认)、‘{‘和’$’。
  • validate:布尔值,指定是否对 format 字符串进行验证。默认为 True
  • class: 指定自定义的格式器类。这是可选的,仅当需要使用不是标准的logging.Formatter的格式器时使用。

示例代码:

  • 包含两个格式器,simplecomplex,分别指定了 formatstyle
log_config = {
    'version': 1,
    'formatters': {
        'simple': {
            'format': '%(levelname)s - %(asctime)s - %(name)s - %(message)s',
            'style ': '%',  # 默认值
            'datefmt': '%Y-%m-%d %H:%M:%S',
        },
        'complex': {
            'format': '{levelname} - {asctime} - {name} - {message}',
            'style': '{'
        }
    }
}
3. filters

这里可以结合这篇文章食用:万字长文 - Python 日志记录器logging 百科全书 之 日志过滤

对应的值将是一个字典,其中每个键是一个过滤器 ID 而每个值则是一个描述如何配置相应 Filter 实例的字典。

配置日志记录的过滤器,一般过滤器需要绑定到处理器中,所以需要结合下面的handlees 使用。

  • name:字符串,过滤器名称
  • ():字符串,过滤器的类命,用于指定日志系统使用哪个过滤器,如logging.Filter,也可以是自定义过滤器类的路径。
  • param:可选,如果过滤类有需要,则可传递。

无param参数:

  • 自定义过滤器CommonFilterconsole_filter指定的过滤器类路径为 CommonFilter__main__需要更改为自定义过滤器的路径
import logging


# 自定义过滤器 - 控制台使用
class CommonFilter(logging.Filter):
    def filter(self, record):
        # 过滤掉包含敏感信息的日志
        return "敏感信息" not in record.getMessage()

    
log_config = {
    'version': 1,
    'filters': {
        'console_filter': {
            '()': '__main__.CommonFilter'
        }
    }
}

有param参数:

  • 携带参数
import logging


# 自定义过滤器 - 控制台使用
class CommonFilter(logging.Filter):
    def __init__(self, param1=None, param2=None):
        super().__init__()
        self.param1 = param1
        self.param2 = param2

    def filter(self, record):
        # 过滤掉包含敏感信息的日志
        return "敏感信息" not in record.getMessage()


log_config = {
    'version': 1,
    'filters': {
        'console_filter': {
            '()': '__main__.CommonFilter',
            'param1': "value1",
            'param2': "value2"
        }
    }
}

4. handlers

对应的值将是一个字典,其中每个键是一个处理器 ID 而每个值则是一个描述如何配置相应 Handler 实例的字典。

参数名类型必需描述
classstring必需处理器的类名,例如 logging.StreamHandlerlogging.handlers.FileHandler
levelstring可选处理器的日志级别,例如 ‘DEBUG’、‘INFO’、‘WARNING’、‘ERROR’ 或 ‘CRITICAL’。默认为 ‘NOTSET’
formatterstring可选处理器使用的格式化器的名称,通常与 formatters 字典中的一个格式化器名称对应
filenamestring可选只有在处理器类型为 FileHandler 时才适用。指定写入日志的文件名
modestring可选只有在处理器类型为 FileHandler 时才适用。指定文件的打开模式,默认为 a
encodingstring可选只有在处理器类型为 FileHandler 时才适用。指定文件的编码,默认为 None
delaybool可选只有在处理器类型为 FileHandler 时才适用。指定文件创建的时机
streamstring可选只有在处理器类型为 StreamHandler 时才适用。指定输出流,例如 ext://sys.stdout,默认为sys.stderr
filterslist可选指定一个或多个过滤器的名称列表,用于过滤要发送到处理器的日志消息

代码

一般来说,需要将日志处理器(Handler)添加到日志记录器(Logger)中才能使用。

  • 包含两个处理器consolefile,分别设置了classformatterlevel,等,注意 FileHandlerStreamHandler 所接受的参数有所不同!
log_config = {
    'version': 1,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'simple',
            'level': 'DEBUG',
            'filters': ['common_filter'],
            'stream': 'ext://sys.stdin',
        },
        'file': {
            'class': 'logging.FileHandler',
            'formatter': 'complex',
            'level': 'DEBUG',
            'filters': ['common_filter'],
            'filename': 'app.log',
            'mode': 'a',
            'encoding': 'utf-8',
        }
    }
}
5. loggers

其中每个键是一个日志记录器名称,而每个值则是一个描述如何配置相应 Logger 实例的字典。每个日志记录器可以接受以下参数:

  • level (可选)。字符串,日志记录器的级别。
  • propagate (可选)。 布尔值,日志记录器的传播设置。
  • filters (可选)。 由日志记录器对应过滤器的 ID 组成的列表。
  • handlers (可选)。 由日志记录器对应处理器的 ID 组成的列表。

代码

  • 配置这里就不解释了,在前的文章都有介绍~
log_config = {
    'version': 1,
    'loggers': {
        'common_logger': {
            'level': 'DEBUG',
            'filters': ['common_filter'],
            'handlers': ['console'],
        },
        'common_logger.file': {
            'level': 'WARNING',
            'propagate': False,
            'filters': ['common_filter'],
            'handlers': ['console', 'file'],
        }
    }
}

6. root

根日志记录器对应的配置。 配置的处理方式将与所有日志记录器一致,除了 propagate 设置将不可用之外。

一般情况下,不需要显式设置根日志记录器(root logger),我们只需要设置自定义的子记录器Logger即可。

如果我们的应用可能会使用默认的日志记录器(即直接通过 logging.getLogger() 获取的记录器),那么配置根日志记录器是有意义的,因为它定义了这些记录器的默认行为。根记录器的目的是提供一个全局的、基本的日志配置,为了保持简单和明确,通常不会涉及过于复杂的参数设置。

置根日志记录器的 root 部分包含以下参数:

  1. level (可选):设置根日志记录器的日志级别。

  2. handlers(可选):指定一个处理器列表,这些处理器会被附加到根日志记录器。这些处理器控制日志信息的输出方式和位置。

  3. propagate (可选):不常用于 root, 对于非根日志记录器,这个布尔值指定日志信息是否向上传播到父记录器。但对于根记录器本身,这个设置通常不适用或忽略,因为根记录器是层级的顶端。

示例代码

  • 指定跟日志记录器的levelhandlersfilters
log_config = {
    'version': 1,
    'root': {
        'level': 'DEBUG',
        'handlers': ['console', 'file'],
        'filters': ['common_filter']
    }
}
7. incremental

配置是否要被解读为在现有配置上新增。 该值默认为 False.

  • incremental=True 时,这意味着正在进行增量更新。只有在配置字典中显式修改的部分会被更新,而其他的配置将保持不变;

  • 当不使用 incremental=True,并且提供了一个新的配置字典给 dictConfig,那么整个日志配置将被这个新的配置字典替换(被覆盖)。

使用 incremental=True 的主要作用是允许对日志配置进行部分更新,!!!值得注意的是

  • 系统将完全忽略任何 formattersfilters 条目,并仅会处理 handlers 条目中的 level 设置,以及 loggersroot 条目中的 levelpropagate 设置。

应用场景

假设小菜维护一个在生产环境中运行的Web服务,该服务正常情况下仅记录 INFO 级别以上的日志。但是,当遇到某些特定问题时,小菜可能需要临时增加日志的详细程度,以便能更好地分析和调试问题。例如,小菜可能想要将某个模块的日志级别从 INFO 提升到 DEBUG 来获得更多信息。

示例代码

在不重写整个日志配置的情况下动态调整日志配置,仅更新了日志级别。这对于生产环境中的问题诊断和调试会有用。

  1. 初始日志配置:最初,小菜的日志配置设置为仅记录 INFO 级别及以上的日志。
  2. 检测到特定问题:当系统检测到特定问题(可能是通过错误计数、特定类型的请求或其他指标)时,小菜想动态调整相关模块的日志级别以捕获更详细的信息。
  3. 应用增量更新:此时,小菜可以使用 incremental=True 来更新特定日志记录器的配置,而不影响其他配置。
import logging
from logging.config import dictConfig
import time

# 初始配置,记录 INFO 级别及以上的日志
initial_config = {
    'version': 1,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG'
        }
    },
    'root': {
        'level': 'INFO',
        'handlers': ['console'],
    }
}
dictConfig(initial_config)

logger = logging.getLogger()

# 模拟应用程序运行
for i in range(5):
    if i == 3:
        # 当出现特定条件时,提升日志级别到 DEBUG
        incremental_config = {
            'version': 1,
            'incremental': True,
            'root': {
                'level': 'DEBUG'
            }
        }
        dictConfig(incremental_config)
        logger.debug("日志级别已提升至 DEBUG")

    logger.debug(f"详细的调试信息 {i}")
    logger.info(f"一般的信息 {i}")
    time.sleep(1)

8. disable_existing_loggers

是否要禁用任何现有的非根日志记录器。形参默认为 True。这个选项的作用主要是控制新的日志配置是否会影响到现有的日志记录器。

  • disable_existing_loggers 设置为 True 时,它的作用是关闭(禁用)之前创建的所有日志记录器,除非它们在新的日志配置中明确定义。
  • disable_existing_loggers 设置为 False 时,它的作用是忽略之前创建的日志记录器,不会关闭它们,除非在新的日志配置中明确定义。

如果希望保留现有记录器的配置,并且不希望新的配置覆盖它们,通常会将 disable_existing_loggers 设置为 False

如果想要在新的配置中重新定义所有记录器的配置,则不必理会,因为 disable_existing_loggers 默认为 True

log_config = {
    'version': 1,
    'disable_existing_loggers': False
}

🧐使用JSON

log_config.json

{
    "version": 1,
    "formatters": {
        "simple": {
            "format": "%(asctime)s - %(levelname)s - %(name)s - %(message)s"
        }
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "simple",
            "level": "DEBUG"
        }
    },
    "root": {
        "level": "INFO",
        "handlers": ["console"]
    }
}

代码

import logging
import logging.config
import json

# 从 JSON 文件加载配置
with open('log_config.json', 'r') as file:
    config = json.load(file)
    logging.config.dictConfig(config)

# 获取日志记录器
logger = logging.getLogger()

🎈使用YAML

整体来看,确实需要比 YAML 确实会比 JSON 更加简单和容易阅读。

配置与上面的 使用 JSON 同款。

log_config.yaml

version: 1	# 如需要则添加注释
formatters:
  simple:
    format: "%(asctime)s - %(levelname)s - %(name)s - %(message)s"
handlers:
  console:
    class: logging.StreamHandler
    formatter: simple
    level: DEBUG
root:
  level: INFO
  handlers: [console]

首先需要安装 PyYAML

pip install pyyaml

代码

import logging
import logging.config
import yaml

# 从 YAML 文件加载配置
with open('log_config.yaml', 'r') as file:
    config = yaml.safe_load(file)
    logging.config.dictConfig(config)

# 获取日志记录器
logger = logging.getLogger()

logging.config.fileConfig

配置文件,支持INI 文件

⚠️⚠️⚠️不支持过滤器

⚠️⚠️⚠️不支持过滤器

⚠️⚠️⚠️不支持过滤器

方法:

logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=None)

这里只做基本介绍,不深入。因为它不够友好。


参数详解

以下是 logging.config.fileConfig 函数的参数整理:

参数名称类型必需描述
fnamestr必须配置文件的路径。这个文件包含了日志配置的信息。
defaultsdict可选配置文件中使用的变量的默认值。
disable_existing_loggersbool可选决定是否禁用在调用 fileConfig 之前已经存在的日志记录器。默认为 True
encodingstr可选用于指定配置文件的编码方式。

必需的字段

logging.config.fileConfig 中使用的 INI 文件中,有几个必需的字段来确保至少基本的日志配置能够工作。以下是一个最简单的示例,其中包含了必需的基础字段。

  • [loggers]:至少需要列出需要配置的日志记录器。
  • [handlers]:至少需要定义一个处理器。
  • [formatters]:至少需要定义一个格式器。
  • [logger_<logger_name>]:为每个需要配置的记录器定义具体配置。
  • [handler_<handler_name>]:为每个处理器定义具体配置。
  • [formatter_<formatter_name>]:为每个格式器定义具体配置。

基础示例 INI 文件

log_config.ini

  • 这个配置定义了一个根日志记录器 root,它的日志级别为 INFO
  • 有一个处理器 consoleHandler,它将日志输出到标准输出(控制台),同时也设置为 INFO 级别。
  • 有一个格式器 simpleFormatter,它定义了日志的显示格式。
[loggers]
keys=root

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=INFO
handlers=consoleHandler

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

[formatter_simpleFormatter]
format=%(asctime)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S

示例代码

代码通过 fileConfig 加载 INI 文件中的配置,然后使用 getLogger 创建一个日志记录器。此记录器将根据 INI 文件中定义的配置处理日志消息。

import logging
import logging.config

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

# 创建日志记录器
logger = logging.getLogger()

# 记录消息
logger.info("这是一个信息级别的日志")
logger.debug("这条调试消息不会显示,因为日志级别设置为 INFO")

特别处理:添加filters

import logging
import logging.config


# 自定义过滤器
class CommonFilter(logging.Filter):
    def filter(self, record):
        # 过滤掉包含敏感信息的日志
        return "敏感信息" not in record.getMessage()
    

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

# 创建日志记录器
logger = logging.getLogger()
# 添加过滤器
logger.addFilter(CommonFilter())

# 记录消息
logger.info("这是一个信息级别的日志")
logger.debug("这条调试消息不会显示,因为日志级别设置为 INFO")

实际案例

以下的代码来自

  • 万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志分层

里的 示例代码,将他修改成本文所介绍的 logging.config 高级配置

import logging
import logging.config
import requests
import sys


class RemoteLogHandler(logging.Handler):
    """自定义远程处理器"""

    def __init__(self, remote_url):
        super().__init__()
        self.remote_url = remote_url
        self.error_logger = logging.getLogger('error')
        # self.setFormatter(formatter)

    def emit(self, record):
        # 发送日志记录到远程服务器
        log_entry = self.format(record)  # 格式化日志记录
        try:
            response = requests.post(self.remote_url, data=log_entry)
            response.raise_for_status()
        except Exception as e:
            record.msg = f"Original message: {record.msg}, Failed to send log to remote: {str(e)}"
            print('error_logger 等级是 ', self.error_logger.level)
            self.error_logger.handle(record)


log_config = {
    'version': 1,
    'formatters': {
        'simple': {
            'format': '%(levelname)-7s - %(asctime)s - %(name)s - %(message)s'
        }
    },
    'handlers': {
        'file_global': {
            '()': 'logging.FileHandler',
            'filename': 'ecommerce_global.log',
            'level': 'DEBUG',
            'formatter': 'simple',
            'delay': True
        },
        'file_error': {
            '()': 'logging.FileHandler',
            'filename': 'error.log',
            'level': 'ERROR',
            'formatter': 'simple',
            'delay': True
        },
        'file_order': {
            '()': 'logging.FileHandler',
            'filename': 'orders.log',
            'level': 'WARNING',
            'formatter': 'simple',
            'delay': True
        },
        'file_payment': {
            '()': 'logging.FileHandler',
            'filename': 'payments.log',
            'level': 'ERROR',
            'formatter': 'simple',
            'delay': True
        },
        'stream': {
            '()': 'logging.StreamHandler',
            'stream': 'ext://sys.stdout',
            'formatter': 'simple'
        },
        'remote': {
            '()': '__main__.RemoteLogHandler',
            'remote_url': 'http://127.0.0.1:5000/submit_log',
        }
    },
    'loggers': {
        'ecommerce': {
            'handlers': ['file_global', 'stream'],
            'level': 'DEBUG'
        },
        'ecommerce.orders': {
            'handlers': ['file_order', 'remote'],
            'level': 'INFO',
            'propagate': False
        },
        'ecommerce.payments': {
            'handlers': ['file_payment', 'remote'],
            'level': 'WARNING',
            'propagate': False
        },
        'error': {
            'handlers': ['file_error'],
            'level': 'WARNING',
        }
    }
}

if __name__ == '__main__':
    logging.config.dictConfig(log_config)

    # 使用日志记录器
    global_logger = logging.getLogger('ecommerce')
    order_logger = logging.getLogger('ecommerce.orders')
    payment_logger = logging.getLogger('ecommerce.payments')
    # 日志测试
    global_logger.info('Global logger configured')
    order_logger.warning('Order logger configured')
    payment_logger.error('Payment logger configured')

总结🎈🎈

本文全面介绍了Pythonlogging模块的高级文件配置技巧,重点讨论了dictConfigfileConfig两种配置方法。

通过dictConfig,开发者可以灵活地使用字典、JSONYAML 格式来设置日志级别、格式和处理器,

fileConfig则提供了对INI格式配置文件的支持。尽管fileConfig在功能上有所限制,但它仍适用于简单的配置需求。

文章通过实例和注意事项,指导读者如何选择和应用这些配置方法,以优化日志处理流程并提升应用性能。

总的来说,这篇文章可以帮助读者朋友们深入了解如何使用 logging.config 进行日志文件配置。进而帮助读者建立一个高效、可维护的日志系统。

后话

本次分享到此结束,

see you~~✨✨

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/186407.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

模拟退火算法应用——求解函数的最小值

仅作自己学习使用 一、问题 需求&#xff1a; 计算函数 的极小值&#xff0c;其中个体x的维数n10&#xff0c;即x(x1,x2,…,x10)&#xff0c;其中每一个分量xi均需在[-20,20]内。因此可以知道&#xff0c;这个函数只有一个极小值点x (0,0,…,0)&#xff0c;且其极小值是0&…

STM32_7(ADC)

一、ADC ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁12位逐次逼近型ADC&#xff0c;1us转换时间输入电压范围&#xff1a;0~3.3V&#xff0c;…

蓝桥杯物联网竞赛_STM32L071_4_按键控制

原理图&#xff1a; 当按键S1按下PC14接GND&#xff0c;为低电平 CubMX配置: Keil配置&#xff1a; main函数&#xff1a; while (1){/* USER CODE END WHILE */OLED_ShowString(32, 0, "hello", 16);if(Function_KEY_S1Check() 1){ OLED_ShowString(16, 2, &quo…

HTTP/2:多路复用、服务器推送和首部压缩的革命

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

ES之x-pack-core-7.14.2许可证修改为白金版

X-Pack是什么 X-pack是elasticsearch的一个扩展包&#xff0c;将安全&#xff0c;警告&#xff0c;监视&#xff0c;图形和报告功能捆绑在一个易于安装的软件包中&#xff0c;虽然x-pack被设计为一个无缝的工作&#xff0c;但是你可以轻松的启用或者关闭一些功能。 主要分一下步…

基于Eclipse+Tomcat+Mysql开发的研究生信息教务系统

基于Eclipse的研究生教务系统 项目介绍&#x1f481;&#x1f3fb; 该研究生教务系统是一款集学生信息管理、学院信息维护、学生类别信息维护、专业信息维护、教师信息导入、课程信息导入及老师信息导入等功能于一体的教育管理软件。它以高效、便捷、准确的方式处理教务管理工作…

百度 文心一言 sdk 试用

JMaven Central: com.baidu.aip:java-sdk (sonatype.com) Java sdk地址如上&#xff1a; 文心一言开发者 文心一言 (baidu.com) ERNIE Bot SDK https://yiyan.baidu.com/developer/doc#Fllzznonw ERNIE Bot SDK提供便捷易用的接口&#xff0c;可以调用文心一言的能力&#…

DevEco Studio安装

HUAWEI DevEco Studio For OpenHarmony&#xff08;以下简称DevEco Studio&#xff09;是基于IntelliJ IDEA Community开源版本打造&#xff0c;面向OpenHarmony全场景多设备的一站式集成开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供工程模板创建、开发、编译…

Markdown如何自定义字体样式:字体颜色、背景、斜体、粗体

Markdown如何自定义字体样式&#xff1a;字体颜色、背景、斜体、粗体 文章目录 Markdown如何自定义字体样式&#xff1a;字体颜色、背景、斜体、粗体前言一、字体大小二、字体颜色1. 英文字母2. 十六进制颜色值 三、字体背景色三、字体类型四、字体加粗五、字体斜体六、混合使用…

Mac Ubuntu双系统解决WiFi和WiFi 5G网络不可用问题

文章目录 设备信息1. Ubuntu WiFi不可用解决方式查看Mac的网卡型号根据网卡型号搜索获取到的解决方法查看WiFi名字问题参考链接 2. 解决WiFi重启后失效问题打开终端创建.sh脚本文件编辑脚本文件复制粘贴脚本修改脚本权限创建并编辑systemd service文件复制粘贴下文到systemd se…

Feign接口请求返回异常 no suitable HttpMessageConvert found for response type

问题场景&#xff1a; 后端调用feign接口请求, 接口返回异常, no suitable HttpMessageConvert found for response type 问题描述 报错异常如下&#xff1a; //根据图片特征 去查询人员信息ResultVo<List> personVos ipbdFaceLibPersonApi.queryFacePersonByFeatur…

Git 与 Maven:企业级版本管理与版本控制规范设计

一、背景 当今&#xff0c;许多开发人员熟悉 GitFlow 工作流程&#xff0c;但往往忽略了 GitFlow 如何与 Maven 版本控制结合&#xff0c;尤其是在管理 snapshot 和 release 版本时的最佳实践。本文旨在整合 GitFlow 工作流程与 Maven 版本管理&#xff0c;提出一个统一的企业…

Python 在 JMeter 中如何使用?

要在JMeter中使用Python&#xff0c;需要使用JSR223 Sampler元素来执行Python脚本。使用JSR223 Sampler执行Python脚本时&#xff0c;需要确保已在JMeter中配置了Python解释器&#xff0c;并设置了正确的环境路径。 1、确保JMeter已安装Python解释器&#xff0c;并将解释器的路…

CSS3新特性(2-1)

CSS3新特性 前言border&#xff1a;radius标签属性选择器box-sizing透明度 前言 本文主要讲解CSS3有哪些新的特性和内容&#xff0c;那么好&#xff0c;本文正式开始. border&#xff1a;radius 新增了圆角边框概念&#xff0c;可以通过具体数值或者百分比&#xff0c;来让边…

Java特殊文件

Properties 读取数据 package com.itheima.d1;import java.io.FileNotFoundException; import java.io.FileReader; import java.nio.charset.StandardCharsets; import java.util.Properties; import java.util.Set;public class Test1 {public static void main(String[] arg…

mysql 变量和配置详解

MySQL 中还有一些特殊的全局变量&#xff0c;如 log_bin、tmpdir、version、datadir&#xff0c;在 MySQL 服务实例运行期间它们的值不能动态修改&#xff0c;也就是不能使用 SET 命令进行重新设置&#xff0c;这种变量称为静态变量。数据库管理员可以使用前面提到的修改源代码…

LV.12 D19 ADC实验 学习笔记

一、ADC简介 1.1 ADC ADC(Analog to Digital Converter)即模数转换器&#xff0c;指一个能将模拟信号转化为数字信号的电子元件 1.2 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示&#xff0c;当最大输入电压一定时&#xff0c;位数越高&#xff0c…

探索网络模型与协议:从OSI到HTTPs的原理解析

一、OSI网络模型 OSI&#xff08;Open Systems Interconnection&#xff09;七层网络参考模型和TCP/IP四层模型都是用于理解和设计计算机网络的框架&#xff0c;但它们之间存在一些差异。 1、七层 vs 四层 OSI七层网络参考模型&#xff1a; 物理层&#xff08;Physical Laye…

京东数据分析:2023年10月京东彩妆销售大数据采集

鲸参谋监测的京东平台10月份彩妆市场销售数据已出炉&#xff01; 鲸参谋数据显示&#xff0c;今年10月份&#xff0c;京东平台上彩妆市场的销量将近430万&#xff0c;环比增长约21%&#xff0c;同比下滑约3%&#xff1b;销售额将近5.8亿&#xff0c;环比增长约7%&#xff0c;同…

【数据库篇】关系模式的表示——(1)问题的提出

1、关系模式的表示 R&#xff1a;表示关系的名字比如&#xff1a;sc选课表&#xff0c;student学生表。 U&#xff1a;表示一个关系模式的所有属性&#xff0c;比如student表&#xff1a;U&#xff08;sno&#xff0c;sname&#xff0c;sage&#xff0c;ssex&#xff09;。 …