Spotix-API / backend /app /core /logger.py
Anish-530
Fixed visual problem of the vanishing heatmap. Also fixed redundant logs
09cc5a2
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=(
"<green>{time:MM-DD-YYYY hh:mm:ss A}</green> | "
"<level>{level:<8}</level> | "
"<cyan>[{extra[request_id]}]</cyan> "
"<white>{name}:{function}:{line}</white> β€” {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