日志层次结构及logger.propagate的作用

一、Python logging 模块的层次结构

Python 的 logging 模块提供了一个灵活的日志系统,适用于各种规模的应用程序。其核心设计基于层次化的命名系统,使得日志记录可以按照组织结构进行管理和配置。

1. Logger(日志器)

  • 定义:Logger 是日志记录的核心对象,用于生成日志消息。
  • 命名:每个 Logger 都有一个名称,通常使用点(.)分隔的字符串来表示层次结构,例如 'app''app.module''app.module.submodule'
  • 层次结构:Logger 名称中的点表示层级关系。例如,'app.module''app' 的子 Logger,'app.module.submodule' 又是 'app.module' 的子 Logger。

2. Handler(处理器)

  • 定义:Handler 负责将日志消息发送到特定的目的地,如控制台、文件、网络等。
  • 类型:常用的 Handler 包括 StreamHandler(输出到控制台)、FileHandler(输出到文件)、SMTPHandler(发送邮件)等。
  • 配置:每个 Handler 可以独立配置其日志级别、格式化器等属性。

3. Filter(过滤器)

  • 定义:Filter 提供了更细粒度的控制,用于决定哪些日志消息可以通过特定的 Handler 或 Logger。
  • 用途:可以基于日志属性(如模块名、线程名等)过滤日志消息。

4. Root Logger(根日志器)

  • 定义:Root Logger 是层次结构中的顶级 Logger,其名称为空字符串('')。
  • 作用:所有未显式设置父 Logger 的 Logger 都是根 Logger 的子 Logger。根 Logger 通常配置全局的 Handler 和 Formatter,以确保所有日志消息都有一个默认的处理方式。

5. Logger 的层次关系示意图

根 Logger ('')
├── app
│   ├── app.module
│   │   └── app.module.submodule
│   └── app.other_module
└── another_app└── another_app.module

在上述层次结构中:

  • 'app.module.submodule''app.module' 的子 Logger。
  • 'app.module''app' 的子 Logger。
  • 'app''another_app' 都是根 Logger 的直接子 Logger。

6. 日志消息的传播

当一个 Logger 记录一条日志消息时,消息会首先被当前 Logger 关联的 Handler 处理,然后根据 propagate 属性决定是否将消息传递给父 Logger 进行进一步处理。这种传播机制允许日志消息在层次结构中逐级传递,直到根 Logger。

二、logger.propagate 属性的解释

logger.propagate 是 Python logging 模块中 Logger 对象的一个布尔属性,用于控制日志消息在 Logger 层次结构中的传播行为。理解和合理配置 propagate 对于避免重复日志输出和实现定制化日志处理至关重要。

1. logger.propagate 的基本概念

  • 默认值True
  • 作用
    • propagate=True:日志消息会在当前 Logger 的 Handler 处理完后,继续传递给父 Logger 的 Handler 进行处理。
    • propagate=False:日志消息只由当前 Logger 的 Handler 处理,不会传递给父 Logger。

2. 具体行为示例

假设有以下 Logger 层次结构:

根 Logger ('')
└── app└── app.module

配置

  • 根 Logger 配置了一个 StreamHandler,格式为 ROOT: %(levelname)s: %(message)s
  • app Logger 配置了一个 StreamHandler,格式为 APP: %(levelname)s: %(message)s
  • app.module Logger 配置了一个 StreamHandler,格式为 MODULE: %(levelname)s: %(message)s

示例代码

