feat: add configurable logging level for backend and Mini App

- Introduced a new `LOG_LEVEL` configuration option in the `.env.example` file to allow users to set the logging level (DEBUG, INFO, WARNING, ERROR).
- Updated the `Settings` class to include the `log_level` attribute, normalizing its value to ensure valid logging levels are used.
- Modified the logging setup in `run.py` to utilize the configured log level, enhancing flexibility in log management.
- Enhanced the Mini App to include the logging level in the JavaScript configuration, allowing for consistent logging behavior across the application.
- Added a new `logger.js` module for frontend logging, implementing level-based filtering and console delegation.
- Included unit tests for the new logger functionality to ensure proper behavior and level handling.
This commit is contained in:
2026-03-02 23:15:22 +03:00
parent 67ba9826c7
commit 43386b15fa
16 changed files with 226 additions and 15 deletions

View File

@@ -4,6 +4,7 @@ BOT_TOKEN is not validated on import; call require_bot_token() in the entry poin
when running the bot.
"""
import logging
import os
import re
from dataclasses import dataclass
@@ -46,6 +47,14 @@ def _parse_phone_list(raw: str) -> set[str]:
return result
def _normalize_log_level(raw: str) -> str:
"""Return a valid log level name (DEBUG, INFO, WARNING, ERROR); default INFO."""
level = (raw or "").strip().upper()
if level in ("DEBUG", "INFO", "WARNING", "ERROR"):
return level
return "INFO"
@dataclass(frozen=True)
class Settings:
"""Injectable settings built from environment. Used in tests or when env is overridden."""
@@ -67,6 +76,7 @@ class Settings:
duty_display_tz: str
default_language: str
duty_pin_notify: bool
log_level: str
@classmethod
def from_env(cls) -> "Settings":
@@ -118,6 +128,7 @@ class Settings:
default_language=normalize_lang(os.getenv("DEFAULT_LANGUAGE", "en")),
duty_pin_notify=os.getenv("DUTY_PIN_NOTIFY", "1").strip().lower()
not in ("0", "false", "no"),
log_level=_normalize_log_level(os.getenv("LOG_LEVEL", "INFO")),
)
@@ -141,6 +152,8 @@ EXTERNAL_CALENDAR_ICS_URL = _settings.external_calendar_ics_url
DUTY_DISPLAY_TZ = _settings.duty_display_tz
DEFAULT_LANGUAGE = _settings.default_language
DUTY_PIN_NOTIFY = _settings.duty_pin_notify
LOG_LEVEL = getattr(logging, _settings.log_level.upper(), logging.INFO)
LOG_LEVEL_STR = _settings.log_level
def is_admin(username: str) -> bool: