Python日志系统详解:从基础配置到高级应用
1. Python日志系统概述logging模块是Python标准库中用于应用程序和库的灵活事件日志系统。它提供了一套完整的日志记录功能允许开发者根据不同的需求对日志进行分级、过滤和输出。日志系统的基本组件包括Logger记录器应用程序代码直接交互的接口Handler处理器决定日志输出的位置控制台、文件等Filter过滤器提供更细粒度的日志过滤功能Formatter格式化器控制日志的最终输出格式2. 日志级别详解Python logging模块定义了6个标准日志级别按严重性递增排列2.1 标准日志级别NOTSET (0)表示不设置级别会继承父logger的级别DEBUG (10)详细的调试信息通常只在开发时使用INFO (20)确认程序按预期运行的一般信息WARNING (30)表示发生了意外情况或即将发生问题ERROR (40)由于更严重的问题程序无法执行某些功能CRITICAL (50)严重错误程序本身可能无法继续运行提示在实际应用中建议根据环境设置不同的日志级别。开发环境可以使用DEBUG生产环境建议使用INFO或WARNING级别。2.2 日志级别设置方法设置日志级别有两种方式# 方式1使用数值 logger.setLevel(10) # 设置为DEBUG级别 # 方式2使用字符串推荐 logger.setLevel(DEBUG)3. Logger对象深入解析Logger是日志系统的核心组件每个Logger都有一个名称形成层次结构。3.1 Logger的层次结构Logger名称使用点号分隔如a、a.b、a.b.c。未命名的logger会返回root logger。import logging # 获取root logger root_logger logging.getLogger() # 获取名为app的logger app_logger logging.getLogger(app) # 获取名为app.module的logger是app的子logger module_logger logging.getLogger(app.module)3.2 Logger的继承机制子logger会继承父logger的日志级别和handler除非显式设置# 设置父logger级别 logging.getLogger(app).setLevel(INFO) # 子logger未设置级别会继承父logger的INFO级别 module_logger logging.getLogger(app.module) print(module_logger.getEffectiveLevel()) # 输出20INFO3.3 Logger的常用方法日志记录方法debug(msg, *args, **kwargs)info(msg, *args, **kwargs)warning(msg, *args, **kwargs)error(msg, *args, **kwargs)critical(msg, *args, **kwargs)log(lvl, msg, *args, **kwargs)配置方法setLevel(lvl)addHandler(hdlr)removeHandler(hdlr)addFilter(filter)removeFilter(filter)4. Handler处理器详解Handler决定日志的输出位置和方式。常用的内置Handler包括4.1 常用Handler类型StreamHandler输出到流如sys.stderrFileHandler输出到文件RotatingFileHandler按大小自动分割日志文件TimedRotatingFileHandler按时间自动分割日志文件SMTPHandler通过邮件发送日志SocketHandler通过TCP发送日志4.2 Handler配置示例import logging # 创建logger logger logging.getLogger(example) logger.setLevel(logging.DEBUG) # 创建控制台handler并设置级别 console_handler logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # 创建文件handler并设置级别 file_handler logging.FileHandler(example.log) file_handler.setLevel(logging.WARNING) # 创建formatter并添加到handler formatter logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s) console_handler.setFormatter(formatter) file_handler.setFormatter(formatter) # 将handler添加到logger logger.addHandler(console_handler) logger.addHandler(file_handler) # 记录日志 logger.debug(Debug message) logger.info(Info message) logger.warning(Warning message) logger.error(Error message) logger.critical(Critical message)5. Formatter格式化器Formatter控制日志的最终输出格式支持丰富的属性替换。5.1 常用格式化属性属性名格式描述asctime%(asctime)s易读的时间格式created%(created)f时间戳time.time()返回值filename%(filename)s文件名部分funcName%(funcName)s包含日志调用的函数名levelname%(levelname)s日志级别文本DEBUG, INFO等levelno%(levelno)s日志级别数字lineno%(lineno)d源代码行号message%(message)s记录的消息module%(module)s模块名name%(name)slogger名称pathname%(pathname)s完整路径名process%(process)d进程IDprocessName%(processName)s进程名thread%(thread)d线程IDthreadName%(threadName)s线程名5.2 自定义Formatter示例# 创建详细的formatter detailed_formatter logging.Formatter( %(asctime)s - %(name)s - %(levelname)s - %(module)s.%(funcName)s:%(lineno)d - %(message)s, datefmt%Y-%m-%d %H:%M:%S ) # 创建简洁的formatter simple_formatter logging.Formatter(%(levelname)s: %(message)s) # 应用到不同的handler console_handler.setFormatter(simple_formatter) file_handler.setFormatter(detailed_formatter)6. 日志配置最佳实践6.1 基础配置方法最简单的配置方式是使用basicConfig()import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, filenameapp.log, filemodea )6.2 从配置文件加载配置更复杂的配置可以从字典或文件加载import logging.config # 配置字典 config { version: 1, formatters: { detailed: { format: %(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s } }, handlers: { console: { class: logging.StreamHandler, level: INFO, formatter: detailed }, file: { class: logging.FileHandler, filename: mplog.log, level: DEBUG, formatter: detailed } }, root: { level: DEBUG, handlers: [console, file] } } logging.config.dictConfig(config)6.3 多模块日志实践在大型项目中建议在主模块中配置日志系统在各子模块中获取logger时使用__name__作为名称# 主模块 main.py import logging import my_module logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) logger.info(Starting application) my_module.do_something() logger.info(Finished) # 子模块 my_module.py import logging logger logging.getLogger(__name__) def do_something(): logger.info(Doing something)7. 高级日志技巧7.1 上下文信息添加可以通过extra参数添加上下文信息logger.info(User logged in, extra{ip: 192.168.1.1, user: admin})需要相应的formatter支持formatter logging.Formatter(%(asctime)s %(ip)-15s %(user)-8s %(message)s)7.2 异常日志记录记录异常信息的最佳实践try: 1 / 0 except ZeroDivisionError: logger.exception(Division by zero) # 会自动记录异常堆栈 # 等价于 # logger.error(Division by zero, exc_infoTrue)7.3 日志过滤自定义过滤器示例class InfoAndAboveFilter(logging.Filter): def filter(self, record): return record.levelno logging.INFO # 应用过滤器 handler.addFilter(InfoAndAboveFilter())7.4 日志轮转使用RotatingFileHandler实现日志轮转from logging.handlers import RotatingFileHandler handler RotatingFileHandler( app.log, maxBytes1024*1024, # 1MB backupCount5 # 保留5个备份 )8. 性能优化与线程安全8.1 日志性能优化避免在日志消息中进行字符串格式化# 不推荐即使日志级别高于DEBUG也会执行字符串格式化 logger.debug(Value: %s % expensive_function()) # 推荐使用%风格的格式化 logger.debug(Value: %s, expensive_function()) # 推荐使用{}或f-string风格的格式化 logger.debug(Value: {}.format(expensive_function()))使用isEnabledFor检查日志级别if logger.isEnabledFor(logging.DEBUG): logger.debug(Message with %s, expensive_data())8.2 线程安全logging模块是线程安全的但在信号处理函数中使用时需要注意import logging import signal # 不安全的信号处理函数 def handle_signal(signum, frame): logging.info(Received signal %s, signum) # 可能引发死锁 # 安全的替代方案 def handle_signal_safe(signum, frame): msg Received signal {}.format(signum) logging.Handler().emit(logging.LogRecord( name__name__, levellogging.INFO, pathname__file__, lineno0, msgmsg, argsNone, exc_infoNone )) signal.signal(signal.SIGINT, handle_signal_safe)9. 常见问题与解决方案9.1 日志重复输出问题原因多次添加handler导致 解决方案# 在添加handler前先移除现有handler logger.handlers.clear() logger.addHandler(handler) # 或者检查是否已有handler if not logger.handlers: logger.addHandler(handler)9.2 日志不输出问题检查步骤确认logger的级别设置确认handler的级别设置确认handler是否添加到logger确认formatter是否正确设置9.3 多进程日志问题在多进程环境下基本的FileHandler会导致日志混乱。解决方案from logging.handlers import QueueHandler, QueueListener import multiprocessing def worker_process(queue): # 所有日志通过QueueHandler发送到主进程 qh QueueHandler(queue) logger logging.getLogger() logger.addHandler(qh) logger.setLevel(logging.INFO) logger.info(Message from worker) def main(): queue multiprocessing.Queue() # 主进程设置QueueListener处理所有日志 handler logging.FileHandler(multiprocess.log) listener QueueListener(queue, handler) listener.start() processes [] for i in range(3): p multiprocessing.Process(targetworker_process, args(queue,)) processes.append(p) p.start() for p in processes: p.join() listener.stop() if __name__ __main__: main()10. 实际项目中的日志策略10.1 开发环境与生产环境配置建议根据环境使用不同的日志配置import logging import sys def setup_logging(envdev): logger logging.getLogger() logger.setLevel(logging.DEBUG) if env dev: # 开发环境详细日志输出到控制台 handler logging.StreamHandler(sys.stdout) formatter logging.Formatter( %(asctime)s - %(name)s - %(levelname)s - %(message)s ) handler.setFormatter(formatter) else: # 生产环境关键日志输出到文件并按日轮转 from logging.handlers import TimedRotatingFileHandler handler TimedRotatingFileHandler( app.log, whenmidnight, backupCount7 ) formatter logging.Formatter( %(asctime)s - %(levelname)s - %(message)s ) handler.setFormatter(formatter) handler.setLevel(logging.INFO) logger.addHandler(handler)10.2 结构化日志对于需要日志分析的系统建议使用JSON格式import json import logging class JsonFormatter(logging.Formatter): def format(self, record): log_record { timestamp: self.formatTime(record), level: record.levelname, message: record.getMessage(), logger: record.name, module: record.module, function: record.funcName, line: record.lineno, } if record.exc_info: log_record[exception] self.formatException(record.exc_info) return json.dumps(log_record) # 使用示例 handler logging.StreamHandler() handler.setFormatter(JsonFormatter()) logger.addHandler(handler)10.3 审计日志对于需要记录用户操作的场景audit_logger logging.getLogger(audit) audit_logger.propagate False # 避免被root logger处理 audit_handler logging.FileHandler(audit.log) audit_formatter logging.Formatter( %(asctime)s %(user)s %(action)s %(status)s %(details)s ) audit_handler.setFormatter(audit_formatter) audit_logger.addHandler(audit_handler) # 记录审计日志 def log_audit_event(user, action, status, detailsNone): extra { user: user, action: action, status: status, details: details or } audit_logger.info(, extraextra)11. 测试中的日志处理11.1 单元测试中的日志验证可以使用MemoryHandler捕获日志进行验证import logging import unittest from io import StringIO class TestLogging(unittest.TestCase): def setUp(self): self.log_stream StringIO() handler logging.StreamHandler(self.log_stream) handler.setFormatter(logging.Formatter(%(levelname)s:%(message)s)) self.logger logging.getLogger(test) self.logger.addHandler(handler) self.logger.setLevel(logging.INFO) def test_log_output(self): self.logger.info(Test message) log_content self.log_stream.getvalue() self.assertIn(INFO:Test message, log_content)11.2 模拟日志记录使用unittest.mock可以模拟日志记录from unittest.mock import patch class TestWithMockLogging(unittest.TestCase): patch(logging.getLogger) def test_logging(self, mock_get_logger): mock_logger mock_get_logger.return_value # 测试代码 some_function_that_logs() # 验证日志调用 mock_logger.info.assert_called_with(Expected message)12. 与其他日志系统集成12.1 与系统日志集成在Linux系统上可以输出到syslogfrom logging.handlers import SysLogHandler syslog_handler SysLogHandler(address/dev/log) syslog_handler.setFormatter(logging.Formatter(%(name)s: %(message)s)) logger.addHandler(syslog_handler)12.2 与日志收集系统集成对于ELK、Splunk等日志收集系统可以使用相应的Handler# 示例使用HTTPHandler发送日志到Logstash from logging.handlers import HTTPHandler http_handler HTTPHandler( logstash.example.com:8080, /log, methodPOST ) logger.addHandler(http_handler)13. 自定义日志级别虽然不推荐但可以添加自定义日志级别TRACE 5 logging.addLevelName(TRACE, TRACE) def trace(self, message, *args, **kwargs): if self.isEnabledFor(TRACE): self._log(TRACE, message, args, **kwargs) logging.Logger.trace trace # 使用 logger.setLevel(TRACE) logger.trace(Very detailed trace message)14. 性能关键代码的日志优化对于性能敏感的代码可以使用延迟日志记录class LazyMessage: def __init__(self, func, *args, **kwargs): self.func func self.args args self.kwargs kwargs def __str__(self): return str(self.func(*self.args, **self.kwargs)) def expensive_operation(): # 模拟耗时操作 import time time.sleep(1) return Result # 只有在日志级别足够时才会调用expensive_operation logger.debug(Result: %s, LazyMessage(expensive_operation))15. 日志文件管理策略15.1 按时间轮转from logging.handlers import TimedRotatingFileHandler handler TimedRotatingFileHandler( app.log, whenmidnight, # 每天轮转 interval1, backupCount7 # 保留7天 )15.2 按大小轮转from logging.handlers import RotatingFileHandler handler RotatingFileHandler( app.log, maxBytes10*1024*1024, # 10MB backupCount5 )15.3 压缩旧日志import gzip import os from logging.handlers import RotatingFileHandler class CompressedRotatingFileHandler(RotatingFileHandler): def doRollover(self): super().doRollover() # 压缩除当前日志外的文件 for i in range(1, self.backupCount 1): logname f{self.baseFilename}.{i} if os.path.exists(logname): with open(logname, rb) as f_in: with gzip.open(f{logname}.gz, wb) as f_out: f_out.writelines(f_in) os.remove(logname)