import logging# 配置根 Logger
root_logger = logging.getLogger()
root_handler = logging.StreamHandler()
root_handler.setFormatter(logging.Formatter('ROOT: %(levelname)s: %(message)s'))
root_logger.addHandler(root_handler)
root_logger.setLevel(logging.DEBUG)# 配置 'app' Logger
app_logger = logging.getLogger('app')
app_handler = logging.StreamHandler()
app_handler.setFormatter(logging.Formatter('APP: %(levelname)s: %(message)s'))
app_logger.addHandler(app_handler)
app_logger.setLevel(logging.DEBUG)# 配置 'app.module' Logger
module_logger = logging.getLogger('app.module')
module_handler = logging.StreamHandler()
module_handler.setFormatter(logging.Formatter('MODULE: %(levelname)s: %(message)s'))
module_logger.addHandler(module_handler)
module_logger.setLevel(logging.DEBUG)print("=== propagate=True ===")
module_logger.propagate = True
module_logger.debug('This is a debug message with propagate=True.')print("\n=== propagate=False ===")
module_logger.propagate = False
module_logger.debug('This is a debug message with propagate=False.')

预期输出

=== propagate=True ===
MODULE: DEBUG: This is a debug message with propagate=True.
APP: DEBUG: This is a debug message with propagate=True.
ROOT: DEBUG: This is a debug message with propagate=True.=== propagate=False ===
MODULE: DEBUG: This is a debug message with propagate=False.

解释

  1. propagate=True(默认)

    • 日志消息首先由 app.module Logger 关联的 module_handler 处理,输出 "MODULE: DEBUG: This is a debug message with propagate=True."
    • 然后,消息传递给父 Logger app,由 app_handler 处理,输出 "APP: DEBUG: This is a debug message with propagate=True."
    • 最后,消息继续传递给根 Logger,由 root_handler 处理,输出 "ROOT: DEBUG: This is a debug message with propagate=True."
  2. propagate=False

    • 日志消息仅由 app.module Logger 关联的 module_handler 处理,输出 "MODULE: DEBUG: This is a debug message with propagate=False."
    • 消息不会传递给父 Logger app 或根 Logger。

3. 使用场景

  • 避免重复日志输出
    在多层次 Logger 配置中,如果不适当设置 propagate,可能导致同一条日志消息被多个 Handler 重复处理。例如,日志同时被子 Logger 和父 Logger 的 Handler 输出。通过将子 Logger 的 propagate 设置为 False,可以避免这种情况。

  • 定制化日志处理
    有时希望特定 Logger 的日志消息只由其自身的 Handler 处理,而不受父 Logger 的影响。此时,可以将该 Logger 的 propagate 设置为 False,实现独立的日志处理逻辑。

4. 综合示例:结合层次结构和 logger.propagate

假设有以下应用场景:

  • 根 Logger:记录所有 WARNING 及以上级别的日志到文件 app.log
  • app.module Logger:记录所有 DEBUG 及以上级别的日志到控制台,并且不希望这些日志再传递给根 Logger

配置代码

import logging# 定义日志器
root_logger = logging.getLogger()
root_logger.setLevel(logging.WARNING)
file_handler = logging.FileHandler('app.log')
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(file_formatter)
root_logger.addHandler(file_handler)app_module_logger = logging.getLogger('app.module')
app_module_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(console_formatter)
app_module_logger.addHandler(console_handler)
app_module_logger.propagate = False  # 禁止传播到根 Logger# 日志记录
app_module_logger.debug('Debug message from app.module.')  # 仅输出到控制台
app_module_logger.warning('Warning message from app.module.')  # 输出到控制台和文件(由于 propagate=False,不会输出到文件)root_logger.warning('Warning message from root logger.')  # 仅输出到文件

预期行为

  • "Debug message from app.module." 仅显示在控制台,因为它的级别是 DEBUG,且 propagate=False,不会传递到根 Logger。
  • "Warning message from app.module." 显示在控制台,并记录到 app.log 文件中,因为它的级别是 WARNINGapp_module_logger 有独立的 Handler,并且 propagate=False 允许它独立记录。
  • "Warning message from root logger." 仅记录到 app.log 文件中,由根 Logger 处理。

文件 app.log 内容(示例):

2024-04-27 12:34:56,789 - root - WARNING - Warning message from root logger.

控制台输出

