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

万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置
前言
在 Python 的logging模块中,它不仅提供了基础的日志功能,还拥有一系列高级配置选项来满足复杂应用的日志管理需求。
说到logging 模块的高级配置,必须提及日志分层、logging.config配置、日志异步操作等关键功能。它们每一项都为开发者提供了强大的调试和监控环境,对于构建可维护和高效的日志系统至关重要。
在接下来的三篇logging高级配置 文章中,我将为读者朋友们介绍 Python 的 logging 模块中的三个高级配置的具体应用:日志分层、logging.config 以及 日志异步操作,探讨它们如何优化日志处理流程,并提升应用的整体性能。
本文将聚焦于 logging 模块中的日志文件配置概念,探讨如何通过配置文件灵活定义和调整日志记录器的行为。我们将详细解析如何利用配置文件来设置日志级别、格式、输出目的地等,以构建一个既灵活又可扩展的日志系统。
知识点📖📖
| 模块 | 释义 |
|---|---|
logging | Python 的日志记录工具,标准库 |
logging.config | 日志文件配置函数 |
导入模块
import logging
import logging.config
文章脉络:
- 点击直达:万字长文 - Python 日志记录器logging 百科全书 之 基础配置
- 点击直达:Python 日志记录器logging 百科全书 之 日志回滚
- 点击直达:万字长文 - Python 日志记录器logging 百科全书 之 日志过滤
- 点击直达:万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志分层
- 点击直达:万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置
理解文件配置 logging.config
logging.config专门用于配置日志系统。它提供了灵活的配置方式,支持多种配置方法,包括基于文件的配置(如INI、JSON和YAML文件等)。
作用和应用场景
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() | 停止监听远程日志配置的更改。 |
下面只介绍关于 dictConfig 和 fileConfig,因为listen不常用。
⚠️⚠️注意点
建议使用
dictConfig,而不是fileConfig。
先说结论,
fileConfig在某些方面(不支持filters,需要额外配置)显得不够灵活,适用于简单的日志配置需求。dictConfig提供了更高的灵活性和更全面的配置选项,更适合复杂的日志配置需求。
logging.config.dictConfig 较比 logging.config.fileConfig 可谓是遥遥领先!!
dictConfig支持JSON和YAML格式,支持所有日志配置功能,可以更灵活地表示复杂的配置结构,包括过滤器、多个处理器和记录器等。fileConfig支持INI格式的文件,这种格式相对简单,在表达能力上不如JSON或YAML强。不支持直接在配置文件中定义过滤器,只适合简单的日志配置需求。
logging.config.dictConfig
配置字典,支持字典,
JSON和YAML格式。
无论使用哪种格式,它们的主要区别在于数据格式和可读性。选择更加符合自己的开发习惯的即可。
JSON:
- 格式更严格(例如,必须使用双引号,不能有注释)。
- 在多数编程环境中广泛支持。
- 可能更适合那些习惯于编程和处理结构化数据的用户。
YAML:
- 可读性更好,容错性更好(例如,可以使用注释,对引号不敏感)。
- 适合配置文件,因为它更易于读写,特别是对于较长或复杂的配置。
- 需要额外的库来解析(
Python中需要安装PyYAML)。
下面将使用 dict() 字典进行介绍(因为方便),JSON 和YAML格式自行学习~
方法:
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 方法中各个参数的整理:
| 参数名 | 类型 | 必需 | 描述 |
|---|---|---|---|
version | int | 必需 | 唯一一个必选项,必须设置为 1,表示配置字典的版本。 |
formatters | dict | 可选 | 定义日志的格式,键是格式器的名称,值是格式器的配置字典。 |
filters | dict | 可选 | 定义过滤器,用于过滤日志记录。键是过滤器的名称,值是过滤器的配置字典。 |
handlers | dict | 可选 | 定义处理程序,决定日志如何输出。键是处理程序的名称,值是处理程序的配置字典。 |
loggers | dict | 可选 | 定义记录器,用于生成日志记录。键是记录器的名称,值是记录器的配置字典。 |
root | dict | 可选 | 定义根记录器的配置,包含日志级别和处理程序列表。 |
incremental | bool | 可选 | 默认False,用于指定是否应该增量地应用配置。 |
disable_existing_loggers | bool | 可选 | 默认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的格式器时使用。
示例代码:
- 包含两个格式器,
simple和complex,分别指定了format、style等
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参数:
- 自定义过滤器
CommonFilter,console_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 = param1self.param2 = param2def 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 实例的字典。
| 参数名 | 类型 | 必需 | 描述 |
|---|---|---|---|
class | string | 必需 | 处理器的类名,例如 logging.StreamHandler 或 logging.handlers.FileHandler |
level | string | 可选 | 处理器的日志级别,例如 ‘DEBUG’、‘INFO’、‘WARNING’、‘ERROR’ 或 ‘CRITICAL’。默认为 ‘NOTSET’ |
formatter | string | 可选 | 处理器使用的格式化器的名称,通常与 formatters 字典中的一个格式化器名称对应 |
filename | string | 可选 | 只有在处理器类型为 FileHandler 时才适用。指定写入日志的文件名 |
mode | string | 可选 | 只有在处理器类型为 FileHandler 时才适用。指定文件的打开模式,默认为 a |
encoding | string | 可选 | 只有在处理器类型为 FileHandler 时才适用。指定文件的编码,默认为 None |
delay | bool | 可选 | 只有在处理器类型为 FileHandler 时才适用。指定文件创建的时机 |
stream | string | 可选 | 只有在处理器类型为 StreamHandler 时才适用。指定输出流,例如 ext://sys.stdout,默认为sys.stderr |
filters | list | 可选 | 指定一个或多个过滤器的名称列表,用于过滤要发送到处理器的日志消息 |
代码
一般来说,需要将日志处理器(
Handler)添加到日志记录器(Logger)中才能使用。
- 包含两个处理器
console和file,分别设置了class,formatter,level,等,注意FileHandler和StreamHandler所接受的参数有所不同!
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 部分包含以下参数:
-
level(可选):设置根日志记录器的日志级别。 -
handlers(可选):指定一个处理器列表,这些处理器会被附加到根日志记录器。这些处理器控制日志信息的输出方式和位置。 -
propagate(可选):不常用于root, 对于非根日志记录器,这个布尔值指定日志信息是否向上传播到父记录器。但对于根记录器本身,这个设置通常不适用或忽略,因为根记录器是层级的顶端。
示例代码
- 指定跟日志记录器的
level,handlers,filters等
log_config = {'version': 1,'root': {'level': 'DEBUG','handlers': ['console', 'file'],'filters': ['common_filter']}
}
7. incremental
配置是否要被解读为在现有配置上新增。 该值默认为
False.
-
当
incremental=True时,这意味着正在进行增量更新。只有在配置字典中显式修改的部分会被更新,而其他的配置将保持不变; -
当不使用
incremental=True,并且提供了一个新的配置字典给dictConfig,那么整个日志配置将被这个新的配置字典替换(被覆盖)。
使用 incremental=True 的主要作用是允许对日志配置进行部分更新,!!!值得注意的是
- 系统将完全忽略任何
formatters和filters条目,并仅会处理handlers条目中的level设置,以及loggers和root条目中的level和propagate设置。
应用场景
假设小菜维护一个在生产环境中运行的Web服务,该服务正常情况下仅记录 INFO 级别以上的日志。但是,当遇到某些特定问题时,小菜可能需要临时增加日志的详细程度,以便能更好地分析和调试问题。例如,小菜可能想要将某个模块的日志级别从 INFO 提升到 DEBUG 来获得更多信息。
示例代码
在不重写整个日志配置的情况下动态调整日志配置,仅更新了日志级别。这对于生产环境中的问题诊断和调试会有用。
- 初始日志配置:最初,小菜的日志配置设置为仅记录
INFO级别及以上的日志。 - 检测到特定问题:当系统检测到特定问题(可能是通过错误计数、特定类型的请求或其他指标)时,小菜想动态调整相关模块的日志级别以捕获更详细的信息。
- 应用增量更新:此时,小菜可以使用
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:# 当出现特定条件时,提升日志级别到 DEBUGincremental_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.StreamHandlerformatter: simplelevel: DEBUG
root:level: INFOhandlers: [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 函数的参数整理:
| 参数名称 | 类型 | 必需 | 描述 |
|---|---|---|---|
fname | str | 必须 | 配置文件的路径。这个文件包含了日志配置的信息。 |
defaults | dict | 可选 | 配置文件中使用的变量的默认值。 |
disable_existing_loggers | bool | 可选 | 决定是否禁用在调用 fileConfig 之前已经存在的日志记录器。默认为 True。 |
encoding | str | 可选 | 用于指定配置文件的编码方式。 |
必需的字段
在 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.configlogging.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 sysclass RemoteLogHandler(logging.Handler):"""自定义远程处理器"""def __init__(self, remote_url):super().__init__()self.remote_url = remote_urlself.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')
总结🎈🎈
本文全面介绍了Python 中logging模块的高级文件配置技巧,重点讨论了dictConfig和fileConfig两种配置方法。
通过dictConfig,开发者可以灵活地使用字典、JSON 或 YAML 格式来设置日志级别、格式和处理器,
而fileConfig则提供了对INI格式配置文件的支持。尽管fileConfig在功能上有所限制,但它仍适用于简单的配置需求。
文章通过实例和注意事项,指导读者如何选择和应用这些配置方法,以优化日志处理流程并提升应用性能。
总的来说,这篇文章可以帮助读者朋友们深入了解如何使用 logging.config 进行日志文件配置。进而帮助读者建立一个高效、可维护的日志系统。
后话
本次分享到此结束,
see you~~✨✨
相关文章:
万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置
万字长文 - Python 日志记录器logging 百科全书 - 高级配置之 日志文件配置 前言 在 Python 的logging模块中,它不仅提供了基础的日志功能,还拥有一系列高级配置选项来满足复杂应用的日志管理需求。 说到logging 模块的高级配置,必须提及日…...
LeetCode解法汇总1410. HTML 实体解析器
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 「HTML 实…...
OpenGL 绘制旋转球(Qt)
文章目录 一、简介二、实现代码三、实现效果一、简介 这里其实就是指三个互相垂直的三个圆形,正好之前已经完成了圆形平面的绘制,那么这里就需要对之前的圆形进行一些改造,使得它们可以以任意一种姿态在OpenGL中进行绘制(添加变换矩阵)。 这里同样对其进行封装,具体内容如…...
解决:javax.websocket.server.ServerContainer not available 报错问题
原因: 用于扫描带有 ServerEndpoint 的注解成为 websocket,该方法是 服务器端点出口,当进行 SpringBoot 单元测试时,并没有启动服务器,所以当加载到这个bean时会报错。 解决方法: 加上这个注解内容 Spr…...
81基于matlab GUI的图像处理
基于matlab GUI的图像处理,功能包括图像颜色处理(灰度图像、二值图像、反色变换、直方图、拉伸变换);像素操作(读取像素、修改像素)、平滑滤波(均值平滑、高斯平滑、中值平滑)、图像…...
虚拟机系列:vmware和Oracle VM VirtualBox虚拟机的区别,简述哪一个更适合我?以及相互转换
一. VMware和Oracle VM VirtualBox虚拟机的区别主要体现在以下几个方面: 首先两种软件的安装使用教程如下: VMware ESXI 安装使用教程 Oracle VM VirtualBox安装使用教程 商业模式:VMware是一家商业公司,而Oracle VM VirtualBox是开源软件; 功能:VMware拥有更多的功能和…...
Go lumberjack 日志轮换和管理
在开发应用程序时,记录日志是一项关键的任务,以便在应用程序运行时追踪问题、监视性能和保留审计记录。Go 语言提供了灵活且强大的日志记录功能,可以通过多种方式配置和使用。其中一个常用的日志记录库是 github.com/natefinch/lumberjack&am…...
git常用命令(git github ssh)
目录 1、语法说明2、本地仓库相关操作建立一个git文件(git init)把工作区的文件添加到暂存区(git add)把暂存区的文件添加到本地仓库(git commit)查看暂存区和本地仓库中的文件(git ls-files)查看文件夹下所有文件的状态(git status)查看版本库中的提交记录(git log)恢复的文件…...
完美解决:Nginx访问PHP出现File not found.
目录 解决方法一: 解决方法二: 遇到 File not found. 出现的问题解决: 解决方法一: 修改nginx的主配置文件。 vi /etc/nginx/nginx.conf location ~ \.php$ { root html; fastcgi_pass …...
音视频5、libavformat-2
4、封装 Muxers (封装器)以 AVPacket 的形式获取编码数据并将其写入到指定容器格式的文件或输出字节流中。 muxing过程中最重要的API函数有: avformat_write_header() 用于写入文件header; av_write_frame() / av_interleaved_write_frame() 用于写…...
python opencv -模板匹配
python opencv -模板匹配 模板匹配就是,我们现有一个模板和一个图片,然后,在这个图片中寻找和模板近似的部分。 在opencv 中主要通过cv2.matchTemplate这个函数去实现。 下面我们先看一下,模板图片和需要匹配的图片:…...
大数据技能大赛(高职组)答案
任务C:数据挖掘(10分) 所有模块都有,不是白嫖!!有需要可以联系我 环境说明: 服务端登录地址详见各任务服务端说明。 补充说明:各节点可通过Asbru工具或SSH客户端进行SSH访问…...
C++动态规划算法:最多可以参加的会议数目
本周推荐阅读 C二分算法:得到子序列的最少操作次数 本题的其它解法 C二分算法:最多可以参加的会议数目 II 本文涉及的基础知识点 二分查找算法合集 题目 给你一个 events 数组,其中 events[i] [startDayi, endDayi, valuei] …...
Windows 下安装MySQL8.0 Zip
1、将下载的mysql 压缩包解压。 2、已管理员身份证 打开 cmd窗口,进入到解压目录的,本文以解压到 D:\soft\mysql-8.0.29-winx64 为例来介绍。 3、在解压目录下 新建一个 my.ini 文件。 my.ini 文件内容如下: [mysqld] # 设置3306端口 por…...
8.2 Windows驱动开发:内核解锁与强删文件
在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttri…...
【Spark源码分析】事件总线机制分析
Spark事件总线机制 采用Spark2.11源码,以下类或方法被DeveloperApi注解额部分,可能出现不同版本不同实现的情况。 Spark中的事件总线用于接受事件并提交到对应的监听器中。事件总线在Spark应用启动时,会在SparkContext中激活spark运行的事件总…...
c语言第七弹--扫雷小游戏!
今天做一个有趣的扫雷小游戏 现在正式开始设计。 思路:想要根本上实现必须拥有 实现函数的主体.c文件 头文件.h 及头文件实现.c。 头文件.h #pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #define EASY_COUNT 10 #d…...
浏览器是什么
浏览器是什么 本文简要介绍浏览器的功能和组成。 浏览器(Web Browser)是一种用于访问和浏览互联网上的网页和资源的软件应用程序。它是用户与互联网交互的主要工具之一。 浏览器通过使用网络协议(如HTTP、HTTPS等)与远程服务器通…...
一文彻底看懂Python切片,Python切片理解与操作
1.什么是切片 切片是Python中一种用于操作序列类型(如列表、字符串和元组)的方法。它通过指定起始索引和结束索引来截取出序列的一部分,形成一个新的序列。切片是访问特定范围内的元素,就是一个Area。 说个笑话:切片不是切片,而是切片,但是又是切片。大家理解下呢(末…...
聊聊tomcat的connection-timeout
序 本文主要研究一下tomcat的connection-timeout ServerProperties.Tomcat org/springframework/boot/autoconfigure/web/ServerProperties.java public static class Tomcat {/*** Access log configuration.*/private final Accesslog accesslog new Accesslog();/*** Th…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
