diff --git a/discord/client.py b/discord/client.py index aaf8461c1..3264e4a5b 100644 --- a/discord/client.py +++ b/discord/client.py @@ -29,7 +29,6 @@ from datetime import datetime import logging import sys import os -import traceback from typing import ( Any, AsyncIterator, @@ -606,16 +605,16 @@ class Client: The default error handler provided by the client. - By default this prints to :data:`sys.stderr` however it could be + 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. + ``event_method`` parameter is now positional-only + and instead of writing to ``sys.stderr`` it logs instead. """ - print(f'Ignoring exception in {event_method}', file=sys.stderr) - traceback.print_exc() + _log.exception('Ignoring exception in %s', event_method) async def on_internal_settings_update(self, old_settings: UserSettings, new_settings: UserSettings): if not self._sync_presences: diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py index 542496435..482c78c6c 100644 --- a/discord/ext/commands/bot.py +++ b/discord/ext/commands/bot.py @@ -31,7 +31,7 @@ import collections.abc import inspect import importlib.util import sys -import traceback +import logging import types from typing import ( Any, @@ -88,6 +88,8 @@ __all__ = ( T = TypeVar('T') CFT = TypeVar('CFT', bound='CoroFunc') +_log = logging.getLogger(__name__) + def when_mentioned(bot: _Bot, msg: Message, /) -> List[str]: """A callable that implements a command prefix equivalent to being mentioned. @@ -225,7 +227,7 @@ class BotBase(GroupMixin[None]): The default command error handler provided by the bot. - By default this prints to :data:`sys.stderr` however it could be + By default this logs to the library logger, however it could be overridden to have a different implementation. This only fires if you do not specify any listeners for command error. @@ -233,6 +235,7 @@ class BotBase(GroupMixin[None]): .. versionchanged:: 2.0 ``context`` and ``exception`` parameters are now positional-only. + Instead of writing to ``sys.stderr`` this now uses the library logger. """ if self.extra_events.get('on_command_error', None): return @@ -245,8 +248,7 @@ class BotBase(GroupMixin[None]): if cog and cog.has_error_handler(): return - print(f'Ignoring exception in command {context.command}:', file=sys.stderr) - traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr) + _log.error('Ignoring exception in command %s', command, exc_info=exception) # global check registration diff --git a/discord/ext/tasks/__init__.py b/discord/ext/tasks/__init__.py index 9179b2215..82fd149d2 100644 --- a/discord/ext/tasks/__init__.py +++ b/discord/ext/tasks/__init__.py @@ -42,8 +42,6 @@ from typing import ( import aiohttp import discord import inspect -import sys -import traceback from collections.abc import Sequence from discord.backoff import ExponentialBackoff @@ -536,8 +534,7 @@ class Loop(Generic[LF]): async def _error(self, *args: Any) -> None: exception: Exception = args[-1] - print(f'Unhandled exception in internal background task {self.coro.__name__!r}.', file=sys.stderr) - traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr) + _log.error('Unhandled exception in internal background task %r.', self.coro.__name__, exc_info=exception) def before_loop(self, coro: FT) -> FT: """A decorator that registers a coroutine to be called before the loop starts running. @@ -600,11 +597,15 @@ class Loop(Generic[LF]): The coroutine must take only one argument the exception raised (except ``self`` in a class context). - By default this prints to :data:`sys.stderr` however it could be + By default this logs to the library logger however it could be overridden to have a different implementation. .. versionadded:: 1.4 + .. versionchanged:: 2.0 + + Instead of writing to ``sys.stderr``, the library's logger is used. + Parameters ------------ coro: :ref:`coroutine ` diff --git a/docs/api.rst b/docs/api.rst index 0ec7ee83e..360aaf07b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -151,7 +151,7 @@ overriding the specific events. For example: :: If an event handler raises an exception, :func:`on_error` will be called -to handle it, which defaults to print a traceback and ignoring the exception. +to handle it, which defaults to logging the traceback and ignoring the exception. .. warning:: @@ -267,7 +267,7 @@ Debug .. function:: on_error(event, *args, **kwargs) Usually when an event raises an uncaught exception, a traceback is - printed to stderr and the exception is ignored. If you want to + logged to stderr and the exception is ignored. If you want to change this behaviour and handle the exception for whatever reason yourself, this event can be overridden. Which, when done, will suppress the default action of printing the traceback. @@ -275,11 +275,6 @@ Debug The information of the exception raised and the exception itself can be retrieved with a standard call to :func:`sys.exc_info`. - If you want exception to propagate out of the :class:`Client` class - you can define an ``on_error`` handler consisting of a single empty - :ref:`raise statement `. Exceptions raised by ``on_error`` will not be - handled in any way by :class:`Client`. - .. note:: ``on_error`` will only be dispatched to :meth:`Client.event`. @@ -288,6 +283,10 @@ Debug :ref:`ext_commands_api_bot` listeners such as :meth:`~ext.commands.Bot.listen` or :meth:`~ext.commands.Cog.listener`. + .. versionchanged:: 2.0 + + The traceback is now logged rather than printed. + :param event: The name of the event that raised the exception. :type event: :class:`str` diff --git a/docs/migrating.rst b/docs/migrating.rst index 7b502496d..3cf5559b5 100644 --- a/docs/migrating.rst +++ b/docs/migrating.rst @@ -844,6 +844,17 @@ The following methods have been changed: - :meth:`Webhook.send` - :meth:`abc.GuildChannel.set_permissions` +Logging Changes +---------------- + +The library now provides a default logging configuration if using :meth:`Client.run`. To disable it, pass ``None`` to the ``log_handler`` keyword parameter. Since the library now provides a default logging configuration, certain methods were changed to no longer print to :data:`sys.stderr` but use the logger instead: + +- :meth:`Client.on_error` +- :meth:`discord.ext.tasks.Loop.error` +- :meth:`discord.ext.commands.Bot.on_command_error` + +For more information, check :doc:`logging`. + Removal of ``StoreChannel`` -----------------------------