app.module - DEBUG - Debug message from app.module.
app.module - WARNING - Warning message from app.module.

5. 注意事项

  • 配置顺序:确保在配置 Logger、Handler 和 Formatter 时,按照正确的顺序进行,以避免配置错误或遗漏。
  • 避免 Handler 重复:如果 Logger 的 propagateTrue,并且父 Logger 也有相同的 Handler,可能导致日志消息被重复处理。使用 propagate=False 可有效避免此类问题。
  • 性能考虑:虽然 propagate 对性能的影响较小,但在高频率的日志记录场景中,过多的传播可能会带来一定的开销。合理配置 propagate 有助于优化日志系统的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何配置OSB连接数据连接/读取超时

1.Oracle DB OSB中的DBAdapter的查询超时参数配置没用,要解决接口超时问题,需要在console中的数据源配置超时参数: oracle.net.CONNECT_TIMEOUT30000 oracle.net.READ_TIMEOUT30000 添加图片注释,不超过 140 字(可选…

一起学Git【第六节:查看版本差异】

git diff是 Git 版本控制系统中用于展示差异的强大工具。他可以用于查看文件在工作区、暂存区和版本库之间的差异、任意两个指定版本之间的差异和两个分支之间的差异等,接下来进行详细的介绍。 1.显示工作区与暂存区之间的差异 # 显示工作区和暂存区之间的差异,后面不加参数…

Python数据处理——re库与pydantic的使用总结与实战,处理采集到的思科ASA防火墙设备信息

目录 Python正则表达式re库的基本用法 引入re库 各函数功能 总结 使用方法举例 正则表达式语法与书写方式 正则表达式的常用操作符 思科ASA防火墙数据 数据1 数据2 书写正则表达式 Python中pydantic的使用 导入基础数据模板 根据数据采集目标定义Pydantic数据类型…

Yolo11改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用

摘要 论文介绍 本文介绍了一种名为DynamicHead的模块,该模块旨在通过注意力机制统一目标检测头部,以提升目标检测的性能。论文详细阐述了DynamicHead的工作原理,并通过实验证明了其在COCO基准测试上的有效性和效率。 创新点 DynamicHead模块的创新之处在于它首次尝试在一…

`we_chat_union_id IS NOT NULL` 和 `we_chat_union_id != ‘‘` 这两个条件之间的区别

文章目录 1、什么是空字符串?2、两个引号之间加上空格 好的,我们来详细解释一下 we_chat_union_id IS NOT NULL 和 we_chat_union_id ! 这两个条件之间的区别,以及它们在 SQL 查询中的作用: 1. we_chat_union_id IS NOT NULL 含…

如何利用AWS监听存储桶并上传到tg bot

业务描述: 需要监听aws的存储中的最新消息,发送新的消息推送到指定tg的频道。 主要流程: 1.上传消息到s3存储桶(不做具体描述) 2.通过aws的lambda监听s3存储桶的最新消息(txt文件) 3.将txt文件…

HarmonyOS NEXT 实战之元服务:静态案例效果---查看国内航班服务

背景: 前几篇学习了元服务,后面几期就让我们开发简单的元服务吧,里面丰富的内容大家自己加,本期案例 仅供参考 先上本期效果图 ,里面图片自行替换 效果图1完整代码案例如下: Index代码 import { authen…

Windows11家庭版启动Hyper-V

Hyper-V 是微软的硬件虚拟化产品,允许在 Windows 上以虚拟机形式运行多个操作系统。每个虚拟机都在虚拟硬件上运行,可以创建虚拟硬盘驱动器、虚拟交换机等虚拟设备。使用虚拟化可以运行需要较旧版本的 Windows 或非 Windows 操作系统的软件,以…

为什么深度学习和神经网络要使用 GPU?

为什么深度学习和神经网络要使用 GPU? 本篇文章的目标是帮助初学者了解 CUDA 是什么,以及它如何与 PyTorch 配合使用,更重要的是,我们为何在神经网络编程中使用 GPU。 图形处理单元 (GPU) 要了解 CUDA,我们需要对图…

每天五分钟机器学习:核函数

本文重点 在学习支持向量机算法之前,我们要继续学习一些数学基础,本文我们将学习核函数的概念。当数据线性不可分的时候,此时就需要核函数出场了,它可以将低维不可分的数据映射到高维可分数据,此时就可以完成数据分类了。 核函数的定义 核函数K(x, y)定义为两个数据点x…

MaaS(Model as a Service)

1.MasS是什么? Model as a Service(MaaS)是一种云计算服务模式,它允许用户通过互联网访问和使用机器学习模型,而不需要自行构建和维护这些模型。MaaS提供了模型的托管、管理和监控,使用户能够专注于应用程…

图像处理-Ch7-快速小波变换和小波包

个人博客!无广告观看,因为这节内容太多了,有点放不下,分了三节 文章目录 快速小波变换(The Fast Wavelet Transform)与两频段子带编译码系统的关系例:计算一维小波变换 一维快速小波反变换例:计算一维小波…

KAFKA 权威指南笔记(一)究竟应该配置多少个BROKER?

一个KAFKA集群需要多少个BROKER? 一个单独的Kafka服务器被叫做BROKER,BROKER可以处理数千个分区以及每秒百万级别的消息量。由BROKER组成了“集群”(其中由集群控制器角色的BROKER是从成员中选举出来的,负责控制管理工作&#xf…

【ES6复习笔记】函数参数的默认值(6)

在ES6中,函数参数默认值是一个非常有用的特性,它允许你在定义函数时为参数指定一个默认值。如果在调用函数时没有提供相应的参数值,那么函数将使用默认值。 1. 形参初始值 具有默认值的参数,一般位置要靠后。这是一个潜规则&…

WebRtc webrtc-streamer部署

文章目录 本文档只是为了留档方便以后工作运维,或者给同事分享文档内容比较简陋命令也不是特别全,不适合小白观看,如有不懂可以私信,上班期间都是在得 WebRtc webrtc-streamer 部署 docker run -p 8000:8000 -it mpromonet/webrt…

Spring Boot中幂等性的应用

在 Spring Boot 中,幂等性是实现分布式系统设计和接口调用的一个重要概念,尤其在高并发、分布式环境下,确保接口重复调用不会引发系统数据异常至关重要。 幂等性概念 幂等性(Idempotence)是指一次请求和重复多次请求…

leetcode 7. 整数反转

class Solution { public: int reverse(int x) { long long n0; if(x0) return 0; while(x%100) { xx/10; } while(x!0) { nn*10x%10; xx/10; } if(n<-2147483648||n>2147483647) return 0; return n; } };

[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结

目录 编写http_server模块 1. 引入cpp-httplib到项目中 2. cpp-httplib的使用介绍 3. 正式编写http_server 九、添加日志到项目中 十、编写前端模块 十一. 详解传 gitee 十二、项目总结 项目的扩展 写在前面 [项目详解][boost搜索引擎#1] 概述 | 去标签 | 数据清洗 |…

xxl-job 简单的入门到实战

本文是参考官方文档自己实践一次&#xff0c;纯享版&#xff0c;大致也是作者边写博客边去跟着官方文档实现 一、前期准备 1、官网地址 GitHub地址&#xff1a; GitHub - xuxueli/xxl-job: A distributed task scheduling framework.&#xff08;分布式任务调度平台XXL-JOB&…

Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org

在 CentOS 7 中使用 yum 工具时&#xff0c;如果出现 "Could not resolve host: mirrorlist.centos.org" 的错误&#xff0c;通常是因为默认的镜像源无法访问。以下是一些常用的解决方法&#xff1a; 检查网络连接&#xff1a;首先使用 ping 命令测试网络连接是否正常…