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。
答案 0 :(得分:4)
问题是您的自定义日志记录格式,您期望%(task)
。
请求(或者更确切地说是捆绑的urllib3)在记录时不包括task
参数,因为它无法知道您希望这样做。
答案 1 :(得分:1)
如t-8ch的answer所示,记录器正由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
条目。我为你提供的代码添加了最简单的解决方案 - 不再发生异常 - 但是各种各样的可能性似乎很明显;)