import sys import os from loguru import logger from app.core.config import settings from pathlib import Path from app.core.request_id import get_request_id # ── 1. Remove default loguru handler ────────────────────────────────────────── logger.remove() # ── 2. Inject request_id into every log record ─────────────────────────────── def _inject_request_id(record): req_id = get_request_id() record["extra"]["request_id"] = req_id if req_id else "SYSTEM" logger.configure(patcher=_inject_request_id) import logging logging.getLogger("uvicorn.access").disabled = True # ── 3. Log directory ────────────────────────────────────────────────────────── log_dir = Path("app_logs") log_dir.mkdir(parents=True, exist_ok=True) # ── 4. Console — structured JSON for production, colorized text for local ───── IS_PROD = os.environ.get("ENVIRONMENT", "development").lower() in ("production", "prod") if IS_PROD: # Production: pure JSON, machine-readable — timestamp in 12-hour AM/PM UTC logger.add( sys.stdout, format="{message}", serialize=True, # emits {"text":..., "record":{...}} JSON lines level=settings.LOG_LEVEL, enqueue=True, ) else: # Local dev: human-readable with color, 12-hour AM/PM format logger.add( sys.stdout, format=( "{time:MM-DD-YYYY hh:mm:ss A} | " "{level:<8} | " "[{extra[request_id]}] " "{name}:{function}:{line} — {message}" ), colorize=True, level=settings.LOG_LEVEL, enqueue=True, ) # ── 5. File logger — 12-hour AM/PM timestamp ───────────────────────────────── logger.add( "app_logs/api_{time:YYYY-MM-DD}.log", rotation="00:00", retention="30 days", compression="zip", level="INFO", # hh = 12-hour clock, A = AM/PM format="{time:MM-DD-YYYY hh:mm:ss A} | {level:<8} | [{extra[request_id]}] {name}:{function}:{line} — {message}", enqueue=True, ) # ── 6. New Relic sink (optional — never crashes the app) ────────────────────── _NR_KEY = os.environ.get("NEW_RELIC_LICENSE_KEY", "") if _NR_KEY: try: import newrelic.agent try: newrelic.agent.initialize() except Exception: pass def _newrelic_sink(message): record = message.record try: newrelic.agent.record_log_event( message=record["message"], level=record["level"].name, timestamp=int(record["time"].timestamp() * 1000), attributes={ "request_id": record["extra"].get("request_id", "SYSTEM"), "method": record["extra"].get("method", ""), "path": record["extra"].get("path", ""), "status": record["extra"].get("status", ""), "duration_ms": record["extra"].get("duration_ms", ""), "logger": record["name"], "function": record["function"], "line": record["line"], } ) except Exception: pass # Cloud logging must never affect the app logger.add(_newrelic_sink, level="INFO", enqueue=True) except ImportError: pass except Exception: pass