相关新闻

如何快速解决Reloaded-II游戏路径错误:3步搞定Mod管理器配置

如何快速解决Reloaded-II游戏路径错误:3步搞定Mod管理器配置

如何快速解决Reloaded-II游戏路径错误:3步搞定Mod管理器配置 【免费下载链接】Reloaded-II Universal .NET Core Powered Modding Framework for any Native Game X86, X64. 项目地址: https://gitcode.com/gh_mirrors/re/Reloaded-II Reloaded-II是一款强大…

2026/7/19 21:42:42阅读更多 →
Android开发知识体系构建与高效笔记实践

Android开发知识体系构建与高效笔记实践

1. 项目概述:Android开发者的知识沉淀与体系重构"Android群英传笔记"这个标题让我想起了当年刚入行时整理的第一个知识库。这不仅仅是一份技术笔记,更是一个Android开发者从碎片化学习到系统化沉淀的成长轨迹。标题中"温故而知新"和…

2026/7/19 21:42:42阅读更多 →
QGimbal云台PID控制与目标跟踪算法实战指南

QGimbal云台PID控制与目标跟踪算法实战指南

最近在准备电子设计竞赛的同学应该对QGimbal云台不陌生,作为25年E题的核心设备,很多队伍都在实际测试中取得了接近满分的成绩。本文将基于实测经验,完整拆解QGimbal云台从硬件选型到算法调参的全流程,手把手带你实现稳定跟踪和精准…

