aboutsummaryrefslogtreecommitdiff
path: root/autogpts/autogpt/autogpt/logs/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'autogpts/autogpt/autogpt/logs/config.py')
-rw-r--r--autogpts/autogpt/autogpt/logs/config.py203
1 files changed, 203 insertions, 0 deletions
diff --git a/autogpts/autogpt/autogpt/logs/config.py b/autogpts/autogpt/autogpt/logs/config.py
new file mode 100644
index 000000000..ae483d0f8
--- /dev/null
+++ b/autogpts/autogpt/autogpt/logs/config.py
@@ -0,0 +1,203 @@
+"""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._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, StructuredLoggingFormatter
+from .handlers import TTSHandler, TypingConsoleHandler
+
+LOG_DIR = Path(__file__).parent.parent.parent / "logs"
+LOG_FILE = "activity.log"
+DEBUG_LOG_FILE = "debug.log"
+ERROR_LOG_FILE = "error.log"
+
+SIMPLE_LOG_FORMAT = "%(asctime)s %(levelname)s %(title)s%(message)s"
+DEBUG_LOG_FORMAT = (
+ "%(asctime)s %(levelname)s %(filename)s:%(lineno)d" " %(title)s%(message)s"
+)
+
+SPEECH_OUTPUT_LOGGER = "VOICE"
+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(
+ 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.
+
+ 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_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(level)
+ stdout.addFilter(BelowLevelFilter(logging.WARNING))
+ stdout.setFormatter(console_formatter)
+ stderr = logging.StreamHandler()
+ stderr.setLevel(logging.WARNING)
+ stderr.setFormatter(console_formatter)
+ 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_console_output else stdout
+ )
+ if tts_config:
+ user_friendly_output_logger.addHandler(TTSHandler(tts_config))
+ 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:
+ speech_output_logger.addHandler(TTSHandler(tts_config))
+ speech_output_logger.propagate = False
+
+ # JSON logger with better formatting
+ json_logger = logging.getLogger("JSON_LOGGER")
+ json_logger.setLevel(logging.DEBUG)
+ json_logger.propagate = False
+
+ # Disable debug logging from OpenAI library
+ openai_logger.setLevel(logging.WARNING)
+
+
+def configure_chat_plugins(config: Config) -> None:
+ """Configure chat plugins for use by the logging module"""
+
+ logger = logging.getLogger(__name__)
+
+ # Add chat plugins capable of report to logger
+ if config.chat_messages_enabled:
+ if _chat_plugins:
+ _chat_plugins.clear()
+
+ for plugin in config.plugins:
+ if hasattr(plugin, "can_handle_report") and plugin.can_handle_report():
+ logger.debug(f"Loaded plugin into logger: {plugin.__class__.__name__}")
+ _chat_plugins.append(plugin)