""" Feature Usage Logger for Mitai Jinkendo Logs all feature access checks to a separate JSON log file for analysis. Phase 2: Non-blocking monitoring of feature usage. """ import logging import json from datetime import datetime from pathlib import Path # ── Setup Feature Usage Logger ─────────────────────────────────────────────── feature_usage_logger = logging.getLogger('feature_usage') feature_usage_logger.setLevel(logging.INFO) feature_usage_logger.propagate = False # Don't propagate to root logger # Ensure logs directory exists LOG_DIR = Path('/app/logs') LOG_DIR.mkdir(parents=True, exist_ok=True) # FileHandler for JSON logs log_file = LOG_DIR / 'feature-usage.log' file_handler = logging.FileHandler(log_file) file_handler.setLevel(logging.INFO) file_handler.setFormatter(logging.Formatter('%(message)s')) # JSON only feature_usage_logger.addHandler(file_handler) # Also log to console in dev (optional) # console_handler = logging.StreamHandler() # console_handler.setFormatter(logging.Formatter('[FEATURE-USAGE] %(message)s')) # feature_usage_logger.addHandler(console_handler) # ── Logging Function ────────────────────────────────────────────────────────── def log_feature_usage(user_id: str, feature_id: str, access: dict, action: str): """ Log feature usage in structured JSON format. Args: user_id: Profile UUID feature_id: Feature identifier (e.g., 'weight_entries', 'ai_calls') access: Result from check_feature_access() containing: - allowed: bool - limit: int | None - used: int - remaining: int | None - reason: str action: Type of action (e.g., 'create', 'export', 'analyze') Example log entry: { "timestamp": "2026-03-20T15:30:45.123456", "user_id": "abc-123", "feature": "weight_entries", "action": "create", "used": 5, "limit": 100, "remaining": 95, "allowed": true, "reason": "within_limit" } """ entry = { "timestamp": datetime.now().isoformat(), "user_id": user_id, "feature": feature_id, "action": action, "used": access.get('used', 0), "limit": access.get('limit'), # None for unlimited "remaining": access.get('remaining'), # None for unlimited "allowed": access.get('allowed', True), "reason": access.get('reason', 'unknown') } feature_usage_logger.info(json.dumps(entry))