diff options
Diffstat (limited to 'autogpts/autogpt/autogpt/logs/config.py')
-rw-r--r-- | autogpts/autogpt/autogpt/logs/config.py | 156 |
1 files changed, 110 insertions, 46 deletions
diff --git a/autogpts/autogpt/autogpt/logs/config.py b/autogpts/autogpt/autogpt/logs/config.py index 7b8a043b1..ae483d0f8 100644 --- a/autogpts/autogpt/autogpt/logs/config.py +++ b/autogpts/autogpt/autogpt/logs/config.py @@ -1,21 +1,24 @@ """Logging module for Auto-GPT.""" from __future__ import annotations +import enum import logging +import os import sys from pathlib import Path from typing import TYPE_CHECKING, Optional from auto_gpt_plugin_template import AutoGPTPluginTemplate -from openai.util import logger as openai_logger +from openai._base_client import log as openai_logger if TYPE_CHECKING: from autogpt.config import Config from autogpt.speech import TTSConfig +from autogpt.core.configuration import SystemConfiguration, UserConfigurable from autogpt.core.runner.client_lib.logging import BelowLevelFilter -from .formatters import AutoGptFormatter +from .formatters import AutoGptFormatter, StructuredLoggingFormatter from .handlers import TTSHandler, TypingConsoleHandler LOG_DIR = Path(__file__).parent.parent.parent / "logs" @@ -34,80 +37,141 @@ USER_FRIENDLY_OUTPUT_LOGGER = "USER_FRIENDLY_OUTPUT" _chat_plugins: list[AutoGPTPluginTemplate] = [] +class LogFormatName(str, enum.Enum): + SIMPLE = "simple" + DEBUG = "debug" + STRUCTURED = "structured_google_cloud" + + +TEXT_LOG_FORMAT_MAP = { + LogFormatName.DEBUG: DEBUG_LOG_FORMAT, + LogFormatName.SIMPLE: SIMPLE_LOG_FORMAT, +} + + +class LoggingConfig(SystemConfiguration): + level: int = UserConfigurable( + default=logging.INFO, + from_env=lambda: logging.getLevelName(os.getenv("LOG_LEVEL", "INFO")), + ) + + # Console output + log_format: LogFormatName = UserConfigurable( + default=LogFormatName.SIMPLE, + from_env=lambda: LogFormatName(os.getenv("LOG_FORMAT", "simple")), + ) + plain_console_output: bool = UserConfigurable( + default=False, + from_env=lambda: os.getenv("PLAIN_OUTPUT", "False") == "True", + ) + + # File output + log_dir: Path = LOG_DIR + log_file_format: Optional[LogFormatName] = UserConfigurable( + default=LogFormatName.SIMPLE, + from_env=lambda: LogFormatName( + os.getenv("LOG_FILE_FORMAT", os.getenv("LOG_FORMAT", "simple")) + ), + ) + + def configure_logging( - debug_mode: bool = False, - plain_output: bool = False, - tts_config: Optional[TTSConfig] = None, + level: int = logging.INFO, log_dir: Path = LOG_DIR, + log_format: Optional[LogFormatName] = None, + log_file_format: Optional[LogFormatName] = None, + plain_console_output: bool = False, + tts_config: Optional[TTSConfig] = None, ) -> None: - """Configure the native logging module.""" + """Configure the native logging module. + + Should be usable as `configure_logging(**config.logging.dict())`, where + `config.logging` is a `LoggingConfig` object. + """ + + # Auto-adjust default log format based on log level + log_format = log_format or ( + LogFormatName.SIMPLE if level != logging.DEBUG else LogFormatName.DEBUG + ) + log_file_format = log_file_format or log_format + + structured_logging = log_format == LogFormatName.STRUCTURED + + if structured_logging: + plain_console_output = True + log_file_format = None # create log directory if it doesn't exist if not log_dir.exists(): log_dir.mkdir() - log_level = logging.DEBUG if debug_mode else logging.INFO - log_format = DEBUG_LOG_FORMAT if debug_mode else SIMPLE_LOG_FORMAT - console_formatter = AutoGptFormatter(log_format) + log_handlers: list[logging.Handler] = [] + + if log_format in (LogFormatName.DEBUG, LogFormatName.SIMPLE): + console_format_template = TEXT_LOG_FORMAT_MAP[log_format] + console_formatter = AutoGptFormatter(console_format_template) + else: + console_formatter = StructuredLoggingFormatter() + console_format_template = SIMPLE_LOG_FORMAT # Console output handlers stdout = logging.StreamHandler(stream=sys.stdout) - stdout.setLevel(log_level) + stdout.setLevel(level) stdout.addFilter(BelowLevelFilter(logging.WARNING)) stdout.setFormatter(console_formatter) stderr = logging.StreamHandler() stderr.setLevel(logging.WARNING) stderr.setFormatter(console_formatter) - - # INFO log file handler - activity_log_handler = logging.FileHandler(log_dir / LOG_FILE, "a", "utf-8") - activity_log_handler.setLevel(logging.INFO) - activity_log_handler.setFormatter( - AutoGptFormatter(SIMPLE_LOG_FORMAT, no_color=True) - ) - - if debug_mode: - # DEBUG log file handler - debug_log_handler = logging.FileHandler(log_dir / DEBUG_LOG_FILE, "a", "utf-8") - debug_log_handler.setLevel(logging.DEBUG) - debug_log_handler.setFormatter( - AutoGptFormatter(DEBUG_LOG_FORMAT, no_color=True) - ) - - # ERROR log file handler - error_log_handler = logging.FileHandler(log_dir / ERROR_LOG_FILE, "a", "utf-8") - error_log_handler.setLevel(logging.ERROR) - error_log_handler.setFormatter(AutoGptFormatter(DEBUG_LOG_FORMAT, no_color=True)) - - # Configure the root logger - logging.basicConfig( - format=log_format, - level=log_level, - handlers=( - [stdout, stderr, activity_log_handler, error_log_handler] - + ([debug_log_handler] if debug_mode else []) - ), - ) - - ## Set up user-friendly loggers + log_handlers += [stdout, stderr] # Console output handler which simulates typing typing_console_handler = TypingConsoleHandler(stream=sys.stdout) typing_console_handler.setLevel(logging.INFO) typing_console_handler.setFormatter(console_formatter) + # User friendly output logger (text + speech) user_friendly_output_logger = logging.getLogger(USER_FRIENDLY_OUTPUT_LOGGER) user_friendly_output_logger.setLevel(logging.INFO) user_friendly_output_logger.addHandler( - typing_console_handler if not plain_output else stdout + typing_console_handler if not plain_console_output else stdout ) if tts_config: user_friendly_output_logger.addHandler(TTSHandler(tts_config)) - user_friendly_output_logger.addHandler(activity_log_handler) - user_friendly_output_logger.addHandler(error_log_handler) user_friendly_output_logger.addHandler(stderr) user_friendly_output_logger.propagate = False + # File output handlers + if log_file_format is not None: + if level < logging.ERROR: + file_output_format_template = TEXT_LOG_FORMAT_MAP[log_file_format] + file_output_formatter = AutoGptFormatter( + file_output_format_template, no_color=True + ) + + # INFO log file handler + activity_log_handler = logging.FileHandler(log_dir / LOG_FILE, "a", "utf-8") + activity_log_handler.setLevel(level) + activity_log_handler.setFormatter(file_output_formatter) + log_handlers += [activity_log_handler] + user_friendly_output_logger.addHandler(activity_log_handler) + + # ERROR log file handler + error_log_handler = logging.FileHandler(log_dir / ERROR_LOG_FILE, "a", "utf-8") + error_log_handler.setLevel(logging.ERROR) + error_log_handler.setFormatter( + AutoGptFormatter(DEBUG_LOG_FORMAT, no_color=True) + ) + log_handlers += [error_log_handler] + user_friendly_output_logger.addHandler(error_log_handler) + + # Configure the root logger + logging.basicConfig( + format=console_format_template, + level=level, + handlers=log_handlers, + ) + + # Speech output speech_output_logger = logging.getLogger(SPEECH_OUTPUT_LOGGER) speech_output_logger.setLevel(logging.INFO) if tts_config: @@ -120,7 +184,7 @@ def configure_logging( json_logger.propagate = False # Disable debug logging from OpenAI library - openai_logger.setLevel(logging.INFO) + openai_logger.setLevel(logging.WARNING) def configure_chat_plugins(config: Config) -> None: |