diff --git a/redbot/__init__.py b/redbot/__init__.py index 236ca418e..567d88fc9 100644 --- a/redbot/__init__.py +++ b/redbot/__init__.py @@ -1,5 +1,7 @@ import asyncio as _asyncio +import logging as _logging import os as _os +import re import re as _re import sys as _sys import warnings as _warnings @@ -14,6 +16,7 @@ from typing import ( Union as _Union, ) +from redbot._log import RedTraceLogger MIN_PYTHON_VERSION = (3, 8, 1) @@ -209,9 +212,14 @@ def _ensure_no_colorama(): colorama.initialise.wrap_stream = _colorama_wrap_stream +def _update_logger_class(): + _logging.setLoggerClass(RedTraceLogger) + + def _early_init(): _update_event_loop_policy() _ensure_no_colorama() + _update_logger_class() __version__ = "3.5.0.dev1" @@ -222,7 +230,8 @@ _warnings.filterwarnings("ignore", module=r"fuzzywuzzy.*") # Show DeprecationWarning _warnings.filterwarnings("default", category=DeprecationWarning) -if "--debug" not in _sys.argv: +# TODO: Rearrange cli flags here and use the value instead of this monkeypatch +if not any(re.match("^-(-debug|d+|-verbose|v+)$", i) for i in _sys.argv): # DEP-WARN # Individual warnings - tracked in https://github.com/Cog-Creators/Red-DiscordBot/issues/3529 # DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python. diff --git a/redbot/_log.py b/redbot/_log.py new file mode 100644 index 000000000..62afdcce5 --- /dev/null +++ b/redbot/_log.py @@ -0,0 +1,22 @@ +import logging as _logging + +__ALL__ = ["VERBOSE", "TRACE", "RedTraceLogger"] + +VERBOSE = _logging.DEBUG - 3 +TRACE = _logging.DEBUG - 5 + + +class RedTraceLogger(_logging.getLoggerClass()): + def __init__(self, name, level=_logging.NOTSET): + super().__init__(name, level) + + _logging.addLevelName(VERBOSE, "VERBOSE") + _logging.addLevelName(TRACE, "TRACE") + + def verbose(self, msg, *args, **kwargs): + if self.isEnabledFor(VERBOSE): + self._log(VERBOSE, msg, args, **kwargs) + + def trace(self, msg, *args, **kwargs): + if self.isEnabledFor(TRACE): + self._log(TRACE, msg, args, **kwargs) diff --git a/redbot/core/cli.py b/redbot/core/cli.py index dcc1378ff..adbf311f9 100644 --- a/redbot/core/cli.py +++ b/redbot/core/cli.py @@ -7,6 +7,8 @@ from typing import Optional import discord from discord import __version__ as discord_version +from redbot.core.utils._internal_utils import cli_level_to_log_level + def confirm(text: str, default: Optional[bool] = None) -> bool: if default is None: @@ -186,12 +188,13 @@ def parse_cli_flags(args): "process.", ) parser.add_argument( + "-v", + "--verbose", "--debug", - action="store_const", + action="count", + default=0, dest="logging_level", - const=logging.DEBUG, - default=logging.INFO, - help="Sets the loggers level as debug", + help="Increase the verbosity of the logs, each usage of this flag increases the verbosity level by 1.", ) parser.add_argument("--dev", action="store_true", help="Enables developer mode") parser.add_argument( @@ -291,5 +294,6 @@ def parse_cli_flags(args): args.prefix = sorted(args.prefix, reverse=True) else: args.prefix = [] + args.logging_level = cli_level_to_log_level(args.logging_level) return args diff --git a/redbot/core/utils/_internal_utils.py b/redbot/core/utils/_internal_utils.py index 3a7ff1e77..d23be45a3 100644 --- a/redbot/core/utils/_internal_utils.py +++ b/redbot/core/utils/_internal_utils.py @@ -36,7 +36,7 @@ from fuzzywuzzy import fuzz, process from rich.progress import ProgressColumn from rich.progress_bar import ProgressBar -from redbot import VersionInfo +from redbot import VersionInfo, _log from redbot.core import data_manager from redbot.core.utils.chat_formatting import box @@ -57,6 +57,7 @@ __all__ = ( "fetch_latest_red_version_info", "deprecated_removed", "RichIndefiniteBarColumn", + "cli_level_to_log_level", ) _T = TypeVar("_T") @@ -357,3 +358,15 @@ class RichIndefiniteBarColumn(ProgressColumn): total=task.total, completed=task.completed, ) + + +def cli_level_to_log_level(level: int) -> int: + if level == 0: + log_level = logging.INFO + elif level == 1: + log_level = logging.DEBUG + elif level == 2: + log_level = _log.VERBOSE + else: + log_level = _log.TRACE + return log_level diff --git a/redbot/logging.py b/redbot/logging.py index ec1af3114..e52c18b4f 100644 --- a/redbot/logging.py +++ b/redbot/logging.py @@ -282,7 +282,6 @@ class RedRichHandler(RichHandler): def init_logging(level: int, location: pathlib.Path, cli_flags: argparse.Namespace) -> None: root_logger = logging.getLogger() - base_logger = logging.getLogger("red") base_logger.setLevel(level) dpy_logger = logging.getLogger("discord") @@ -298,6 +297,8 @@ def init_logging(level: int, location: pathlib.Path, cli_flags: argparse.Namespa "log.time": Style(dim=True), "logging.level.warning": Style(color="yellow"), "logging.level.critical": Style(color="white", bgcolor="red"), + "logging.level.verbose": Style(color="magenta", italic=True, dim=True), + "logging.level.trace": Style(color="white", italic=True, dim=True), "repr.number": Style(color="cyan"), "repr.url": Style(underline=True, italic=True, bold=False, color="cyan"), } diff --git a/redbot/setup.py b/redbot/setup.py index f3363d4d1..89b4f2993 100644 --- a/redbot/setup.py +++ b/redbot/setup.py @@ -17,7 +17,11 @@ import appdirs import click from redbot.core.cli import confirm -from redbot.core.utils._internal_utils import safe_delete, create_backup as red_create_backup +from redbot.core.utils._internal_utils import ( + safe_delete, + create_backup as red_create_backup, + cli_level_to_log_level, +) from redbot.core import config, data_manager, drivers from redbot.core.drivers import BackendType, IdentifierData @@ -352,7 +356,7 @@ async def remove_instance_interaction() -> None: @click.group(invoke_without_command=True) -@click.option("--debug", type=bool) +@click.option("--debug", "--verbose", "-v", count=True) @click.option( "--no-prompt", "interactive", @@ -402,7 +406,7 @@ def cli( overwrite_existing_instance: bool, ) -> None: """Create a new instance.""" - level = logging.DEBUG if debug else logging.INFO + level = cli_level_to_log_level(debug) base_logger = logging.getLogger("red") base_logger.setLevel(level) formatter = logging.Formatter(