feat: make log format configurable (#4851)

* made logformat configurable

* [autofix.ci] apply automated fixes

* documentation of log format env var

* log stuff at one place in documentation

* added documentation of log environment

* check for log format

* [autofix.ci] apply automated fixes

* just load log format on custom logenv

* [autofix.ci] apply automated fixes

* no more invalid whitespaces

* fixed br s with escape

* logging error in case of invalid format string

---------

Co-authored-by: Kraxner Thomas <thomas.kraxner@illwerkevkw.at>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Thomas Kraxner 2024-11-27 15:28:50 +01:00 committed by GitHub
commit 1e6ada3a3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 5 deletions

View file

@ -20,6 +20,10 @@ from typing_extensions import NotRequired
from langflow.settings import DEV
VALID_LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
# Human-readable
DEFAULT_LOG_FORMAT = (
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> - <level>" "{level: <8}</level> - {module} - <level>{message}</level>"
)
class SizedLogBuffer:
@ -147,6 +151,7 @@ class LogConfig(TypedDict):
log_file: NotRequired[Path]
disable: NotRequired[bool]
log_env: NotRequired[str]
log_format: NotRequired[str]
class AsyncFileSink(AsyncSink):
@ -166,12 +171,37 @@ class AsyncFileSink(AsyncSink):
await asyncio.to_thread(self._sink.write, message)
def is_valid_log_format(format_string) -> bool:
"""Validates a logging format string by attempting to format it with a dummy LogRecord.
Args:
format_string (str): The format string to validate.
Returns:
bool: True if the format string is valid, False otherwise.
"""
record = logging.LogRecord(
name="dummy", level=logging.INFO, pathname="dummy_path", lineno=0, msg="dummy message", args=None, exc_info=None
)
formatter = logging.Formatter(format_string)
try:
# Attempt to format the record
formatter.format(record)
except (KeyError, ValueError, TypeError):
logger.error("Invalid log format string passed, fallback to default")
return False
return True
def configure(
*,
log_level: str | None = None,
log_file: Path | None = None,
disable: bool | None = False,
log_env: str | None = None,
log_format: str | None = None,
async_file: bool = False,
) -> None:
if disable and log_level is None and log_file is None:
@ -195,11 +225,11 @@ def configure(
elif log_env.lower() == "container_csv":
logger.add(sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss.SSS} {level} {file} {line} {function} {message}")
else:
# Human-readable
log_format = (
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> - <level>"
"{level: <8}</level> - {module} - <level>{message}</level>"
)
if os.getenv("LANGFLOW_LOG_FORMAT") and log_format is None:
log_format = os.getenv("LANGFLOW_LOG_FORMAT")
if log_format is None or not is_valid_log_format(log_format):
log_format = DEFAULT_LOG_FORMAT
# Configure loguru to use RichHandler
logger.configure(