当前位置: 首页 > article >正文

《Python实战进阶》No27: 日志管理:Logging 模块的最佳实践(下)

No27: 日志管理:Logging 模块的最佳实践(下)


实战案例 :复杂场景下的 Logging 配置与使用

本实战案例在 Python 3.11.5环境下运行通过

在本案例中,我们将通过一个复杂的日志配置示例,全面展示 logging 模块的参数设置和高级功能。该示例将涵盖以下内容:

  • 使用配置文件(JSON 格式)动态调整日志设置。
  • 同时输出日志到控制台、文件和远程服务器。
  • 设置日志轮转策略。
  • 自定义日志格式。
    在这里插入图片描述

代码实现

1. 配置文件 (logging_config.json)

我们首先创建一个 JSON 文件来定义日志的详细配置。

{"version": 1,"disable_existing_loggers": false,"formatters": {"detailed": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"},"simple": {"format": "%(levelname)s - %(message)s"}},"handlers": {"console": {"class": "logging.StreamHandler","level": "DEBUG","formatter": "simple","stream": "ext://sys.stdout"},"file": {"class": "logging.handlers.RotatingFileHandler","level": "INFO","formatter": "detailed","filename": "app.log","maxBytes": 1048576,"backupCount": 3},"remote": {"class": "logging.handlers.SocketHandler","level": "ERROR","host": "localhost","port": 9020}},"loggers": {"app_logger": {"level": "DEBUG","handlers": ["console", "file", "remote"],"propagate": false}},"root": {"level": "WARNING","handlers": ["console"]}
}
2. Python 脚本 (complex_logging.py)

接下来,我们编写 Python 脚本来加载配置文件并使用日志系统。

import logging
import logging.config
import json
import os
import sys# 加载日志配置文件
def setup_logging(config_file):"""从 JSON 配置文件加载日志设置。"""try:if not os.path.exists(config_file):raise FileNotFoundError(f"配置文件 {config_file} 未找到。")with open(config_file, 'r', encoding='utf-8') as f:config = json.load(f)# 应用配置logging.config.dictConfig(config)print(f"成功加载日志配置: {config_file}")except json.JSONDecodeError as e:sys.stderr.write(f"配置文件格式错误: {e}\n")sys.exit(1)except Exception as e:sys.stderr.write(f"设置日志时出错: {e}\n")sys.exit(1)# 使用更安全的方式初始化日志
def initialize_logging():try:setup_logging('logging_config.json')return logging.getLogger('app_logger')except Exception as e:# 如果配置失败,设置基本日志print(f"使用默认日志配置: {e}")logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')return logging.getLogger('app_logger')# 初始化日志
logger = initialize_logging()# 示例函数:模拟程序运行
def simulate_application():try:logger.debug("这是一条调试信息。")       # 控制台和文件中可见logger.info("这是一条信息消息。")        # 控制台和文件中可见logger.warning("这是一条警告消息。")     # 控制台和文件中可见logger.error("这是一条错误消息。")       # 控制台、文件和远程服务器中可见logger.critical("这是一条严重错误消息。") # 控制台、文件和远程服务器中可见# 模拟一个异常情况try:result = 10 / 0except Exception as e:logger.exception(f"发生异常: {e}")except Exception as e:print(f"记录日志时出错: {e}")if __name__ == '__main__':simulate_application()print("日志测试完成。请检查日志文件和远程服务器。")# 为了确保所有日志都被发送,特别是通过网络logging.shutdown()

代码详解

1. 配置文件解析
  • formatters: 定义了两种日志格式:
    • detailed: 包含时间戳、日志名称、日志级别和消息。
    • simple: 仅包含日志级别和消息。
  • handlers:
    • console: 将日志输出到控制台,使用 simple 格式。
    • file: 将日志写入文件,支持日志轮转(最大 1MB,保留 3 个备份),使用 detailed 格式。
    • remote: 将错误日志发送到远程服务器(假设运行了一个监听端口 9020 的服务)。
  • loggers:
    • app_logger: 自定义日志记录器,绑定到 consolefileremote 处理器。
    • root: 全局日志记录器,默认仅输出警告及以上级别的日志到控制台。
  • disable_existing_loggers: 禁用默认的日志记录器,避免干扰。
2. 动态加载配置

通过 logging.config.dictConfig() 方法动态加载 JSON 配置文件,使日志配置更加灵活且易于维护。

3. 日志轮转

RotatingFileHandler 用于限制日志文件大小,并自动分割旧日志文件。例如,当 app.log 达到 1MB 时,会生成 app.log.1app.log.2 等备份文件。

4. 远程日志

SocketHandler 将错误日志发送到远程服务器,适合分布式系统中的集中日志管理。


输入与输出

运行环境准备
  • 启动远程日志服务器:
    假设我们有一个运行在 localhost:9020 的简单 TCP 日志服务器。
import socketserver
import pickle
import logging
import structclass LogRecordStreamHandler(socketserver.StreamRequestHandler):"""处理由logging.handlers.SocketHandler发送的日志记录"""def handle(self):"""处理来自客户端的日志记录"""while True:try:# 根据logging.handlers.SocketHandler的协议读取数据长度chunk = self.connection.recv(4)if len(chunk) < 4:breakslen = struct.unpack('>L', chunk)[0]chunk = self.connection.recv(slen)while len(chunk) < slen:chunk = chunk + self.connection.recv(slen - len(chunk))# 安全地反序列化数据obj = self.unPickle(chunk)record = logging.makeLogRecord(obj)# 打印日志信息print(f"收到日志: [{record.levelname}] {record.name}: {record.getMessage()}")# 可选:重新格式化并记录到本地日志系统# self.handleLogRecord(record)except Exception as e:print(f"处理日志时出错: {e}")breakdef unPickle(self, data):"""以更安全的方式反序列化数据"""try:return pickle.loads(data)except Exception as e:print(f"反序列化出错: {e}")raiseclass LogRecordSocketReceiver(socketserver.ThreadingTCPServer):"""使用TCP协议接收日志记录的简单服务器"""allow_reuse_address = Truedef __init__(self, host='localhost', port=9020, handler=LogRecordStreamHandler):socketserver.ThreadingTCPServer.__init__(self, (host, port), handler)self.abort = 0self.timeout = 1if __name__ == "__main__":# 启动日志服务器tcpserver = LogRecordSocketReceiver()print("日志服务器已在 localhost:9020 启动")try:tcpserver.serve_forever()except KeyboardInterrupt:print("服务器关闭中...")finally:tcpserver.server_close()
运行代码

执行主程序:

python complex_logging.py
输出结果
  • 控制台输出:
成功加载日志配置: logging_config.json
DEBUG - 这是一条调试信息。
INFO - 这是一条信息消息。
WARNING - 这是一条警告消息。
ERROR - 这是一条错误消息。
CRITICAL - 这是一条严重错误消息。
ERROR - 发生异常: division by zero
Traceback (most recent call last):File "D:\python_projects\python_shizhan\logging_demo\complex_logging.py", line 57, in simulate_applicationresult = 10 / 0~~~^~~
ZeroDivisionError: division by zero
日志测试完成。请检查日志文件和远程服务器。
  • 日志文件 (app.log):
2025-03-19 17:33:44,890 - app_logger - INFO - 这是一条信息消息。
2025-03-19 17:33:44,890 - app_logger - WARNING - 这是一条警告消息。
2025-03-19 17:33:44,890 - app_logger - ERROR - 这是一条错误消息。
2025-03-19 17:33:45,903 - app_logger - CRITICAL - 这是一条严重错误消息。
2025-03-19 17:33:45,904 - app_logger - ERROR - 发生异常: division by zero
Traceback (most recent call last):File "D:\python_projects\python_shizhan\logging_demo\complex_logging.py", line 57, in simulate_applicationresult = 10 / 0~~~^~~
ZeroDivisionError: division by zero
  • 远程日志服务器:
日志服务器已在 localhost:9020 启动
收到日志: [ERROR] app_logger: 这是一条错误消息。
收到日志: [CRITICAL] app_logger: 这是一条严重错误消息。
收到日志: [ERROR] app_logger: 发生异常: division by zero

总结

本案例展示了如何通过 JSON 配置文件灵活地管理日志系统,并结合多种处理器实现多目标输出(控制台、文件、远程服务器)。同时,我们还介绍了日志轮转和远程日志发送等高级功能。这种配置方式非常适合复杂的生产环境,能够显著提升日志管理的效率和可维护性。


扩展思考

1. 如何优化日志性能?
  • 在高并发场景下,可以使用异步日志处理器(如 QueueHandlerQueueListener)以减少日志记录对主线程的影响。
  • 对于大文件日志,建议定期归档或压缩旧日志。
2. 如何增强日志安全性?
  • 在发送日志到远程服务器时,建议启用加密传输(如 TLS/SSL)。
  • 敏感信息(如用户密码)应从日志中过滤掉,避免泄露。

希望本集内容能帮助你更全面地掌握 logging 模块的高级用法!

相关文章:

《Python实战进阶》No27: 日志管理:Logging 模块的最佳实践(下)

No27: 日志管理&#xff1a;Logging 模块的最佳实践&#xff08;下&#xff09; 实战案例 &#xff1a;复杂场景下的 Logging 配置与使用 本实战案例在 Python 3.11.5环境下运行通过 在本案例中&#xff0c;我们将通过一个复杂的日志配置示例&#xff0c;全面展示 logging 模…...

Web 小项目: 网页版图书管理系统

目录 最终效果展示 代码 Gitee 地址 1. 引言 2. 留言板 [热身小练习] 2.1 准备工作 - 配置相关 2.2 创建留言表 2.3 创建 Java 类 2.4 定义 Mapper 接口 2.5 controller 2.6 service 3. 图书管理系统 3.1 准备工作 - 配置相关 3.2 创建数据库表 3.2.1 创建用户表…...

【Dive Into Stable Diffusion v3.5】1:开源项目正式发布——深入探索SDv3.5模型全参/LoRA/RLHF训练

目录 1 引言2 项目简介3 快速上手3.1 下载代码3.2 环境配置3.3 项目结构3.4 下载模型与数据集3.5 运行指令3.6 核心参数说明3.6.1 通用参数3.6.2 优化器/学习率3.6.3 数据相关 4 结语 1 引言 在人工智能和机器学习领域&#xff0c;生成模型的应用越来越广泛。Stable Diffusion…...

《Waf 火绒终端防护绕过实战:系统程序副本+Certutil木马下载技术详解》

目录 绕过火绒终端安全软件的详细方法 方法一&#xff1a;利用系统程序副本绕过命令监控 方法二&#xff1a;结合certutil.exe副本下载并执行上线木马 注意事项 总结 实际案例解决方案 前提条件 详细操作步骤 1. 攻击主机&#xff08;VPS&#xff09;上的准备工作 2.…...

上海高考解析几何

解析几何的核心思想。 1. 核心分析方法&#xff1a; 自由度引入 方程组中&#xff0c; n n n 个未知数需要 n n n 个等式来解出具体的值。 自由度 性质 一个未知数带来一个自由度&#xff0c;一个等式条件减少一个自由度&#xff08;减少自由度的方式为消元&#xff09;。…...

android MutableLiveData setValue 响应速速 postValue 快

MutableLiveData 是 LiveData 的一个可变版本,常用于在ViewModel中保存和管理UI相关的数据。MutableLiveData 提供了两种主要的方法来更新其值:setValue 和 postValue。关于这两者的响应速度,通常认为 setValue 比 postValue 更快。下面详细解释这两者的区别以及影响响应速度…...

【AVRCP】服务发现互操作性:CT 与 TG 的 SDP 协议契约解析

目录 一、服务发现的核心目标&#xff1a;能力画像对齐 二、控制器&#xff08;CT&#xff09;服务记录&#xff1a;控制能力的声明 2.1 必选字段&#xff1a;角色与协议的刚性契约 2.1.1 服务类标识&#xff08;Service Class ID List&#xff09; 2.1.2 协议描述列表&am…...

MySQL:数据库基础

数据库基础 1.什么是数据库&#xff1f;2.为什么要学习数据库&#xff1f;3.主流的数据库&#xff08;了解&#xff09;4.服务器&#xff0c;数据库&#xff0c;表之间的关系5.数据的逻辑存储6.MYSQL架构7.存储引擎 1.什么是数据库&#xff1f; 数据库(Database,简称DB)&#x…...

市场热点复盘20240319

以下是对当前市场热点板块的分析总结&#xff0c;按逻辑分类如下&#xff1a; 一、机器人产业链核心标的 1. 减速器与核心部件 襄阳轴承&#xff1a;直接受益人形机器人减速器轴承需求&#xff0c;技术国内领先。金帝股份&#xff1a;聚焦机器人手指关节谐波减速机保持架&am…...

深入 Linux 声卡驱动开发:核心问题与实战解析

1. 字符设备驱动如何为声卡提供操作接口&#xff1f; 问题背景 在 Linux 系统中&#xff0c;声卡被抽象为字符设备。如何通过代码让应用程序能够访问声卡的录音和播放功能&#xff1f; 核心答案 1.1 字符设备驱动的核心结构 Linux 字符设备驱动通过 file_operations 结构体定…...

鸿蒙下载文件保存到手机本地公共文件夹下、将本地的沙箱目录文件,保存到公共目录,鸿蒙picker save保存文件为空(0字节)的问题

1、首先将下载好的文件&#xff0c;保存到本地目录&#xff0c;这个目录是用户看不到的&#xff1b; 2、然后通过picker的save保存文件&#xff0c;这个picker&#xff0c;它只是获取公共目录uri用的 3、当picker有回调时&#xff0c;将公共目录的uri获取之后&#xff0c;把下…...

OpenNJet动态API设置accessLog开关,颠覆传统运维工作模式

OpenNJet OpenNJet 应用引擎是高性能、轻量级的WEB应用与代理软件。作为云原生服务网格的数据平面&#xff0c;NJet具备动态配置加载、主动式健康检测、集群高可用、声明式API等多种强大功能。通过CoPliot副驾驶服务框架&#xff0c;在隔离控制面和数据面的情况下实现了高可扩…...

案例5_4: 6位数码管轮播0-9【静态显示】

文章目录 文章介绍效果图提示代码&#xff08;不完整&#xff09; 文章介绍 5.1.2 数码管静态显示应用举例 要求&#xff1a; 1、仿真图同案例5_3 2、代码参考案例5_3和案例5_2 效果图 提示代码&#xff08;不完整&#xff09; #include<reg52.h> // 头文件#define uch…...

navicat忘记已经连接过的数据库密码的操作步骤

第一步&#xff1a; 点击文件-》导出连接 第二步&#xff1a;选中具体的数据库&#xff0c;且勾选左下角的记住密码 第三步&#xff1a;打开刚刚导出的文件&#xff0c;找到对应加密后的密码 第四步&#xff1a;复制密码到工具点击查看密码 注&#xff1a;参考文章链接附…...

Qt窗口坐标体系

坐标系&#xff1a;以左上角为原点&#xff08;0&#xff0c;0&#xff09;&#xff0c;X向右增加&#xff0c;Y向下增加 对于嵌套窗口&#xff0c;其坐标是相对于父窗口来说的 例如&#xff1a; 通过move方法实现...

DeepSeek写打台球手机小游戏

DeepSeek写打台球手机小游戏 提问 根据提的要求&#xff0c;让DeepSeek整理的需求&#xff0c;进行提问&#xff0c;内容如下&#xff1a; 请生成一个包含以下功能的可运行移动端打台球小游戏H5文件&#xff1a; 要求 可以重新开始游戏 可以暂停游戏 有白球和其他颜色的球&am…...

VR大空间多人互动方案,VR大空间融合AI行为预测的动捕技术

在数字科技迅猛发展的今天&#xff0c;VR大空间技术正逐步成为各行业探索沉浸式体验的重要方向。从企业培训、线上展览到社交元宇宙&#xff0c;VR大空间的应用范围不断拓展。而在这个过程中&#xff0c;多人实时交互成为核心需求&#xff0c;它不仅关乎沉浸感的提升&#xff0…...

十四、OSG学习笔记-事件响应

上一章节 十三、OSG学习笔记-osgDB文件读写-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146165712 本章节代码&#xff1a; OsgStudy/EventHandle CuiQingCheng/OsgStudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/osg-study/tree/master/Osg…...

JS逆向_腾讯点选_VMP补环境

1.接口分析 1.cap_union_prehandle 说明:图片、jsvmp GET QueryString:{aid: xxxxxx //网站在腾讯登记的idprotocol: httpsaccver: 1showtype: popupua: //ua atob后的结果noheader: 1fb: 1aged: 0enableAged: 0enableDarkMode: 0grayscale: 1clientype: 2cap_cd: uid: lang:…...

【MySQL数据库】多表查询(笛卡尔积现象,联合查询、内连接、左外连接、右外连接、子查询)-通过练习快速掌握法

在DQL的基础查询中&#xff0c;我们已经学过了多表查询的一种&#xff1a;联合查询&#xff08;union&#xff09;。本文我们将系统的讲解多表查询。 笛卡尔积现象 首先&#xff0c;我们想要查询emp表和stu表两个表&#xff0c;按照我们之前的知识栈&#xff0c;我们直接使用…...

爬虫案例-爬取某狗音乐

文章目录 1、爬取代码2、效果图1、爬取代码 import time import requests import hashlib import jsonpath import osurl = "https://wwwapi.kugou.com/play/songinfo"#伪造请求头 header= {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64…...

Android第四次面试总结(基础算法篇)

一、反转链表 // 定义链表节点类 class ListNode {// 节点存储的值int val;// 指向下一个节点的引用ListNode next;// 构造函数&#xff0c;用于初始化节点的值ListNode(int x) { val x; } }class Solution {// 反转链表的方法public ListNode reverseList(ListNode head) {/…...

DAPO-Decoupled Clip and Dynamic sAmpling Policy Optimization

论文地址&#xff1a;https://dapo-sia.github.io/static/pdf/dapo_paper.pdf 代码地址&#xff1a;https://github.com/volcengine/verl/tree/gm-tyx/puffin/main/recipe/dapo 数据&#xff1a;https://huggingface.co/datasets/BytedTsinghua-SIA/DAPO-Math-17k 1. 背景与动机…...

每日一题——买卖股票的最佳时机

买卖股票的最佳时机 问题描述示例示例 1示例 2 提示 问题分析难点分析 算法设计思路 代码实现复杂度分析测试用例测试用例 1测试用例 2测试用例 3 总结 问题描述 给定一个数组 prices&#xff0c;其中第 i 个元素 prices[i] 表示一支给定股票在第 i 天的价格。你可以选择某一天…...

数组模拟邻接表 #图论

文章目录 为什么要用数组来模拟邻接表存储思路遍历思路 树是特殊的图&#xff0c;因此邻接表可以存储图和树两种数据结构。 为什么要用数组来模拟邻接表 在算法设计当中&#xff0c;利用数组来代替结构体模拟各种数据结构会更加简单。 存储思路 给定如下数据,我们可以构造如…...

如何实现一个分布式单例对象?什么场景需要分布式单例?

单例模式确保一个类在同一个进程中只有一个实例&#xff0c;并提供一个全局访问点。这意味着无论在哪里调用该类的实例化方法&#xff0c;返回的都是同一个对象实例。 在分布式系统中&#xff0c;无论是单台机器多个实例&#xff0c;还是多台机器多个实例&#xff0c;每个实例…...

Elasticsearch8.17 集群重启操作

一、全集群重启步骤 1. 禁用分片分配 在关闭数据节点前,需禁用副本分片的分配,避免不必要的 I/O 操作。通过以下命令将分片分配限制为仅主分片: resp = client.cluster.put_settings(persistent={"cluster.routing.allocation.enable": "primaries"}…...

VBA常见的知识都有哪些,让AI编写的VBA经常 报错,所以VBA的基础还是要学习的

掌握这些能够大大的提高VBA的编写效率&#xff0c;欢迎来到涛涛聊AI。 1. 异常处理 Cleanup:是VBScript的错误处理标签&#xff0c;用于标记程序执行失败或退出时需要执行的清理操作&#xff08;如关闭文件、释放对象&#xff09;。这段代码会在遇到错误或用户取消操作时跳转…...

dify重磅升级:从0.15.3安全升级1.1.0新手避坑指南

Docker Compose 部署 备份自定义的 docker-compose YAML 文件(可选) cd docker cp docker-compose.yaml docker-compose.yaml.-$(date +%Y-%m-%d-%H-%M).bak从 main 分支获取最新代码 git checkout main git pull origin main停止服务,命令,请在 docker 目录下执行...

NLP高频面试题(六)——decoder-only、encoder-only和encoder-decoder的区别与联系

一、基本概念与代表模型 1. Encoder-only 架构 Encoder-only 架构最具代表性的模型是 BERT。BERT 使用 masked language modeling&#xff08;MLM&#xff09;进行预训练&#xff0c;即随机遮蔽部分输入词汇&#xff0c;让模型预测被遮蔽的词汇。由于这种架构能够同时看到输入…...