Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import logging | |
| import os | |
| from typing import Any, Dict, Optional | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| logger = logging.getLogger("integrachat.mcp") | |
| if not logger.handlers: | |
| handler = logging.StreamHandler() | |
| formatter = logging.Formatter( | |
| "[%(asctime)s] %(levelname)s %(name)s - %(message)s", | |
| datefmt="%Y-%m-%d %H:%M:%S", | |
| ) | |
| handler.setFormatter(formatter) | |
| logger.addHandler(handler) | |
| logger.setLevel(os.getenv("LOG_LEVEL", "INFO").upper()) | |
| try: | |
| from backend.api.storage.analytics_store import AnalyticsStore | |
| except Exception: # pragma: no cover - analytics storage is optional during tests | |
| AnalyticsStore = None # type: ignore | |
| _analytics_store: Optional["AnalyticsStore"] = None | |
| _analytics_failed = False | |
| _analytics_disabled = os.getenv("ANALYTICS_DISABLED", "").lower() in {"1", "true", "yes"} | |
| def _get_analytics_store() -> Optional["AnalyticsStore"]: | |
| """ | |
| Lazily create the analytics store so missing Supabase credentials or package | |
| do not prevent the MCP server from starting. When initialization fails we | |
| keep analytics disabled for the remainder of the process. | |
| """ | |
| global _analytics_store, _analytics_failed | |
| if _analytics_disabled or _analytics_failed: | |
| return None | |
| if _analytics_store is not None: | |
| return _analytics_store | |
| if AnalyticsStore is None: | |
| _analytics_failed = True | |
| return None | |
| try: | |
| _analytics_store = AnalyticsStore() | |
| except RuntimeError as exc: | |
| logger.warning("Analytics disabled: %s", exc) | |
| _analytics_failed = True | |
| _analytics_store = None | |
| except Exception as exc: # pragma: no cover - unexpected failures | |
| logger.debug("Unexpected analytics init failure: %s", exc) | |
| _analytics_failed = True | |
| _analytics_store = None | |
| return _analytics_store | |
| def log_tool_usage( | |
| tool_name: str, | |
| tenant_id: Optional[str], | |
| *, | |
| success: bool, | |
| latency_ms: Optional[int] = None, | |
| metadata: Optional[Dict[str, Any]] = None, | |
| error_message: Optional[str] = None, | |
| user_id: Optional[str] = None, | |
| ): | |
| log_data = { | |
| "tool": tool_name, | |
| "tenant_id": tenant_id, | |
| "success": success, | |
| "latency_ms": latency_ms, | |
| "user_id": user_id, | |
| "metadata": metadata or {}, | |
| } | |
| if error_message: | |
| log_data["error"] = error_message | |
| if success: | |
| logger.info("tool_completed %s", log_data) | |
| else: | |
| logger.warning("tool_failed %s", log_data) | |
| store = _get_analytics_store() | |
| if store and tenant_id: | |
| try: | |
| store.log_tool_usage( | |
| tenant_id=tenant_id, | |
| tool_name=tool_name, | |
| latency_ms=latency_ms, | |
| success=success, | |
| error_message=error_message, | |
| metadata=metadata, | |
| user_id=user_id, | |
| ) | |
| except Exception as exc: # pragma: no cover - analytics failures shouldn't crash tools | |
| logger.debug("analytics logging failed: %s", exc) | |
| def log_rag_search_metrics( | |
| tenant_id: str, | |
| query: str, | |
| hits_count: int, | |
| avg_score: Optional[float], | |
| top_score: Optional[float], | |
| latency_ms: Optional[int] = None, | |
| ): | |
| store = _get_analytics_store() | |
| if store: | |
| try: | |
| store.log_rag_search( | |
| tenant_id=tenant_id, | |
| query=query, | |
| hits_count=hits_count, | |
| avg_score=avg_score, | |
| top_score=top_score, | |
| latency_ms=latency_ms, | |
| ) | |
| except Exception as exc: # pragma: no cover | |
| logger.debug("rag analytics logging failed: %s", exc) | |
| def log_redflag_violation( | |
| tenant_id: str, | |
| rule_id: str, | |
| rule_pattern: str, | |
| severity: str, | |
| matched_text: str, | |
| *, | |
| confidence: Optional[float] = None, | |
| message_preview: Optional[str] = None, | |
| user_id: Optional[str] = None, | |
| ): | |
| store = _get_analytics_store() | |
| if store: | |
| try: | |
| store.log_redflag_violation( | |
| tenant_id=tenant_id, | |
| rule_id=rule_id, | |
| rule_pattern=rule_pattern, | |
| severity=severity, | |
| matched_text=matched_text, | |
| confidence=confidence, | |
| message_preview=message_preview, | |
| user_id=user_id, | |
| ) | |
| except Exception as exc: # pragma: no cover | |
| logger.debug("redflag logging failed: %s", exc) | |