feat(observability): structured logging, metrics wiring, graceful degradation

- Item 5: Convert remaining printf-style logger call to structured logging
  (key=value format) in x402_middleware.py
- Item 6: Wire CACHE_HITS counter into cache get() and per-tier SCRAPE_LATENCY
  histogram into UltimateScraper scrape loop
- Item 7: Add circuit-breaker checks in extractor.py (Ollama) and
  routers/vision.py (OpenRouter) to fail fast and record success/failure
  when external services are down; attach recovery results to resilience
  registry for per-service circuit state

560 tests passing, ruff clean
This commit is contained in:
Crypto Rug Munch 2026-07-03 12:13:03 +02:00
parent 2970c15dbb
commit 5a21133b1d
5 changed files with 20 additions and 1 deletions

View file

@ -19,6 +19,7 @@ from fastapi import APIRouter, Body
from client import get_client
from deps import automator
from errors import ExternalServiceError, InvalidRequestError, PryError, ScrapeError
from resilience import registry
from settings import settings
logger = logging.getLogger(__name__)
@ -171,6 +172,8 @@ async def _call_vision_api(
key = _get_or_key()
if not key:
return None, None, "OPENROUTER_API_KEY not set"
if not registry.is_service_allowed("openrouter"):
return None, None, "OpenRouter circuit breaker open"
# Accept either data URI or raw base64
data_uri = image_b64 if image_b64.startswith("data:") else f"data:image/png;base64,{image_b64}"
@ -203,6 +206,7 @@ async def _call_vision_api(
)
resp.raise_for_status()
body = resp.json()
registry.record_service_result("openrouter", True)
return body["choices"][0]["message"]["content"], model, None