2026/7/19 21:40:42阅读更多 →
验证码轰炸攻击防御与账户安全防护指南

验证码轰炸攻击防御与账户安全防护指南

1. 验证码轰炸背后的黑色产业链那天凌晨3点,我的手机突然连续震动十几下。睡眼惺忪地解锁屏幕,发现收件箱里塞满了来自各大平台的验证码短信——美团、京东、银行APP...前后不到两分钟收到23条。这种被称为"验证码轰炸"的攻击手段,…

2026/7/20 11:43:44阅读更多 →
API隐形水印技术:高效反爬虫解决方案

API隐形水印技术:高效反爬虫解决方案

1. 为什么需要API隐形水印?在当今数据驱动的互联网环境中,API接口已经成为各类应用的核心数据通道。但随之而来的爬虫泛滥问题让无数开发者头疼不已。传统的反爬手段如IP限流、验证码、User-Agent检测等,往往治标不治本。聪明的爬虫开发者总能…

2026/7/20 11:43:44阅读更多 →
从零到一:用SkillMCP插件开发掌握CodeBuddy企业级AI实战

从零到一:用SkillMCP插件开发掌握CodeBuddy企业级AI实战

# 从零到一:用SkillMCP插件开发掌握CodeBuddy企业级AI实战在2026年,企业级AI开发已不再是“调API、套模板”的简单游戏。随着MCP(Model Context Protocol)协议成为行业标准,CodeBuddy作为集成开发环境中的AI中枢&#…

