diff --git a/.env.example b/.env.example index 1e51771499..9ea7727c11 100644 --- a/.env.example +++ b/.env.example @@ -22,6 +22,9 @@ LANGFLOW_SAVE_DB_IN_CONFIG_DIR= # SQLite example: LANGFLOW_DATABASE_URL=sqlite:///./langflow.db +# Alembic logs path flag. If set to true, Alembic will log to stdout. +LANGFLOW_ALEMBIC_LOG_TO_STDOUT=False + # mem0 creates a directory # for chat history, vector stores, and other artifacts diff --git a/src/backend/base/langflow/services/database/service.py b/src/backend/base/langflow/services/database/service.py index 302188e9a8..2e4027a45a 100644 --- a/src/backend/base/langflow/services/database/service.py +++ b/src/backend/base/langflow/services/database/service.py @@ -3,8 +3,9 @@ from __future__ import annotations import asyncio import re import sqlite3 +import sys import time -from contextlib import asynccontextmanager +from contextlib import asynccontextmanager, nullcontext from datetime import datetime, timezone from pathlib import Path from typing import TYPE_CHECKING @@ -62,14 +63,20 @@ class DatabaseService(Service): else: self.engine = self._create_engine() + # Check if Alembic should log to stdout or a file. + # If file, check if the provided path is absolute, cross-platform. alembic_log_file = self.settings_service.settings.alembic_log_file - # Check if the provided path is absolute, cross-platform. - if Path(alembic_log_file).is_absolute(): + self.alembic_log_to_stdout = self.settings_service.settings.alembic_log_to_stdout + if self.alembic_log_to_stdout: + self.alembic_log_path = None + elif Path(alembic_log_file).is_absolute(): self.alembic_log_path = Path(alembic_log_file) else: self.alembic_log_path = Path(langflow_dir) / alembic_log_file async def initialize_alembic_log_file(self): + if self.alembic_log_to_stdout: + return # Ensure the directory and file for the alembic log file exists await anyio.Path(self.alembic_log_path.parent).mkdir(parents=True, exist_ok=True) await anyio.Path(self.alembic_log_path).touch(exist_ok=True) @@ -328,7 +335,10 @@ class DatabaseService(Service): # which is a buffer # I don't want to output anything # subprocess.DEVNULL is an int - with self.alembic_log_path.open("w", encoding="utf-8") as buffer: + buffer_context = ( + nullcontext(sys.stdout) if self.alembic_log_to_stdout else self.alembic_log_path.open("w", encoding="utf-8") # type: ignore[union-attr] + ) + with buffer_context as buffer: alembic_cfg = Config(stdout=buffer) # alembic_cfg.attributes["connection"] = session alembic_cfg.set_main_option("script_location", str(self.script_location)) diff --git a/src/lfx/src/lfx/services/settings/base.py b/src/lfx/src/lfx/services/settings/base.py index 48c345a723..07b01394d0 100644 --- a/src/lfx/src/lfx/services/settings/base.py +++ b/src/lfx/src/lfx/services/settings/base.py @@ -245,6 +245,8 @@ class Settings(BaseSettings): """The path to log file for Langflow.""" alembic_log_file: str = "alembic/alembic.log" """The path to log file for Alembic for SQLAlchemy.""" + alembic_log_to_stdout: bool = False + """If set to True, the log file will be ignored and Alembic will log to stdout.""" frontend_path: str | None = None """The path to the frontend directory containing build files. This is for development purposes only..""" open_browser: bool = False