""" Structured Analytics Service - Konkrete Implementation für Analytics """ import logging import json from typing import List, Optional, Dict, Any, Union from datetime import datetime, timedelta import uuid from domain.services.analytics_service import IAnalyticsService from domain.entities.account_creation_event import AccountCreationEvent from domain.entities.error_event import ErrorEvent from domain.value_objects.error_summary import ErrorSummary from domain.value_objects.report import Report, ReportType, Metric, PlatformStats, TimeSeriesData from infrastructure.repositories.analytics_repository import AnalyticsRepository logger = logging.getLogger("structured_analytics_service") class StructuredAnalyticsService(IAnalyticsService): """Konkrete Implementation des Analytics Service""" def __init__(self, repository: AnalyticsRepository = None): self.repository = repository or AnalyticsRepository() def log_event(self, event: Union[AccountCreationEvent, ErrorEvent, Any]) -> None: """Loggt ein Event für spätere Analyse""" if isinstance(event, AccountCreationEvent): self.repository.save_account_creation_event(event) logger.debug(f"Logged account creation event {event.event_id}") elif isinstance(event, ErrorEvent): self.repository.save_error_event(event) logger.debug(f"Logged error event {event.error_id}") else: logger.warning(f"Unknown event type: {type(event)}") def get_success_rate(self, timeframe: Optional[timedelta] = None, platform: Optional[str] = None) -> float: """Berechnet die Erfolgsrate""" return self.repository.get_success_rate(timeframe, platform) def get_common_errors(self, limit: int = 10, timeframe: Optional[timedelta] = None) -> List[ErrorSummary]: """Holt die häufigsten Fehler""" return self.repository.get_common_errors(limit, timeframe) def generate_report(self, report_type: ReportType, start: datetime, end: datetime, platforms: Optional[List[str]] = None) -> Report: """Generiert einen Report""" # Hole Basis-Metriken timeframe = end - start success_rate = self.get_success_rate(timeframe, platforms[0] if platforms else None) # Hole Platform-Statistiken platform_stats_data = self.repository.get_platform_stats(timeframe) platform_stats = [] for platform, stats in platform_stats_data.items(): if not platforms or platform in platforms: platform_stats.append(PlatformStats( platform=platform, total_attempts=stats['total_attempts'], successful_accounts=stats['successful_accounts'], failed_attempts=stats['failed_attempts'], avg_duration_seconds=stats['avg_duration_seconds'], error_distribution={} # TODO: Implementiere Error Distribution )) # Berechne Gesamt-Statistiken total_attempts = sum(ps.total_attempts for ps in platform_stats) total_accounts = sum(ps.successful_accounts for ps in platform_stats) avg_duration = sum(ps.avg_duration_seconds * ps.total_attempts for ps in platform_stats) / total_attempts if total_attempts > 0 else 0 # Erstelle Metriken metrics = [ Metric("success_rate", success_rate, "percentage", 0.0), Metric("total_accounts", float(total_accounts), "count", 0.0), Metric("avg_duration", avg_duration, "seconds", 0.0) ] # Hole Timeline-Daten timeline_data = self.repository.get_timeline_data('success_rate', 24, platforms[0] if platforms else None) success_timeline = None if timeline_data: timestamps = [datetime.fromisoformat(d['timestamp']) for d in timeline_data] values = [d['success_rate'] for d in timeline_data] success_timeline = TimeSeriesData(timestamps, values, "Success Rate") # Hole Error Summaries error_summaries = [] common_errors = self.get_common_errors(10, timeframe) for error in common_errors: error_summaries.append(error.to_dict()) # Erstelle Report return Report( report_id=str(uuid.uuid4()), report_type=report_type, start_date=start, end_date=end, generated_at=datetime.now(), total_accounts_created=total_accounts, total_attempts=total_attempts, overall_success_rate=success_rate, avg_creation_time=avg_duration, metrics=metrics, platform_stats=platform_stats, error_summaries=error_summaries, success_rate_timeline=success_timeline ) def get_real_time_metrics(self) -> Dict[str, Any]: """Holt Echtzeit-Metriken""" # Letzte Stunde one_hour_ago = datetime.now() - timedelta(hours=1) # Timeline für letzte Stunde timeline = self.repository.get_timeline_data('success_rate', 1) # Berechne Metriken total_attempts = sum(d['total'] for d in timeline) successful = sum(d['successful'] for d in timeline) success_rate = successful / total_attempts if total_attempts > 0 else 0 # Platform Stats platform_stats = self.repository.get_platform_stats(timedelta(hours=1)) return { 'timestamp': datetime.now().isoformat(), 'active_sessions': len(self.repository._execute_query( "SELECT DISTINCT session_id FROM account_creation_analytics WHERE timestamp > ?", (one_hour_ago,) )), 'accounts_last_hour': successful, 'attempts_last_hour': total_attempts, 'success_rate_last_hour': success_rate, 'avg_creation_time': sum( stats.get('avg_duration_seconds', 0) for stats in platform_stats.values() ) / len(platform_stats) if platform_stats else 0, 'platform_breakdown': platform_stats, 'hourly_trend': self._calculate_trend(timeline) } def _calculate_trend(self, timeline: List[Dict[str, Any]]) -> float: """Berechnet Trend aus Timeline""" if len(timeline) < 2: return 0.0 # Vergleiche erste und letzte Hälfte mid = len(timeline) // 2 first_half = timeline[:mid] second_half = timeline[mid:] first_rate = sum(d.get('success_rate', 0) for d in first_half) / len(first_half) if first_half else 0 second_rate = sum(d.get('success_rate', 0) for d in second_half) / len(second_half) if second_half else 0 if first_rate > 0: return ((second_rate - first_rate) / first_rate) * 100 return 0.0 def track_performance(self, metric_name: str, value: float, tags: Optional[Dict[str, str]] = None) -> None: """Trackt Performance-Metrik""" # Würde in echter Implementation in separater Tabelle gespeichert logger.info(f"Performance metric: {metric_name}={value} tags={tags}") def get_account_creation_timeline(self, hours: int = 24, platform: Optional[str] = None) -> Dict[str, Any]: """Holt Account Creation Timeline""" timeline = self.repository.get_timeline_data('accounts', hours, platform) return { 'hours': hours, 'platform': platform, 'data_points': timeline, 'total': sum(d['successful'] for d in timeline), 'peak_hour': max(timeline, key=lambda d: d['successful'])['timestamp'] if timeline else None } def analyze_failure_patterns(self, timeframe: Optional[timedelta] = None) -> Dict[str, Any]: """Analysiert Fehler-Muster""" errors = self.get_common_errors(50, timeframe) patterns = { 'timeframe': str(timeframe) if timeframe else 'all', 'total_error_types': len(errors), 'critical_errors': [], 'recurring_errors': [], 'error_clusters': [] } # Identifiziere kritische Fehler for error in errors: if error.severity_score > 0.7: patterns['critical_errors'].append({ 'type': error.error_type, 'frequency': error.frequency, 'impact': error.total_user_impact + error.total_system_impact }) # Identifiziere wiederkehrende Fehler for error in errors: if error.error_count > 10: patterns['recurring_errors'].append({ 'type': error.error_type, 'count': error.error_count, 'recovery_rate': error.recovery_success_rate }) return patterns def get_platform_comparison(self, timeframe: Optional[timedelta] = None) -> Dict[str, Any]: """Vergleicht Plattformen""" platform_stats = self.repository.get_platform_stats(timeframe) comparison = {} for platform, stats in platform_stats.items(): comparison[platform] = { 'success_rate': stats['success_rate'], 'total_accounts': stats['successful_accounts'], 'avg_duration': stats['avg_duration_seconds'], 'performance_score': self._calculate_platform_score(stats) } return comparison def _calculate_platform_score(self, stats: Dict[str, Any]) -> float: """Berechnet Performance Score für Platform""" # Gewichtete Bewertung success_weight = 0.5 speed_weight = 0.3 volume_weight = 0.2 # Normalisiere Werte success_score = stats['success_rate'] speed_score = 1.0 - min(stats['avg_duration_seconds'] / 300, 1.0) # 5 min max volume_score = min(stats['total_attempts'] / 100, 1.0) # 100 als Referenz return (success_score * success_weight + speed_score * speed_weight + volume_score * volume_weight) def export_data(self, format: str = "json", start: Optional[datetime] = None, end: Optional[datetime] = None) -> bytes: """Exportiert Daten""" # Generiere Report für Zeitraum report = self.generate_report( ReportType.CUSTOM, start or datetime.now() - timedelta(days=7), end or datetime.now() ) if format == "json": return json.dumps(report.to_dict(), indent=2).encode() elif format == "csv": # Vereinfachte CSV-Implementation csv_data = "platform,attempts,success,rate\n" for stat in report.platform_stats: csv_data += f"{stat.platform},{stat.total_attempts},{stat.successful_accounts},{stat.success_rate}\n" return csv_data.encode() else: raise ValueError(f"Unsupported format: {format}") def cleanup_old_events(self, older_than: datetime) -> int: """Bereinigt alte Events""" return self.repository.cleanup_old_events(older_than)