From b4b486e908bd8c6c406bfa5c612a6a28785bc8dd Mon Sep 17 00:00:00 2001 From: Deeman Date: Tue, 24 Feb 2026 10:50:10 +0100 Subject: [PATCH] feat(logging): add setup_logging() to core.py, wire into app startup - Add logging import and setup_logging() that reads LOG_LEVEL env var (defaults DEBUG in dev, INFO in prod), sets format with timestamp + level + logger name, silences hypercorn/asyncio noise - Add module-level logger to core.py - Convert 3 [EMAIL] print() calls to logger.info / logger.error - Call setup_logging() from app.py at import time Co-Authored-By: Claude Sonnet 4.6 --- web/src/padelnomics/app.py | 4 +++- web/src/padelnomics/core.py | 23 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/web/src/padelnomics/app.py b/web/src/padelnomics/app.py index 75c9f78..2ffda12 100644 --- a/web/src/padelnomics/app.py +++ b/web/src/padelnomics/app.py @@ -7,7 +7,9 @@ from pathlib import Path from quart import Quart, Response, abort, g, redirect, request, session, url_for from .analytics import close_analytics_db, open_analytics_db -from .core import close_db, config, get_csrf_token, init_db, is_flag_enabled, setup_request_id +from .core import close_db, config, get_csrf_token, init_db, is_flag_enabled, setup_logging, setup_request_id + +setup_logging() from .i18n import LANG_BLUEPRINTS, SUPPORTED_LANGS, get_translations _ASSET_VERSION = str(int(time.time())) diff --git a/web/src/padelnomics/core.py b/web/src/padelnomics/core.py index 5260ec0..769c718 100644 --- a/web/src/padelnomics/core.py +++ b/web/src/padelnomics/core.py @@ -4,6 +4,7 @@ Core infrastructure: database, config, email, and shared utilities. import hashlib import hmac +import logging import os import random import re @@ -88,6 +89,22 @@ class Config: config = Config() + +def setup_logging() -> None: + """Configure root logger. Call once from each entry point (app, worker, scripts).""" + level_name = os.environ.get("LOG_LEVEL", "DEBUG" if config.DEBUG else "INFO") + level = getattr(logging, level_name.upper(), logging.INFO) + logging.basicConfig( + level=level, + format="%(asctime)s %(levelname)-8s %(name)s: %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + logging.getLogger("hypercorn").setLevel(logging.WARNING) + logging.getLogger("asyncio").setLevel(logging.WARNING) + + +logger = logging.getLogger(__name__) + # ============================================================================= # Database # ============================================================================= @@ -364,7 +381,7 @@ async def send_email( resend_id = None if not config.RESEND_API_KEY: - print(f"[EMAIL] Would send to {to}: {subject}") + logger.info("Would send to %s: %s", to, subject) resend_id = "dev" else: resend.api_key = config.RESEND_API_KEY @@ -380,7 +397,7 @@ async def send_email( ) resend_id = result.get("id") if isinstance(result, dict) else getattr(result, "id", None) except Exception as e: - print(f"[EMAIL] Error sending to {to}: {e}") + logger.error("Error sending to %s: %s", to, e) return None # Log to email_log (best-effort, never fail the send) @@ -391,7 +408,7 @@ async def send_email( (resend_id, sender, to, subject, email_type), ) except Exception as e: - print(f"[EMAIL] Failed to log email: {e}") + logger.error("Failed to log email: %s", e) return resend_id