diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b071af00df36..5fbd33885d16 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -139,6 +139,15 @@ repos: types: [file, python] language: system + - repo: local + hooks: + - id: check-loggers + name: Check for plain loggers + entry: poetry -C autogpt_platform/backend run python check_logging.py + files: ^autogpt_platform/backend/backend/ + language: system + pass_filenames: false + - repo: https://github.com/psf/black rev: 24.10.0 # Black has sensible defaults, doesn't need package context, and ignores diff --git a/autogpt_platform/README.md b/autogpt_platform/README.md index 92ea6ec95090..05b05b525c36 100644 --- a/autogpt_platform/README.md +++ b/autogpt_platform/README.md @@ -115,6 +115,17 @@ Here are some common scenarios where you might use multiple Docker Compose comma These scenarios demonstrate how to use Docker Compose commands in combination to manage your AutoGPT Platform effectively. +### Logging +The backend configures logging by calling `configure_logging()` at startup. +Logs use the format: + +``` +YYYY-MM-DD HH:MM:SS LEVEL [PREFIX] message {"json_fields": {...}} +``` + +When creating loggers for user-facing modules, wrap them with +`TruncatedLogger(logging.getLogger(__name__), "[Component]")` to truncate long +messages and include optional metadata. ### Persisting Data diff --git a/autogpt_platform/backend/backend/app.py b/autogpt_platform/backend/backend/app.py index e605e227f435..d4c86e747ad1 100644 --- a/autogpt_platform/backend/backend/app.py +++ b/autogpt_platform/backend/backend/app.py @@ -4,7 +4,9 @@ if TYPE_CHECKING: from backend.util.process import AppProcess -logger = logging.getLogger(__name__) +from backend.util.logging import TruncatedLogger, configure_logging + +logger = TruncatedLogger(logging.getLogger(__name__), "[App]") def run_processes(*processes: "AppProcess", **kwargs): @@ -31,6 +33,7 @@ def main(**kwargs): """ Run all the processes required for the AutoGPT-server (REST and WebSocket APIs). """ + configure_logging() from backend.executor import DatabaseManager, ExecutionManager, Scheduler from backend.notifications import NotificationManager diff --git a/autogpt_platform/backend/backend/exec.py b/autogpt_platform/backend/backend/exec.py index 46101a742af9..62fac6af06c2 100644 --- a/autogpt_platform/backend/backend/exec.py +++ b/autogpt_platform/backend/backend/exec.py @@ -1,11 +1,13 @@ from backend.app import run_processes from backend.executor import ExecutionManager +from backend.util.logging import configure_logging def main(): """ Run all the processes required for the AutoGPT-server REST API. """ + configure_logging() run_processes(ExecutionManager()) diff --git a/autogpt_platform/backend/backend/rest.py b/autogpt_platform/backend/backend/rest.py index 0fb1eed87533..5c4d9fcac84c 100644 --- a/autogpt_platform/backend/backend/rest.py +++ b/autogpt_platform/backend/backend/rest.py @@ -2,12 +2,14 @@ from backend.executor import DatabaseManager from backend.notifications.notifications import NotificationManager from backend.server.rest_api import AgentServer +from backend.util.logging import configure_logging def main(): """ Run all the processes required for the AutoGPT-server REST API. """ + configure_logging() run_processes( NotificationManager(), DatabaseManager(), diff --git a/autogpt_platform/backend/backend/scheduler.py b/autogpt_platform/backend/backend/scheduler.py index 22be4bf7fd87..d6bfe414d5cc 100644 --- a/autogpt_platform/backend/backend/scheduler.py +++ b/autogpt_platform/backend/backend/scheduler.py @@ -1,11 +1,13 @@ from backend.app import run_processes from backend.executor.scheduler import Scheduler +from backend.util.logging import configure_logging def main(): """ Run all the processes required for the AutoGPT-server Scheduling System. """ + configure_logging() run_processes(Scheduler()) diff --git a/autogpt_platform/backend/backend/ws.py b/autogpt_platform/backend/backend/ws.py index 3b15a60eb03a..7f0f0a1ba550 100644 --- a/autogpt_platform/backend/backend/ws.py +++ b/autogpt_platform/backend/backend/ws.py @@ -1,11 +1,13 @@ from backend.app import run_processes from backend.server.ws_api import WebsocketServer +from backend.util.logging import configure_logging def main(): """ Run all the processes required for the AutoGPT-server WebSocket API. """ + configure_logging() run_processes(WebsocketServer()) diff --git a/autogpt_platform/backend/check_logging.py b/autogpt_platform/backend/check_logging.py new file mode 100644 index 000000000000..068a21f1730e --- /dev/null +++ b/autogpt_platform/backend/check_logging.py @@ -0,0 +1,17 @@ +import pathlib +import re + +PATTERN = re.compile(r"logging\.getLogger\(") +ROOT = pathlib.Path(__file__).resolve().parent / "backend" + +errors = [] + +for path in ROOT.rglob("*.py"): + if path.name == "logging.py": + continue + text = path.read_text() + if PATTERN.search(text) and "TruncatedLogger" not in text: + errors.append(str(path.relative_to(ROOT))) + +if errors: + print("Plain logging.getLogger usage detected in:\n" + "\n".join(errors)) diff --git a/autogpt_platform/backend/linter.py b/autogpt_platform/backend/linter.py index a86e6761f7a0..b810bea10912 100644 --- a/autogpt_platform/backend/linter.py +++ b/autogpt_platform/backend/linter.py @@ -30,6 +30,7 @@ def lint(): ["ruff", "format", "--diff", "--check", LIBS_DIR], ["isort", "--diff", "--check", "--profile", "black", BACKEND_DIR], ["black", "--diff", "--check", BACKEND_DIR], + ["python", "check_logging.py"], ["pyright", *TARGET_DIRS], ] lint_error = None