2026/7/20 11:43:44阅读更多 →
PotPlayer百度翻译插件终极指南:3步实现外语字幕实时翻译的完整教程

PotPlayer百度翻译插件终极指南:3步实现外语字幕实时翻译的完整教程

PotPlayer百度翻译插件终极指南:3步实现外语字幕实时翻译的完整教程 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 还在为…

2026/7/20 11:43:44阅读更多 →
量化交易入门:成熟策略与风控体系助你实现稳定收益

量化交易入门:成熟策略与风控体系助你实现稳定收益

# 量化交易入门:成熟策略与风控体系助你实现稳定收益## 引言在金融市场中,量化交易早已不再是华尔街的专属。随着开源工具和云计算的普及,个人投资者也能搭建属于自己的量化系统。但大多数入门者面临的困境是:**策略回测漂亮&…

2026/7/20 11:43:43阅读更多 →
Gemini Advanced订阅值不值得?实测12项专业任务耗时/准确率/成本三维对比(附独家配置模板)

Gemini Advanced订阅值不值得?实测12项专业任务耗时/准确率/成本三维对比(附独家配置模板)

更多请点击: https://codechina.net 第一章:Gemini Advanced订阅值不值得?实测12项专业任务耗时/准确率/成本三维对比(附独家配置模板) 为验证Gemini Advanced($19.99/月)在真实工作流中的投入…

2026/7/20 11:41:40阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/20 0:50:54阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/20 0:50:54阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/20 0:50:54阅读更多 →
2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

7月18日智东西消息,在2026 WAIC期间,努比亚联合字节豆包打造的二代“豆包手机”努比亚NaviX Ultra首次亮相,相比一代有诸多升级。智能体手机理念中兴通讯终端事业部总裁、努比亚总裁倪飞表示,智能体手机要从人操作手机变为手机帮人…

2026/7/20 0:01:04阅读更多 →
努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra:外观与功能双升级在2026 WAIC期间,首次亮相的努比亚NaviX Ultra吸引了众多目光。它是努比亚联合字节豆包打造的二代“豆包手机”,与一代努比亚M153相比,外观设计变化较大。其机身背部搭载横向排布的大尺寸影像模…

2026/7/20 0:01:04阅读更多 →
C# 将逗号分割的字符串转换为long,并添加到List<long>

C# 将逗号分割的字符串转换为long,并添加到List<long>

目录 方法1:使用Split和Convert.ToInt64 方法2:使用LINQ的Select和ToList 方法3:使用TryParse进行异常安全转换(推荐) 如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天…

2026/7/20 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/19 22:50:49阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/19 18:50:36阅读更多 →