核心内容摘要
ZOO嘼与人:一段跨越物种的深情对望
原文towardsdatascience.com/log-breadcrumbs-only-show-logs-leading-up-to-an-error-82b9f4c15520https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a40ff83722411f873098d942f36a
png图片由 Daniel Tseng / Unsplash 提供在这篇文章中我们将探讨一种高效记录日志碎片的途径只显示导致错误的日志。
我们将仅使用 Python 的标准日志库来创建一个高效的日志设置仅在发生异常时捕获调试日志。
这种方法提供了对导致问题的步骤的详细视图同时减少混乱和最小化 I/O。
让我们开始编码为什么记录日志碎片当发生错误时你希望尽可能多地拥有信息以便引导你找到代码中的问题。
记录大量信息在这方面非常有用。
坏处是所有这些日志都需要被处理。
然后需要将它们写入文件或通过 HTTP 发送到端点这可能会影响你的应用程序或服务器的性能。
此外它可能会使日志变得混乱使得在发生错误时更难找到相关信息。
面包屑方法“忽略”例如所有debug日志除非发生错误。
这允许你记录大量关于错误的详细信息同时保持性能和概览在水平。
设置面包屑路径下面是一个简单的函数divide其中包含帮助跟踪其内部行为的调试日志。
理想情况下我们不想每次都看到日志只想在发生错误时看到这样我们就可以看到函数尝试除以哪两个数字。
defdivide(a,b):logger.debug(fDividing [{a}] by [{b}])returna/bforvaluein[1,2,3,4,5,6,7,8,9,not a number,0]:try:logger.debug(fstart dividing..)resdivide(a10,bvalue)exceptExceptionase:logger.error(f❌An exception occurred:{e})前几个值1到9成功进行了除法运算在这些情况下通常不需要调试日志。
然而对于像not a number和0这样的错误输入捕获debug日志会提供有价值的上下文。
我们的。
我们如何回到过去检索日志用一行代码将你的 Python 函数转换为装饰器解决方案概述要创建面包屑我们将配置我们的日志记录器以使用两个处理器StreamHandler仅显示INFO级别及以上的消息MemoryHandler临时存储DEBUG消息并在发生错误时将它们传递给StreamHandler此设置不会显示DEBUG日志因为 StreamHandler 被设置为INFO。
我们可以临时将DEBUG消息存储在 MemoryHandler 中当我们检测到错误时将消息刷新到 StreamHandler。
然后它将显示存储的DEBUG消息。
配置日志记录器下面是如何使用StreamHandler进行常规输出和MemoryHandler进行缓冲DEBUG日志来配置记录器的示例importloggingfromlogging.handlersimportMemoryHandler# Create logger and formatter for a structured log messageloggerlogging.getLogger(my_logger)formatterlogging.Formatter(fmt%(levelname)-7s ⏱️%(asctime)s %(funcName)12s:%(lineno)-2s %(message)s,datefmt%H:%M:%S)# Configure stream handlerstream_handlerlogging.StreamHandler()stream_handler.setLevel(logging.INFO)# Only INFO and above will be displayedstream_handler.setFormatter(formatter)logger.addHandler(stream_handler)# Configure memory handlermemory_handlerMemoryHandler(capacity100,targetstream_handler,flushLevellogging.ERROR)memory_handler.setFormatter(formatter)logger.addHandler(memory_handler)在上述设置中MemoryHandler可以缓冲最多 100 条日志条目。
如果发生错误我们可以从MemoryHandler刷新日志到StreamHandler从而得到完整的线索路径。
如何仅用 77MB 使用 Python Bloom 过滤器存储和查询 1 亿项数据在代码中使用面包屑记录器下面是配置好的新日志记录器的演示。
注意finally块我们在每次尝试后清除缓冲区以保持针对每个操作的特定调试日志。
defdivide(a,b):logger.debug(fDividing [{a}] by [{b}])returna/bforvaluein[1,2,3,4,5,6,7,8,9,not a number,0]:try:logger.debug(Start dividing..)resdivide(a10,bvalue)exceptExceptionase:logger.error(f❌ An exception occurred:{e})finally:memory_handler.buffer.clear()# Clear memory after each pass直到not a number我们不会看到任何日志因为所有前面的值执行时都没有错误。
然而当我们处理not a number时divide函数会抛出异常因为我们不能将整数除以字符串。
我们最终进入except块并记录一个ERROR。
我们已将MemoryHandler配置为在遇到ERROR时将所有缓冲日志刷新到StreamHandler这正是本例中将要发生的事情。
最后我们在finally块中清除缓冲区以便在开始处理not a number时删除9的DEBUG日志。
样本输出当我们运行最终代码时只有错误情况的日志会显示调试信息作为线索。
以下是完整输出的样子# Logs corresponding to not a numberERROR ⏱️17:07:03 main:44 ❌ An exception occurred:unsupported operandtype(s)for/:intandstrDEBUG ⏱️17:07:03 main:41 Start dividing..DEBUG ⏱️17:07:03 divide:32 Dividing[10]by[nota number]# Logs corresponding to 0ERROR ⏱️17:07:03 main:44 ❌ An exception occurred:division by zero DEBUG ⏱️17:07:03 main:41 Start dividing..DEBUG ⏱️17:07:03 divide:32 Dividing[10]by[0]在这些示例中MemoryHandler仅在遇到错误时捕获和刷新调试日志提供了一个清晰的线索路径提供了关于错误的有价值信息。
用两行代码应用 Python 多进程结论通过这种设置我们通过缓冲调试日志并仅在遇到错误时显示它们实现了更精简的日志记录过程。
这种面包屑式的方法对于性能和日志量管理至关重要的应用程序来说非常理想。
MemoryHandler为我们提供了两全其美的解决方案当我们需要时提供详细的跟踪当我们不需要时最小化日志量。
希望这篇文章和我希望的一样清晰如果不是这样请告诉我我可以做些什么来进一步澄清。
同时查看我关于各种编程相关主题的**其他文章**。
开心编码— MikeP.s: 喜欢我在做的事情吗关注我