【问题标题】:Python Requests library throws exceptions in loggingPython Requests 库在日志记录中引发异常
【发布时间】:2015-01-01 18:50:51
【问题描述】:

Python requests 库在其日志记录行为方面似乎有一些相当奇怪的怪癖。 使用最新的 Python 2.7.8,我有以下代码:

import requests
import logging

logging.basicConfig(
    filename='mylog.txt',
    format='%(asctime)-19.19s|%(task)-36s|%(levelname)s:%(name)s: %(message)s',
    level=eval('logging.%s' % 'DEBUG'))

logger = logging.getLogger(__name__)

logger.info('myprogram starting up...', extra={'task': ''})     # so far so good
...
(ommited code)
...
payload = {'id': 'abc', 'status': 'ok'}

# At this point the program continues but throws an exception.
requests.get('http://localhost:9100/notify', params=payload) 

print 'Task is complete! NotifyURL was hit! - Exiting'

我的程序似乎正常退出,但是在它创建的日志文件 (mylog.txt) 中,我总是发现以下异常:

KeyError: 'task'
Logged from file connectionpool.py, line 362

如果我删除它: requests.get('http://localhost:9100/notify', params=payload) 那么异常就消失了。

我到底做错了什么,我该如何解决这个问题? 我正在使用请求 v2.4.3。

【问题讨论】:

    标签: python python-2.7 logging python-requests urllib3


    【解决方案1】:

    问题在于您的自定义日志记录格式,您希望在其中使用%(task)。 请求(或者更确切地说是捆绑的 urllib3)在记录时不包含 task 参数,因为它无法知道您期望这个。

    【讨论】:

    • 好的。我明白了。现在,我该如何解决这个问题?有没有办法让Requests 知道我的task 参数?
    • 您使用的是同步方式的请求,所以在检查请求返回值后手动记录,而不是使用自定义格式。
    【解决方案2】:

    t-8chanswer 所示,requests 库在内部使用记录器,而该库对您的参数一无所知。一种可能的解决方案是在库的记录器(在这种情况下,它的一个模块)中植入custom filter

    class TaskAddingFilter(logging.Filter):
        def __init__(self):
            logging.Filter.__init__(self)
    
        def filter(self, record):
            record.args = record.args + ('task', '')
    
    # ...
    
    requestsLogger = logging.getLogger('requests.packages.urllib3.connectionpool')
    requestsLogger.addFilter(TaskAddingFilter())
    

    可能,您需要将此类过滤添加到来自requests 的所有记录器,它们是:

    • requests.packages.urllib3.util
    • requests.packages.urllib3.connectionpool
    • requests.packages
    • requests.packages.urllib3
    • requests.packages.urllib3.util.retry
    • requests
    • requests.packages.urllib3.poolmanager

    在我的版本中,您可以使用logging.Logger.manager.loggerDict 属性找到它们。所以,你可以这样做:

    for name,logger in logging.Logger.manager.loggerDict.iteritems():
        logger = logging.getLogger(name) # because of lazy initialization
        if name.startswith('requests.'):
            logger.addFilter(TaskAddingFilter())
    

    TaskAddingFilter 当然可以更聪明一些,例如根据您在代码中的位置添加特定的 task 条目。我只为您提供的代码添加了最简单的解决方案 - 异常不再发生 - 但各种可能性似乎很明显;)

    【讨论】:

    • 谢谢。这正是我所需要的。
    猜你喜欢
    • 1970-01-01
    • 2011-10-23
    • 2020-12-31
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多