在一个上下文中禁用 python 模块的日志记录,但在另一个上下文中禁用

2024-04-19

我有一些代码使用requests与日志 API 进行通信的模块。然而,requests本身,通过urllib3,进行日志记录。当然,我需要禁用日志记录,以便对日志记录 API 的请求不会导致日志无限循环。所以,在我进行日志记录调用的模块中,我做logging.getLogger("requests").setLevel(logging.CRITICAL)使例行请求日志静音。

但是,此代码旨在加载并运行任意用户代码。自从有了蟒蛇logging模块显然使用全局状态来管理给定记录器的设置,我担心用户的代码可能会重新打开日志记录并导致问题,例如,如果他们天真地在代码中使用请求模块,而没有意识到我已经禁用了它的日志记录原因。

当从我的代码上下文执行请求模块时,如何禁用该模块的日志记录,但从用户的角度来看,不影响模块记录器的状态?某种类型的上下文管理器可以使管理器内代码的日志记录调用保持沉默,这将是理想的选择。能够使用独特的方式加载请求模块__name__因此记录器使用不同的名称也可以工作,尽管有点复杂。不过,我找不到办法做这两件事。

遗憾的是,该解决方案需要处理多个线程,因此按程序关闭日志记录,然后运行 ​​API 调用,然后重新打开它将不起作用,因为全局状态已发生变化。


我想我已经为你找到了一个解决方案:

The logging模块是构建为线程安全的 https://docs.python.org/2/library/logging.html#thread-safety:

日志记录模块的目的是线程安全没有任何特殊的 需要由客户完成的工作。它通过使用实现了这一点 螺纹锁;有一个锁可以序列化对模块的访问 共享数据,以及每个处理程序还创建一个锁序列化访问 到其底层 I/O。

幸运的是,它通过公共 API 公开了提到的第二个锁:Handler.acquire() https://docs.python.org/2/library/logging.html#logging.Handler.acquire让您获取特定日志处理程序的锁(并且Handler.release() https://docs.python.org/2/library/logging.html#logging.Handler.release再次释放)。获取该锁将阻止所有其他尝试记录将由该处理程序处理的记录的线程,直到锁被释放。

这允许您以线程安全的方式操纵处理程序的状态。需要注意的是:因为它的目的是作为处理程序 I/O 操作的锁,所以该锁只能在emit()。因此,只有当一条记录通过过滤器和日志级别并由特定处理程序发出时,才会获取锁。这就是为什么我必须子类化处理程序并创建SilencableHandler.

所以想法是这样的:

  • 获取最顶层的记录器requests模块并停止其传播
  • 创建您的定制SilencableHandler并将其添加到请求记录器中
  • Use the Silenced上下文管理器有选择地沉默SilencableHandler

main.py

from Queue import Queue
from threading import Thread
from usercode import fetch_url
import logging
import requests
import time


logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)


class SilencableHandler(logging.StreamHandler):

    def __init__(self, *args, **kwargs):
        self.silenced = False
        return super(SilencableHandler, self).__init__(*args, **kwargs)

    def emit(self, record):
        if not self.silenced:
            super(SilencableHandler, self).emit(record)


requests_logger = logging.getLogger('requests')
requests_logger.propagate = False
requests_handler = SilencableHandler()
requests_logger.addHandler(requests_handler)


class Silenced(object):

    def __init__(self, handler):
        self.handler = handler

    def __enter__(self):
        log.info("Silencing requests logger...")
        self.handler.acquire()
        self.handler.silenced = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.handler.silenced = False
        self.handler.release()
        log.info("Requests logger unsilenced.")


NUM_THREADS = 2
queue = Queue()

URLS = [
    'http://www.stackoverflow.com',
    'http://www.stackexchange.com',
    'http://www.serverfault.com',
    'http://www.superuser.com',
    'http://travel.stackexchange.com',
]


for i in range(NUM_THREADS):
    worker = Thread(target=fetch_url, args=(i, queue,))
    worker.setDaemon(True)
    worker.start()

for url in URLS:
    queue.put(url)


log.info('Starting long API request...')

with Silenced(requests_handler):
    time.sleep(5)
    requests.get('http://www.example.org/api')
    time.sleep(5)
    log.info('Done with long API request.')

queue.join()

usercode.py

import logging
import requests
import time


logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)


def fetch_url(i, q):
    while True:
        url = q.get()
        response = requests.get(url)
        logging.info("{}: {}".format(response.status_code, url))
        time.sleep(i + 2)
        q.task_done()

输出示例:

(注意如何调用http://www.example.org/api未记录,并且所有尝试记录请求的线程都会在前 10 秒内被阻止)。

INFO:__main__:Starting long API request...
INFO:__main__:Silencing requests logger...
INFO:__main__:Requests logger unsilenced.
INFO:__main__:Done with long API request.
Starting new HTTP connection (1): www.stackoverflow.com
Starting new HTTP connection (1): www.stackexchange.com
Starting new HTTP connection (1): stackexchange.com
Starting new HTTP connection (1): stackoverflow.com
INFO:root:200: http://www.stackexchange.com
INFO:root:200: http://www.stackoverflow.com
Starting new HTTP connection (1): www.serverfault.com
Starting new HTTP connection (1): serverfault.com
INFO:root:200: http://www.serverfault.com
Starting new HTTP connection (1): www.superuser.com
Starting new HTTP connection (1): superuser.com
INFO:root:200: http://www.superuser.com
Starting new HTTP connection (1): travel.stackexchange.com
INFO:root:200: http://travel.stackexchange.com

线程代码基于 Doug Hellmann 的文章线程 http://pymotw.com/2/threading/ and queues http://pymotw.com/2/Queue/index.html#module-Queue.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在一个上下文中禁用 python 模块的日志记录,但在另一个上下文中禁用 的相关文章

  • 在Python中解析空选项

    我有一个应用程序 允许您将事件数据发送到自定义脚本 您只需布置命令行参数并指定什么事件数据与什么参数相匹配 问题是这里没有真正的灵活性 您制定的每个选项都将被使用 但并非每个选项都必须有数据 因此 当应用程序构建要发送到脚本的字符串时 某些
  • 将 python scikit learn 模型导出到 pmml

    我想将 python scikit learn 模型导出到 PMML 中 什么 python 包最适合 我读到Augustus https github com opendatagroup augustus 但我找不到任何使用 scikit
  • 如何在 for 循环中跳过一些迭代

    在 python 中 我通常简单地循环遍历范围 for i in range 100 do something 但现在我想跳过循环中的几个步骤 更具体地说 我想要类似的东西continue 10 这样它就会跳过整个循环并将计数器增加 10
  • Python中的键盘可中断阻塞队列

    It seems import Queue Queue Queue get timeout 10 键盘可中断 ctrl c 而 import Queue Queue Queue get 不是 我总是可以创建一个循环 import Queue
  • 在 python 中返回 self [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个代表对象的类 我有很多方法可以修改这个对象状态 没有明显的返回或显然没有任何返回 在 C 中 我会将所有这些方法声明为void
  • python 正则表达式中括号的奇怪行为

    我正在编写一个 python 正则表达式 它可以在文本文档中查找引用的字符串 从黑匣子中记录的航空公司飞行员的引用 我首先尝试编写具有以下规则的正则表达式 返回引号之间的内容 如果以 single 打开 则仅在以 single 关闭时返回
  • 如何从 python 脚本更改 python 文件中的变量值

    我目前有一个 python 文件 其中包含一堆带有值的全局变量 我想从一个单独的 python 脚本永久更改这些值 我尝试过 setattr 等 但似乎不起作用 有没有办法做到这一点 简短的回答是 不 不值得这么麻烦 听起来您正在尝试创建一
  • 多级QTreeView

    我很难理解如何使用 QTreeView 和 QStandardItemModel 设置多级 QTree 这是我所拥有的 from PySide QtGui import import sys class MainFrame QWidget
  • scipy 的 curve_fit 函数的尺寸问题

    我对 python 中的曲线拟合以及一般的 python 都很陌生 目前 我正在尝试使用 scipy 中的 curve fit 模块来拟合 4 个光谱峰 简而言之 我的文本文件中有两列数据 所以我的第一步是将数据导入到两个数组中 一个包含
  • Python lmfit:拟合 2D 模型

    我正在尝试将二维高斯拟合到一些灰度图像数据 该数据由一个二维数组给出 lmfit 库实现了一个易于使用的模型类 它应该能够做到这一点 不幸的是文档 http lmfit github io lmfit py model html http
  • 使用底图和Python在地图中绘制海洋

    我正在绘制此处提供的 netCDF 文件 https goo gl QyUI4J https goo gl QyUI4J Using the code below the map looks like this 然而 我希望海洋是白色的 更
  • 让垂直网格线出现在 matplotlib 的线图中

    我想在绘图上同时获得水平和垂直网格线 但默认情况下仅显示水平网格线 我正在使用一个pandas DataFrame从 python 中的 sql 查询生成 x 轴上带有日期的线图 我不知道为什么它们没有出现在日期上 我试图寻找这个问题的答案
  • 结束一天(日期时间)的最优雅的方式是什么?

    我目前正在编写一些报告代码 允许用户选择指定日期范围 它的工作方式 简化 是 用户 可选 指定年份 用户 可选 指定月份 用户 可选 指定一天 这是一个代码片段 以及描述我想要的内容的注释like to do from datetime i
  • 传递宏作为参数 jinja dbt

    Today date milliseconds 是我在项目中的宏 如何将此宏重定向为参数 以便默认情况下我可以在 yml 中编写另一个宏 test valid date model column name exclude condition
  • 分别计算男女宿舍

    我想要的结果是这样的 males 1990 Q1 value Q2 value Q3 Value Q4 Value females Q1 value Q2 value Q3 Value Q4 value 如果任何值不存在则默认值 0 imp
  • 对二进制数的字符串表示进行按位运算 python 2.7

    我想对二进制数的两个字符串表示执行按位或 但我不知道如何将字符串转换为原始二进制 a 010110 b 100000 a b 应该产生 110110 然后我想计算 on 位的数量 这应该返回 4 您可以使用内置的将字符串转换为二进制int
  • 帮助我在 Python 中实现反向传播

    EDIT2 新的训练集 Inputs 0 0 0 0 0 0 1 0 0 0 2 0 0 0 3 0 0 0 4 0 1 0 0 0 1 0 1 0 1 0 2 0 1 0 3 0 1 0 4 0 2 0 0 0 2 0 1 0 2 0 2
  • 如何加速Python循环

    我查看了几个网站上的一些讨论 但没有一个给我解决方案 这段代码运行时间超过5秒 for i in xrange 100000000 pass 我正在研究整数优化问题 我必须使用O n log n 算法编辑 O n 4 算法 其中n代表矩阵的
  • 保存 Jupyter Notebook,并显示 Plotly Express 小部件

    我有一个 Jupyter 笔记本 python 我使用plotlyexpress 在笔记本中绘图以进行分析 我想与非编码人员共享此笔记本 并让交互式视觉效果仍然可用 但它似乎不起作用 我尝试以下此处提出的建议 https community
  • 安装 confluence-kafka 时“文件名或扩展名太长”?

    我在使用 pip install confluence kafka 安装 confluence kafka 时遇到一些问题 但我收到此错误 文件名或扩展名太长 详细信息如下 Collecting confluent kafka Using

随机推荐

  • 导入错误:没有名为 psycopg2 的模块

    在 OpenERP 6 的安装过程中 我想使用以下命令生成一个配置文件 cd home openerp openerp server bin openerp server py s stop after init c home opener
  • windows下如何设置keytool的密码?

    我正在为 android 应用程序开发的 my hello mapview 程序添加 google maps api 参考网站 http developer android com guide tutorials views hello m
  • 我需要处置 SemaphoreSlim 吗?

    根据文档 a SemaphoreSlim不使用 Windows 内核信号量 是否有任何特殊资源被使用SemaphoreSlim这使得打电话很重要Dispose当 的时候SemaphoreSlim将不再使用 如果您访问AvailableWai
  • Java中如何正确计算字符串的长度?

    我知道有String length以及其中的各种方法Character它或多或少适用于代码单元 代码点 Java 中实际返回 Unicode 标准指定的结果的建议方法是什么 UAX 29 http www unicode org repor
  • 保持 UI 响应的 Thread.Sleep 替代方案?

    我在 Visual Studio 2008 中使用 C 完成所有这些工作 我想放慢算法的工作速度 以便用户可以观看它的工作 GUI 上有可见的周期性变化 所以我添加了Thread Sleep每次实例之后 问题是Thread Sleep 当设
  • 赋值运算符的参数必须是引用吗?

    C 中重载类的赋值运算符时 其参数必须是引用吗 例如 class MyClass public MyClass operator const MyClass rhs 是真的吗 class MyClass public MyClass ope
  • 如何在 if 语句中使用 fork()

    有人可以向我解释一下是什么吗fork 0意思是 据我了解 我认为这意味着 fork 不是 false 吗 或者如果 fork 是 true 那么 我不明白 Fork 如何是 true 或 false 因为它只是将进程的副本创建到父进程和子进
  • 根据第一列中的字母数将行与上一行连接起来

    编码新手 试图弄清楚如何修复损坏的 csv 文件 以便能够正确使用它 因此 该文件已从案例管理系统导出 并包含用户名 案例 花费时间 注释和日期字段 问题在于 偶尔注释中会有换行符 并且在导出 csv 时 工具不包含引号来将其定义为字段内的
  • 在 GUI MATLAB 中为静态文本赋值

    如何在 MATLAB GUI 中为静态文本赋值 双击指南中的文本打开属性编辑器 然后编辑 String 财产 您还可以设置 Tag 属性 以便您可以在 GUI 运行时对其进行编辑 如果您将标签设置为mytext 您可以将静态文本更改为 My
  • 如何在 Python Qt 应用程序中使用 KDE Okular 的文档视图小部件?

    我正在 Linux 上使用 Qt 4 8 和 PyQt 用 Python 3 4 编写桌面应用程序 有没有办法将 Okular 的 pdf 查看功能作为小部件使用 导入 如果是 怎么办 这对我有用 import sys from PyKDE
  • 类型错误:这不是日期对象

    知道为什么这在 Chrome 中不起作用吗 var foo new Date getDate foo 我收到一个 TypeError 这不是 Date 对象 然而 new Date getDate works 该函数在您的示例中未正确绑定
  • 使用 Google Guice 注入 java 属性

    我想使用 google guice 使属性在我的应用程序的所有类中可用 我定义了一个加载并绑定属性文件的模块测试属性 Property1 TEST Property2 25 包com test import java io FileNotF
  • GUI 中的 Matlab 缩放监听器

    我有一个 GUI 由 MATLAB 中的绘图和静态文本组成 我想在绘图上有一个缩放侦听器 以便我可以用放大倍率更新静态文本 无论如何 我可以做到这一点吗 脚本文件 或者您可以将其作为嵌套函数执行 无论您喜欢什么 f figure 1 z z
  • 通过 api 上传照片时 Foursquare 缺少文件上传/InvalidPhotoFormat 错误

    我正在尝试使用 api 将照片添加到 foursquare 页面 https api foursquare com v2 photos add https api foursquare com v2 photos add和以下node js
  • 是否可以通过 Viber API 获取消息历史记录?

    根据 API 文档 http developers viber com api rest bot api index html viber rest api http developers viber com api rest bot ap
  • PyQt 与 PySide 比较 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我目前在 Linux 上的 Qt 重型 C Python 环境中开发了许多应用程序 并根据需要移植到 PC Mac 我使用嵌入 C 中的 Pyt
  • Firebase 9(模块化 sdk web )替换 fieldPath

    我将以下代码与 Firebase SDK 8 一起使用 const db firebase firestore const collectionRef db collection collectionName var query colle
  • Vue:v-model 不适用于动态组件

    例如
  • Java中如何设置背景图片?

    我正在使用 Java 使用 BlueJ 作为 IDE 开发一个简单的平台游戏 现在 我在游戏中使用多边形和简单形状绘制了玩家 敌人精灵 平台和其他物品 最终我希望用实际图像替换它们 现在我想知道将图像 URL 或来自本地源 设置为游戏窗口
  • 在一个上下文中禁用 python 模块的日志记录,但在另一个上下文中禁用

    我有一些代码使用requests与日志 API 进行通信的模块 然而 requests本身 通过urllib3 进行日志记录 当然 我需要禁用日志记录 以便对日志记录 API 的请求不会导致日志无限循环 所以 在我进行日志记录调用的模块中