使用aiohttp.ClientSession()发出请求时如何设置aiohttp.client的日志记录?

时间:2017-08-09 09:19:37

标签: python python-3.x python-3.5 python-asyncio aiohttp

我有一些代码向某些API发出请求序列。我想为所有人设置通用日志记录,我该如何设置它?

假设我的代码看起来像这样

import aiohttp
import asyncio

async def fetch(client):
    async with client.get('http://httpbin.org/get') as resp:
        assert resp.status == 200
        return await resp.text()

async def post_data(client):
    async with client.post('http://httpbin.org/post', data={'foo': 'bar'}) as resp:
        assert resp.status == 200
        return await resp.text()

async def main(loop):
    async with aiohttp.ClientSession(loop=loop) as client:
        html = await fetch(client)
        print(html)
        other_html = await post_data(client)
        print(other_html)

loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))

现在我想查看所有请求的状态代码,网址,标题和所有请求,因此日志中的输出如下所示:

2017-08-09 08:44:30 DEBUG (200) <GET http://httpbin.org/get>
2017-08-09 08:44:30 DEBUG (200) <POST http://httpbin.org/post>

我知道我可以在每次请求后添加logger.log()调用,但这将是重复的。如果我有更多请求,我将不得不在调用logger.log的每个请求下编写重复的代码。似乎效率低下。

aiohttp.client logger,但没有详细说明如何设置它。

我正试图像这样设置

logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
logging.getLogger('aiohttp.client').addHandler(ch)

但它不会打印我想看到的信息(例如响应状态代码,网址)。

有没有办法达到我的需要?也许我可以从客户端订阅一些信号并在发送信号时记录一些消息?例如。有一些机制来订阅当客户端收到响应时发送的信号,然后记录消息吗?

2 个答案:

答案 0 :(得分:6)

正如您在aiohttp的代码中看到的那样,aiohttp.client记录器不用于记录请求,但只有在响应中的cookie无效时才能记录警告 https://github.com/aio-libs/aiohttp/search?utf8=%E2%9C%93&q=client_logger&type=

要记录您正在执行的每个请求,您需要创建一个符合您需要的自定义ClientSession。类似的东西:

class LoggingClientSession(aiohttp.ClientSession):
    def request(self, method, url, **kwargs):
        logger.debug('Starting request <%s %r>', method, url)
        return super().request(method, url, **kwargs)

-

Jaanus在此处的评论中指出,postget,...帮助者直接知道调用ClientSession._request,而不是request。因此,覆盖后者将不会拦截使用短手助手进行的呼叫。

所以你可以:

  • 在助手中覆盖_request而不是request

  • 或确保您的代码永远不会使用get / ...帮助程序,并始终直接调用request

  • 或定义LoggingClientSession

  • 中的所有辅助方法

-

正如Romuald所指出的,_request现在是一个协程,所以用常规函数覆盖它不会在正确的时间记录。这是一个更新的例子:

class LoggingClientSession(aiohttp.ClientSession):
    async def _request(self, method, url, **kwargs):
        logger.debug('Starting request <%s %r>', method, url)
        return await super()._request(method, url, **kwargs)

答案 1 :(得分:0)

在撰写本文时(2020年11月11日),您应该使用tracing functionality of aiohttp

schema_view = get_schema_view(
    openapi.Info(
       title="Your API",
       default_version='v1',
       description="Your description",
    ),
    public=True,
    generator_class=MyOpenAPISchemaGenerator, # <--- Don't forget this
    permission_classes=[permissions.AllowAny],
)