From da4061881863e224e5930a2b54db7e78fbf720f9 Mon Sep 17 00:00:00 2001 From: Antti Kettunen Date: Tue, 21 Apr 2026 11:25:58 +0300 Subject: [PATCH] Add the option to override log level via env variables --- Support/README-Docker.md | 3 ++- config/settings.py | 31 +++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Support/README-Docker.md b/Support/README-Docker.md index d52a4205..77d0f2d8 100644 --- a/Support/README-Docker.md +++ b/Support/README-Docker.md @@ -63,6 +63,7 @@ environment: - FLASK_ENV=production # Flask environment - PYTHONPATH=/app # Python path - SOULSYNC_CONFIG_PATH=/app/config/config.json # Config file location + - SOULSYNC_LOG_LEVEL=INFO # Optional startup log level override, takes precedence over the UI-configured log level - TZ=America/New_York # Timezone ``` @@ -268,4 +269,4 @@ services: - [ ] Configure firewall rules - [ ] Set up backup strategy - [ ] Test health checks -- [ ] Verify external service connectivity \ No newline at end of file +- [ ] Verify external service connectivity diff --git a/config/settings.py b/config/settings.py index f4b455a8..19b24e6c 100644 --- a/config/settings.py +++ b/config/settings.py @@ -334,8 +334,27 @@ class ConfigManager: if conn: conn.close() - def _apply_stored_log_level(self, config_data: Dict[str, Any]) -> Dict[str, Any]: - """Overlay any persisted UI log level onto the loaded config.""" + def _load_env_log_level(self) -> Optional[str]: + """Load the log level override from the environment, if one exists.""" + raw_level = os.environ.get("SOULSYNC_LOG_LEVEL") + if not raw_level: + return None + + level = raw_level.upper() + if level not in self._VALID_LOG_LEVELS: + logger.warning(f"Ignoring invalid SOULSYNC_LOG_LEVEL value: {raw_level}") + return None + + return level + + def _apply_log_level_overrides(self, config_data: Dict[str, Any]) -> Dict[str, Any]: + """Overlay env and persisted log level preferences onto the loaded config.""" + env_level = self._load_env_log_level() + if env_level: + config_data.setdefault("logging", {})["level"] = env_level + logger.info(f"Using log level from SOULSYNC_LOG_LEVEL: {env_level}") + return config_data + stored_level = self._load_stored_log_level() if stored_level: config_data.setdefault("logging", {})["level"] = stored_level @@ -554,7 +573,7 @@ class ConfigManager: if config_data: # Configuration exists in database - self.config_data = self._apply_stored_log_level(config_data) + self.config_data = self._apply_log_level_overrides(config_data) # Ensure sensitive values are encrypted at rest (one-time migration) self._migrate_encrypt_if_needed() return @@ -568,11 +587,11 @@ class ConfigManager: logger.info("Migrating configuration from config.json to database...") if self._save_to_database(config_data): logger.info("Configuration migrated successfully to database.") - self.config_data = self._apply_stored_log_level(config_data) + self.config_data = self._apply_log_level_overrides(config_data) return else: logger.warning("Migration failed - using file-based config temporarily.") - self.config_data = self._apply_stored_log_level(config_data) + self.config_data = self._apply_log_level_overrides(config_data) return # No config.json either - use defaults @@ -585,7 +604,7 @@ class ConfigManager: else: logger.warning("Could not save defaults to database - using in-memory config") - self.config_data = self._apply_stored_log_level(config_data) + self.config_data = self._apply_log_level_overrides(config_data) def _save_config(self): """Save configuration to database with retry on lock."""