我在许多关于堆栈溢出的文章中提到过,如果没有配置日志记录,默认情况下discord.py会“隐藏错误”。在文档中,有人提到:
强烈建议配置日志模块,因为如果不设置,则不会输出错误或警告。重点雷
但是,在discord.py 1.7.3中,我观察到错误被输出到控制台。运行以下代码片段:
import discord
client = discord.Client(intents=discord.Intents.all())
@client.event
async def on_ready():
raise ValueError
client.run(TOKEN)
正确地引发ValueError
-错误不会被吞没。
在discord.py 2.0中,已经设置了日志记录,输出(具有相同的代码片段)就证明了这一点:
[2022-07-15 12:28:40] [INFO ] discord.client: logging in using static token
[2022-07-15 12:28:41] [INFO ] discord.gateway: Shard ID None has sent the IDENTIFY payload.
[2022-07-15 12:28:41] [INFO ] discord.gateway: Shard ID None has connected to Gateway (Session ID: ...).
[2022-07-15 12:28:43] [ERROR ] discord.client: Ignoring exception in on_ready
# ^-----------------^ These lines are all from the logging module
Traceback (most recent call last):
File "C:\Users\TheFu\PycharmProjects\mcve2.0\venv\lib\site-packages\discord\client.py", line 456, in _run_event
await coro(*args, **kwargs)
File "C:\Users\TheFu\PycharmProjects\mcve2.0\main.py", line 8, in on_ready
raise ValueError
ValueError
那么,如果没有在discord.py 1.7.3中设置日志记录,那么为什么输出一个错误呢?在这个版本中会被哪些错误吞没?
发布于 2022-07-17 19:22:11
默认情况下,在1.7.3中,它完全绕过日志记录并直接打印到stderr (代码在这里):
async def on_error(self, event_method, *args, **kwargs):
print('Ignoring exception in {}'.format(event_method), file=sys.stderr)
traceback.print_exc()
然后调用on_error
,类似于下面的这里
async def _run_event(self, coro, event_name, *args, **kwargs):
try:
await coro(*args, **kwargs)
except asyncio.CancelledError:
pass
except Exception:
try:
await self.on_error(event_name, *args, **kwargs)
except asyncio.CancelledError:
pass
不管是否设置了日志记录,它都会这样做。
我用这个简化版本的机器人来测试它。注意,它在错误消息中包含了_run_event
,这应该是上面代码中链接的相同的错误消息。
import discord
from discord.ext import commands
import logging
import sys
LOGGING_ENABLE = True
if LOGGING_ENABLE:
log = logging.getLogger()
log.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter('\033[0;36m%(asctime)s \033[0;32m%(levelname)s\033[0;0m %(message)s', '%Y%m%d %H:%M:%S'))
log.addHandler(handler)
print(f'discord version {discord.__version__}')
intent = discord.Intents.all()
client = commands.Bot(command_prefix='sudo ', intents=intent)
@client.event
async def on_ready():
print('logged in')
print('raising exception!')
raise ValueError()
print('starting client.run:')
client.run(...)
当日志记录是而不是设置时给出的
discord version 1.7.3
starting client.run:
logged in
raising exception!
Ignoring exception in on_ready
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/greateric/Documents/PYTHON/old-discordbot/bot_cut.py", line 14, in on_ready
raise ValueError()
ValueError
并给出了日志记录设置的时间。
discord version 1.7.3
starting client.run:
20220717 14:50:10 INFO logging in using static token
20220717 14:50:11 INFO Shard ID None has sent the IDENTIFY payload.
20220717 14:50:12 INFO Shard ID None has connected to Gateway: <a bunch of irrelevant stuff>.
logged in
raising exception!
Ignoring exception in on_ready
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/greateric/Documents/PYTHON/old-discordbot/bot_cut.py", line 23, in on_ready
raise ValueError()
ValueError
^C20220717 14:50:15 INFO Cleaning up tasks.
20220717 14:50:15 INFO Cleaning up after 1 tasks.
20220717 14:50:15 INFO All tasks finished cancelling.
20220717 14:50:15 INFO Closing the event loop.
在2.0中,在启用日志记录的情况下,它实际上“很好”地打印了错误。
discord version 2.0.0a
20220717 14:53:09 WARNING PyNaCl is not installed, voice will NOT be supported
starting client.run:
2022-07-17 14:53:09 INFO discord.client logging in using static token
20220717 14:53:09 INFO logging in using static token
2022-07-17 14:53:09 INFO discord.gateway Shard ID None has sent the IDENTIFY payload.
20220717 14:53:09 INFO Shard ID None has sent the IDENTIFY payload.
2022-07-17 14:53:09 INFO discord.gateway Shard ID None has connected to Gateway (Session ID: ...).
20220717 14:53:09 INFO Shard ID None has connected to Gateway (Session ID: ...).
logged in
raising exception!
2022-07-17 14:53:12 ERROR discord.client Ignoring exception in on_ready
Traceback (most recent call last):
File "/home/greateric/Documents/PYTHON/old-discordbot/venv/lib/python3.9/site-packages/discord/client.py", line 456, in _run_event
await coro(*args, **kwargs)
File "/home/greateric/Documents/PYTHON/old-discordbot/bot_cut.py", line 23, in on_ready
raise ValueError()
ValueError
20220717 14:53:12 ERROR Ignoring exception in on_ready
Traceback (most recent call last):
File "/home/greateric/Documents/PYTHON/old-discordbot/venv/lib/python3.9/site-packages/discord/client.py", line 456, in _run_event
await coro(*args, **kwargs)
File "/home/greateric/Documents/PYTHON/old-discordbot/bot_cut.py", line 23, in on_ready
raise ValueError()
ValueError
(我不知道这里发生了什么,但我认为是两个伐木处理人员为了争夺对方而争吵。屏幕截图与颜色这里)
实际上,当我禁用日志记录时,会发生这样的情况:
discord version 2.0.0a
starting client.run:
2022-07-17 14:56:40 INFO discord.client logging in using static token
2022-07-17 14:56:40 INFO discord.gateway Shard ID None has sent the IDENTIFY payload.
2022-07-17 14:56:40 INFO discord.gateway Shard ID None has connected to Gateway (Session ID: 85657d0594417664850b2c03c2ca0d77).
logged in
raising exception!
2022-07-17 14:56:42 ERROR discord.client Ignoring exception in on_ready
Traceback (most recent call last):
File "/home/greateric/Documents/PYTHON/old-discordbot/venv/lib/python3.9/site-packages/discord/client.py", line 456, in _run_event
await coro(*args, **kwargs)
File "/home/greateric/Documents/PYTHON/old-discordbot/bot_cut.py", line 23, in on_ready
raise ValueError()
ValueError
现在看来,discord.py正在制作自己的日志处理程序(独立于我上次创建的日志处理程序)。
代码是不同的。(代码段,来自提交52f3a3496bea13fefc08b38f9ed01641e565d0eb
)
async def on_error(self, event_method: str, /, *args: Any, **kwargs: Any) -> None:
"""|coro|
The default error handler provided by the client.
By default this logs to the library logger however it could be
overridden to have a different implementation.
Check :func:`~discord.on_error` for more details.
.. versionchanged:: 2.0
``event_method`` parameter is now positional-only
and instead of writing to ``sys.stderr`` it logs instead.
"""
_log.exception('Ignoring exception in %s', event_method)
由于这,记录器独立于您自己的设置记录器。
_log = logging.getLogger(__name__)
它还在__init__.py
中添加了一个处理程序。
logging.getLogger(__name__).addHandler(logging.NullHandler())
以这两个文件为例:
a.py
import logging
import sys
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter('\033[0;36m%(asctime)s \033[0;32m%(levelname)s\033[0;0m %(message)s', '%Y%m%d %H:%M:%S'))
logging.getLogger(__name__).addHandler(handler)
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.info('hi from a.py')
print('done executing a.py')
b.py
import logging
import a
import sys
LOGGING_ENABLE = True
if LOGGING_ENABLE:
logger = logging.getLogger()
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter('\033[0;33mreminder that this is the formatter of b.py \033[0;36m%(asctime)s \033[0;32m%(levelname)s\033[0;0m %(message)s', '%Y%m%d %H:%M:%S'))
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.info('hi from b.py')
print('just finished running b.py')
如果启用了LOGGING_ENABLE
,这就是输出。这两个记录器完全相互独立(它们有不同的格式化程序)。
20220717 15:10:49 INFO hi from a.py
done executing a.py
reminder that this is the formatter of b.py 20220717 15:10:49 INFO hi from b.py
just finished running b.py
当b.py
中没有记录器时,a.py
的记录器仍然工作:
20220717 15:11:19 INFO hi from a.py
done executing a.py
just finished running b.py
or的2.0记录器独立于代码的记录器或缺少一个记录器。不管您自己的记录器设置是什么,它自己的记录器总是会打印错误。
在任何版本中都不应该错误(除了非Exception
错误,如KeyboardInterrupt
之类的错误)。在2.0中,_run_event
基本上是相同的:
async def _run_event(
self,
coro: Callable[..., Coroutine[Any, Any, Any]],
event_name: str,
*args: Any,
**kwargs: Any,
) -> None:
try:
await coro(*args, **kwargs)
except asyncio.CancelledError:
pass
except Exception:
try:
await self.on_error(event_name, *args, **kwargs)
except asyncio.CancelledError:
pass
如果有“没有错误”,这通常意味着它被故意忽略,例如,如果您覆盖错误处理程序。也可能是因为某些原因,您的终端忽略了stderr,这在我的另一个项目中发生过一次。
在1.7.3中,无论任何日志记录配置,这些错误都将被打印到stderr,而在2.0中,这些错误将使用不和谐的记录器记录。
当它说什么都不会输出到文档上时,它意味着额外的日志信息,比如logging in using static token
信息。错误跟踪仍然直接打印到stderr。
https://stackoverflow.com/questions/72997136
复制相似问题