From 9bd13c5897f012978667e113e83ee502153cb980 Mon Sep 17 00:00:00 2001 From: Reinier van der Leer Date: Fri, 15 Sep 2023 13:11:43 +0200 Subject: [PATCH] AutoGPT: Enhance log readability of autogpt.core --- .../autogpt/core/runner/cli_app/main.py | 6 +- .../autogpt/core/runner/client_lib/logging.py | 87 ++++++++++++++++--- autogpts/autogpt/autogpt/logs/config.py | 3 +- autogpts/autogpt/autogpt/logs/formatters.py | 36 ++------ 4 files changed, 89 insertions(+), 43 deletions(-) diff --git a/autogpts/autogpt/autogpt/core/runner/cli_app/main.py b/autogpts/autogpt/autogpt/core/runner/cli_app/main.py index e0d9689a..7f2c8f6c 100644 --- a/autogpts/autogpt/autogpt/core/runner/cli_app/main.py +++ b/autogpts/autogpt/autogpt/core/runner/cli_app/main.py @@ -1,7 +1,9 @@ import click from autogpt.core.agent import AgentSettings, SimpleAgent -from autogpt.core.runner.client_lib.logging import get_client_logger +from autogpt.core.runner.client_lib.logging import ( + configure_root_logger, get_client_logger +) from autogpt.core.runner.client_lib.parser import ( parse_ability_result, parse_agent_name_and_goals, @@ -13,6 +15,8 @@ from autogpt.core.runner.client_lib.parser import ( async def run_auto_gpt(user_configuration: dict): """Run the Auto-GPT CLI client.""" + configure_root_logger() + client_logger = get_client_logger() client_logger.debug("Getting agent settings") diff --git a/autogpts/autogpt/autogpt/core/runner/client_lib/logging.py b/autogpts/autogpt/autogpt/core/runner/client_lib/logging.py index 04f0a9c4..d4ffeffe 100644 --- a/autogpts/autogpt/autogpt/core/runner/client_lib/logging.py +++ b/autogpts/autogpt/autogpt/core/runner/client_lib/logging.py @@ -1,4 +1,26 @@ import logging +import sys + +from colorama import Fore, Style + +SIMPLE_LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s" +DEBUG_LOG_FORMAT = ( + "%(asctime)s.%(msecs)03d %(levelname)s %(filename)s:%(lineno)d %(message)s" +) + + +def configure_root_logger(): + console_formatter = FancyConsoleFormatter(SIMPLE_LOG_FORMAT) + + stdout = logging.StreamHandler(stream=sys.stdout) + stdout.setLevel(logging.DEBUG) + stdout.addFilter(BelowLevelFilter(logging.WARNING)) + stdout.setFormatter(console_formatter) + stderr = logging.StreamHandler() + stderr.setLevel(logging.WARNING) + stderr.setFormatter(console_formatter) + + logging.basicConfig(level=logging.DEBUG, handlers=[stdout, stderr]) def get_client_logger(): @@ -7,14 +29,59 @@ def get_client_logger(): client_logger = logging.getLogger("autogpt_client_application") client_logger.setLevel(logging.DEBUG) - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - ) - - ch = logging.StreamHandler() - ch.setLevel(logging.DEBUG) - ch.setFormatter(formatter) - - client_logger.addHandler(ch) - return client_logger + + +class FancyConsoleFormatter(logging.Formatter): + """ + A custom logging formatter designed for console output. + + This formatter enhances the standard logging output with color coding. The color + coding is based on the level of the log message, making it easier to distinguish + between different types of messages in the console output. + + The color for each level is defined in the LEVEL_COLOR_MAP class attribute. + """ + + # level -> (level & text color, title color) + LEVEL_COLOR_MAP = { + logging.DEBUG: Fore.LIGHTBLACK_EX, + logging.INFO: Fore.BLUE, + logging.WARNING: Fore.YELLOW, + logging.ERROR: Fore.RED, + logging.CRITICAL: Fore.RED + Style.BRIGHT, + } + + def format(self, record: logging.LogRecord) -> str: + # Make sure `msg` is a string + if not hasattr(record, "msg"): + record.msg = "" + elif not type(record.msg) == str: + record.msg = str(record.msg) + + # Determine default color based on error level + level_color = "" + if record.levelno in self.LEVEL_COLOR_MAP: + level_color = self.LEVEL_COLOR_MAP[record.levelno] + record.levelname = f"{level_color}{record.levelname}{Style.RESET_ALL}" + + # Determine color for message + color = getattr(record, "color", level_color) + color_is_specified = hasattr(record, "color") + + # Don't color INFO messages unless the color is explicitly specified. + if color and (record.levelno != logging.INFO or color_is_specified): + record.msg = f"{color}{record.msg}{Style.RESET_ALL}" + + return super().format(record) + + +class BelowLevelFilter(logging.Filter): + """Filter for logging levels below a certain threshold.""" + + def __init__(self, below_level: int): + super().__init__() + self.below_level = below_level + + def filter(self, record: logging.LogRecord): + return record.levelno < self.below_level diff --git a/autogpts/autogpt/autogpt/logs/config.py b/autogpts/autogpt/autogpt/logs/config.py index dc1e24c4..ce278f02 100644 --- a/autogpts/autogpt/autogpt/logs/config.py +++ b/autogpts/autogpt/autogpt/logs/config.py @@ -12,7 +12,8 @@ from openai.util import logger as openai_logger if TYPE_CHECKING: from autogpt.config import Config -from .filters import BelowLevelFilter +from autogpt.core.runner.client_lib.logging import BelowLevelFilter + from .formatters import AutoGptFormatter from .handlers import TTSHandler, TypingConsoleHandler diff --git a/autogpts/autogpt/autogpt/logs/formatters.py b/autogpts/autogpt/autogpt/logs/formatters.py index 2c05f831..77371206 100644 --- a/autogpts/autogpt/autogpt/logs/formatters.py +++ b/autogpts/autogpt/autogpt/logs/formatters.py @@ -1,25 +1,13 @@ import logging -from colorama import Fore, Style +from colorama import Style + +from autogpt.core.runner.client_lib.logging import FancyConsoleFormatter from .utils import remove_color_codes -class AutoGptFormatter(logging.Formatter): - """ - Allows to handle custom placeholders 'title_color' and 'message_no_color'. - To use this formatter, make sure to pass 'color', 'title' as log extras. - """ - - # level -> (level & text color, title color) - LEVEL_COLOR_MAP = { - logging.DEBUG: Fore.LIGHTBLACK_EX, - logging.INFO: Fore.BLUE, - logging.WARNING: Fore.YELLOW, - logging.ERROR: Fore.RED, - logging.CRITICAL: Fore.RED + Style.BRIGHT, - } - +class AutoGptFormatter(FancyConsoleFormatter): def format(self, record: logging.LogRecord) -> str: # Make sure `msg` is a string if not hasattr(record, "msg"): @@ -31,26 +19,12 @@ class AutoGptFormatter(logging.Formatter): if record.msg and not getattr(record, "preserve_color", False): record.msg = remove_color_codes(record.msg) - # Determine default color based on error level - level_color = "" - if record.levelno in self.LEVEL_COLOR_MAP: - level_color = self.LEVEL_COLOR_MAP[record.levelno] - record.levelname = f"{level_color}{record.levelname}{Style.RESET_ALL}" - - # Determine color for message - color = getattr(record, "color", level_color) - color_is_specified = hasattr(record, "color") - # Determine color for title title = getattr(record, "title", "") - title_color = getattr(record, "title_color", "") or level_color + title_color = getattr(record, "title_color", "") or self.LEVEL_COLOR_MAP.get(record.levelno, "") if title and title_color: title = f"{title_color + Style.BRIGHT}{title}{Style.RESET_ALL}" # Make sure record.title is set, and padded with a space if not empty record.title = f"{title} " if title else "" - # Don't color INFO messages unless the color is explicitly specified. - if color and (record.levelno != logging.INFO or color_is_specified): - record.msg = f"{color}{record.msg}{Style.RESET_ALL}" - return super().format(record)