Spaces:
Sleeping
Sleeping
| """ | |
| Shadow Mode Logger. | |
| Structured JSON logging for shadow predictions (production testing). | |
| """ | |
| import json | |
| import logging | |
| from datetime import datetime | |
| from typing import Dict, Any | |
| # Configure shadow prediction logger | |
| shadow_logger = logging.getLogger("shadow_predictions") | |
| shadow_logger.setLevel(logging.INFO) | |
| # File handler for shadow predictions | |
| handler = logging.FileHandler("logs/shadow_predictions.jsonl") | |
| handler.setFormatter(logging.Formatter("%(message)s")) | |
| shadow_logger.addHandler(handler) | |
| def log_shadow_prediction( | |
| request_data: Dict[str, Any], probability: float, real_decision: str, latency_ms: float | |
| ) -> None: | |
| """ | |
| Log a shadow prediction for comparison with production. | |
| Shadow mode allows testing new models in production without | |
| affecting real transactions. All decisions are logged but | |
| the API always returns APPROVE to the user. | |
| Args: | |
| request_data: Original request payload | |
| probability: Model's fraud probability | |
| real_decision: What the model would have decided (BLOCK/APPROVE) | |
| latency_ms: Processing time | |
| Example log entry: | |
| { | |
| "timestamp": "2020-06-15T14:30:00Z", | |
| "user_id": "u12345", | |
| "amt": 150.0, | |
| "real_decision": "BLOCK", | |
| "probability": 0.923, | |
| "latency_ms": 12.5, | |
| "shadow_mode": true | |
| } | |
| """ | |
| log_entry = { | |
| "timestamp": datetime.utcnow().isoformat() + "Z", | |
| "user_id": request_data.get("user_id"), | |
| "amt": float(request_data.get("amt")) if request_data.get("amt") is not None else None, | |
| "category": request_data.get("category"), | |
| "real_decision": real_decision, | |
| "probability": float(probability), # Convert numpy float32 to Python float | |
| "latency_ms": float(latency_ms), | |
| "shadow_mode": True, | |
| } | |
| shadow_logger.info(json.dumps(log_entry)) | |
| __all__ = ["log_shadow_prediction", "shadow_logger"] | |