这时代码执行崩溃了
C:Python37liblogging__init__.py:894: RuntimeWarning: coroutine 'CustomHandler.emit' was never awaited self.emit(record)RuntimeWarning: Enable tracemalloc to get the object allocation traceback
服务端也没有收到发送日志的请求 。
究其原因是由于emit方法中使用async with session.post 函数,它需要在一个使用async 修饰的函数里执行,所以修改emit函数,使用async来修饰,这里emit函数变成了异步的函数, 返回的是一个coroutine 对象,要想执行coroutine对象,需要使用await, 但是脚本里却没有在哪里调用 await emit() ,所以崩溃信息中显示coroutine 'CustomHandler.emit' was never awaited.
既然emit方法返回的是一个coroutine对象,那么我们将它放一个loop中执行
async def main(): await logger.debug("今天天气不错") await logger.debug("是风和日丽的")loop = asyncio.get_event_loop()loop.run_until_complete(main())
执行依然报错
raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
意思是需要的是一个coroutine,但是传进来的对象不是 。
这似乎就没有办法了 , 想要使用异步库来发送 , 但是却没有可以调用await的地方.
解决办法是有的,我们使用 asyncio.get_event_loop() 获取一个事件循环对象, 我们可以在这个对象上注册很多协程对象,这样当执行事件循环的时候,就是去执行注册在该事件循环上的协程, 我们通过一个小例子来看一下
import asyncio async def test(n): while n > 0: await asyncio.sleep(1) print("test {}".format(n)) n -= 1 return n async def test2(n): while n >0: await asyncio.sleep(1) print("test2 {}".format(n)) n -= 1def stoploop(task): print("执行结束, task n is {}".format(task.result())) loop.stop()loop = asyncio.get_event_loop()task = loop.create_task(test(5))task2 = loop.create_task(test2(3))task.add_done_callback(stoploop)task2 = loop.create_task(test2(3))loop.run_forever()
我们使用loop = asyncio.get_event_loop() 创建了一个事件循环对象loop, 并且在loop上创建了两个task, 并且给task1添加了一个回调函数,在task1它执行结束以后,将loop停掉.
注意看上面的代码,我们并没有在某处使用await来执行协程,而是通过将协程注册到某个事件循环对象上,然后调用该循环的run_forever() 函数,从而使该循环上的协程对象得以正常的执行.
上面得到的输出为
test 5test2 3test 4test2 2test 3test2 1test 2test 1执行结束, task n is 0
可以看到,使用事件循环对象创建的task,在该循环执行run_forever() 以后就可以执行了.
如果不执行loop.run_forever() 函数,则注册在它上面的协程也不会执行
loop = asyncio.get_event_loop()task = loop.create_task(test(5))task.add_done_callback(stoploop)task2 = loop.create_task(test2(3))time.sleep(5)# loop.run_forever()
上面的代码将loop.run_forever() 注释掉,换成time.sleep(5) 停5秒, 这时脚本不会有任何输出,在停了5秒以后就中止了.
回到之前的日志发送远程服务器的代码,我们可以使用aiohttp封装一个发送数据的函数, 然后在emit中将这个函数注册到全局的事件循环对象loop中,最后再执行loop.run_forever() .
loop = asyncio.get_event_loop()class CustomHandler(logging.Handler): def __init__(self, host, uri, method="POST"): logging.Handler.__init__(self) self.url = "%s/%s" % (host, uri) method = method.upper() if method not in ["GET", "POST"]: raise ValueError("method must be GET or POST") self.method = method # 使用aiohttp封装发送数据函数 async def submit(self, data): timeout = aiohttp.ClientTimeout(total=6) if self.method == "GET": if self.url.find("?") >= 0: sep = '&' else: sep = '?' url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log": data})) async with aiohttp.ClientSession(timeout=timeout) as session: async with session.get(url) as resp: print(await resp.text()) else: headers = { "Content-type": "application/x-www-form-urlencoded", } async with aiohttp.ClientSession(timeout=timeout, headers=headers) as session: async with session.post(self.url, data=https://www.isolves.com/it/cxkf/yy/Python/2020-09-25/{'log': data}) as resp: print(await resp.text()) return True def emit(self, record): msg = self.format(record) loop.create_task(self.submit(msg))# 添加一个httphandlerhttp_handler = CustomHandler(r"http://127.0.0.1:1987", 'api/log/get')http_handler.setLevel(logging.DEBUG)http_handler.setFormatter(fmt)logger.addHandler(http_handler)logger.debug("今天天气不错")logger.debug("是风和日丽的")loop.run_forever()
推荐阅读
- 金骏眉是红茶还是绿茶,骏眉中国之大叶金粹红茶贵州普安大叶种红茶
- Python爬虫案例:爬取微信公众号文章
- 神经网络中的蒸馏技术,从Softmax开始说起
- 一行代码让你的python运行速度提高100倍
- 正史中的关羽真有这么厉害吗 关羽是哪部作品的人物
- 浅谈 React 中的 XSS 攻击
- 抖一中是什么梗?
- 中型犬不掉毛无体味的狗排名如何?
- 为什么有的国家车辆靠左行驶 中国车辆靠左行驶还是靠右行驶
- 三国干涉还辽中的三国指的是