335 Zeilen
12 KiB
Python
335 Zeilen
12 KiB
Python
"""
|
|
Log Account Creation Use Case - Strukturiertes Logging für Account-Erstellung
|
|
"""
|
|
|
|
import logging
|
|
import time
|
|
from typing import Dict, Any, Optional, List
|
|
from datetime import datetime, timedelta
|
|
import uuid
|
|
|
|
from domain.services.analytics_service import IAnalyticsService
|
|
from domain.entities.account_creation_event import (
|
|
AccountCreationEvent, AccountData, WorkflowStep,
|
|
WorkflowStepStatus, ErrorDetails
|
|
)
|
|
from domain.value_objects.action_timing import ActionType
|
|
|
|
logger = logging.getLogger("log_account_creation_use_case")
|
|
|
|
|
|
class LogAccountCreationUseCase:
|
|
"""
|
|
Use Case für strukturiertes Logging von Account-Erstellungen.
|
|
Trackt detaillierte Steps, Performance-Metriken und Fehler-Kontextualisierung.
|
|
"""
|
|
|
|
def __init__(self, analytics_service: IAnalyticsService):
|
|
self.analytics_service = analytics_service
|
|
self.active_events = {} # event_id -> AccountCreationEvent
|
|
|
|
def start_tracking(self,
|
|
platform: str,
|
|
session_id: str,
|
|
fingerprint_id: str,
|
|
context: Optional[Dict[str, Any]] = None) -> str:
|
|
"""
|
|
Startet Tracking für neue Account-Erstellung.
|
|
|
|
Args:
|
|
platform: Zielplattform
|
|
session_id: Session ID
|
|
fingerprint_id: Fingerprint ID
|
|
context: Zusätzlicher Kontext
|
|
|
|
Returns:
|
|
Event ID für weiteres Tracking
|
|
"""
|
|
event = AccountCreationEvent(
|
|
event_id=str(uuid.uuid4()),
|
|
timestamp=datetime.now(),
|
|
session_id=session_id,
|
|
fingerprint_id=fingerprint_id,
|
|
proxy_used=context.get('proxy_used', False) if context else False,
|
|
proxy_type=context.get('proxy_type') if context else None,
|
|
browser_type=context.get('browser_type', 'chromium') if context else 'chromium',
|
|
headless=context.get('headless', False) if context else False
|
|
)
|
|
|
|
# Speichere temporär für Step-Tracking
|
|
self.active_events[event.event_id] = event
|
|
|
|
logger.info(f"Started tracking account creation {event.event_id} for {platform}")
|
|
|
|
return event.event_id
|
|
|
|
def track_step(self,
|
|
event_id: str,
|
|
step_name: str,
|
|
metadata: Optional[Dict[str, Any]] = None) -> None:
|
|
"""
|
|
Beginnt Tracking eines Workflow-Schritts.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
step_name: Name des Schritts
|
|
metadata: Zusätzliche Metadaten
|
|
"""
|
|
event = self.active_events.get(event_id)
|
|
if not event:
|
|
logger.error(f"No active event found for {event_id}")
|
|
return
|
|
|
|
step = WorkflowStep(
|
|
step_name=step_name,
|
|
start_time=datetime.now(),
|
|
status=WorkflowStepStatus.IN_PROGRESS,
|
|
metadata=metadata or {}
|
|
)
|
|
|
|
event.add_step(step)
|
|
logger.debug(f"Started step '{step_name}' for event {event_id}")
|
|
|
|
def complete_step(self,
|
|
event_id: str,
|
|
step_name: str,
|
|
success: bool = True,
|
|
error_message: Optional[str] = None,
|
|
retry_count: int = 0) -> None:
|
|
"""
|
|
Markiert einen Schritt als abgeschlossen.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
step_name: Name des Schritts
|
|
success: Ob Schritt erfolgreich war
|
|
error_message: Fehlermeldung bei Misserfolg
|
|
retry_count: Anzahl der Wiederholungen
|
|
"""
|
|
event = self.active_events.get(event_id)
|
|
if not event:
|
|
logger.error(f"No active event found for {event_id}")
|
|
return
|
|
|
|
step = event.get_step(step_name)
|
|
if not step:
|
|
logger.error(f"Step '{step_name}' not found in event {event_id}")
|
|
return
|
|
|
|
step.end_time = datetime.now()
|
|
step.status = WorkflowStepStatus.COMPLETED if success else WorkflowStepStatus.FAILED
|
|
step.retry_count = retry_count
|
|
step.error_message = error_message
|
|
|
|
# Update Metriken
|
|
event.network_requests += step.metadata.get('network_requests', 0)
|
|
event.screenshots_taken += step.metadata.get('screenshots', 0)
|
|
|
|
logger.debug(f"Completed step '{step_name}' for event {event_id} "
|
|
f"(success: {success}, duration: {step.duration})")
|
|
|
|
def set_account_data(self,
|
|
event_id: str,
|
|
username: str,
|
|
password: str,
|
|
email: str,
|
|
additional_data: Optional[Dict[str, Any]] = None) -> None:
|
|
"""
|
|
Setzt Account-Daten für erfolgreich erstellten Account.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
username: Benutzername
|
|
password: Passwort
|
|
email: E-Mail
|
|
additional_data: Zusätzliche Daten
|
|
"""
|
|
event = self.active_events.get(event_id)
|
|
if not event:
|
|
logger.error(f"No active event found for {event_id}")
|
|
return
|
|
|
|
event.account_data = AccountData(
|
|
platform=additional_data.get('platform', 'unknown') if additional_data else 'unknown',
|
|
username=username,
|
|
password=password,
|
|
email=email,
|
|
phone=additional_data.get('phone') if additional_data else None,
|
|
full_name=additional_data.get('full_name') if additional_data else None,
|
|
birthday=additional_data.get('birthday') if additional_data else None,
|
|
verification_status=additional_data.get('verification_status', 'unverified') if additional_data else 'unverified',
|
|
metadata=additional_data or {}
|
|
)
|
|
|
|
logger.info(f"Set account data for {username} in event {event_id}")
|
|
|
|
def log_error(self,
|
|
event_id: str,
|
|
error_type: str,
|
|
error_message: str,
|
|
stack_trace: Optional[str] = None,
|
|
screenshot_path: Optional[str] = None,
|
|
context: Optional[Dict[str, Any]] = None) -> None:
|
|
"""
|
|
Loggt einen Fehler während der Account-Erstellung.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
error_type: Typ des Fehlers
|
|
error_message: Fehlermeldung
|
|
stack_trace: Stack Trace
|
|
screenshot_path: Pfad zum Fehler-Screenshot
|
|
context: Fehler-Kontext
|
|
"""
|
|
event = self.active_events.get(event_id)
|
|
if not event:
|
|
logger.error(f"No active event found for {event_id}")
|
|
return
|
|
|
|
event.error_details = ErrorDetails(
|
|
error_type=error_type,
|
|
error_message=error_message,
|
|
stack_trace=stack_trace,
|
|
screenshot_path=screenshot_path,
|
|
context=context or {}
|
|
)
|
|
|
|
logger.error(f"Logged error for event {event_id}: {error_type} - {error_message}")
|
|
|
|
def finish_tracking(self,
|
|
event_id: str,
|
|
success: bool,
|
|
final_status: Optional[Dict[str, Any]] = None) -> None:
|
|
"""
|
|
Beendet Tracking und speichert Event.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
success: Ob Account-Erstellung erfolgreich war
|
|
final_status: Finaler Status/Metadaten
|
|
"""
|
|
event = self.active_events.get(event_id)
|
|
if not event:
|
|
logger.error(f"No active event found for {event_id}")
|
|
return
|
|
|
|
# Setze finale Eigenschaften
|
|
event.success = success
|
|
event.calculate_duration()
|
|
|
|
# Füge finale Metadaten hinzu
|
|
if final_status:
|
|
if event.account_data:
|
|
event.account_data.metadata.update(final_status)
|
|
|
|
# Logge Event
|
|
self.analytics_service.log_event(event)
|
|
|
|
# Entferne aus aktiven Events
|
|
del self.active_events[event_id]
|
|
|
|
# Log Summary
|
|
self._log_summary(event)
|
|
|
|
def _log_summary(self, event: AccountCreationEvent) -> None:
|
|
"""Loggt eine Zusammenfassung des Events"""
|
|
summary = f"Account creation {event.event_id} "
|
|
|
|
if event.success:
|
|
summary += f"SUCCEEDED"
|
|
if event.account_data:
|
|
summary += f" - {event.account_data.username} on {event.account_data.platform}"
|
|
else:
|
|
summary += f"FAILED"
|
|
if event.error_details:
|
|
summary += f" - {event.error_details.error_type}: {event.error_details.error_message}"
|
|
|
|
if event.duration:
|
|
summary += f" (duration: {event.duration.total_seconds():.1f}s"
|
|
summary += f", steps: {len(event.steps_completed)}"
|
|
summary += f", retries: {event.total_retry_count})"
|
|
|
|
logger.info(summary)
|
|
|
|
def track_performance_metric(self,
|
|
event_id: str,
|
|
metric_name: str,
|
|
value: float,
|
|
tags: Optional[Dict[str, str]] = None) -> None:
|
|
"""
|
|
Trackt eine Performance-Metrik.
|
|
|
|
Args:
|
|
event_id: Event ID
|
|
metric_name: Name der Metrik
|
|
value: Wert der Metrik
|
|
tags: Zusätzliche Tags
|
|
"""
|
|
# Tracke über Analytics Service
|
|
metric_tags = tags or {}
|
|
metric_tags['event_id'] = event_id
|
|
|
|
self.analytics_service.track_performance(metric_name, value, metric_tags)
|
|
|
|
def get_active_events(self) -> List[Dict[str, Any]]:
|
|
"""Gibt Liste aktiver Events zurück"""
|
|
active = []
|
|
|
|
for event_id, event in self.active_events.items():
|
|
duration = (datetime.now() - event.timestamp).total_seconds()
|
|
current_step = None
|
|
|
|
# Finde aktuellen Schritt
|
|
for step in event.steps_completed:
|
|
if step.status == WorkflowStepStatus.IN_PROGRESS:
|
|
current_step = step.step_name
|
|
break
|
|
|
|
active.append({
|
|
'event_id': event_id,
|
|
'started_at': event.timestamp.isoformat(),
|
|
'duration_seconds': duration,
|
|
'current_step': current_step,
|
|
'steps_completed': len([s for s in event.steps_completed
|
|
if s.status == WorkflowStepStatus.COMPLETED]),
|
|
'platform': event.account_data.platform if event.account_data else 'unknown'
|
|
})
|
|
|
|
return active
|
|
|
|
def cleanup_stale_events(self, timeout_minutes: int = 30) -> int:
|
|
"""
|
|
Bereinigt Events die zu lange laufen.
|
|
|
|
Args:
|
|
timeout_minutes: Timeout in Minuten
|
|
|
|
Returns:
|
|
Anzahl bereinigter Events
|
|
"""
|
|
stale_events = []
|
|
timeout = timedelta(minutes=timeout_minutes)
|
|
|
|
for event_id, event in self.active_events.items():
|
|
if datetime.now() - event.timestamp > timeout:
|
|
stale_events.append(event_id)
|
|
|
|
for event_id in stale_events:
|
|
event = self.active_events[event_id]
|
|
|
|
# Markiere als Timeout
|
|
self.log_error(
|
|
event_id,
|
|
'timeout',
|
|
f'Event timed out after {timeout_minutes} minutes',
|
|
context={'timeout_minutes': timeout_minutes}
|
|
)
|
|
|
|
# Beende Tracking
|
|
self.finish_tracking(event_id, success=False,
|
|
final_status={'reason': 'timeout'})
|
|
|
|
if stale_events:
|
|
logger.warning(f"Cleaned up {len(stale_events)} stale events")
|
|
|
|
return len(stale_events) |