Files
AccountForger-neuerUpload/application/use_cases/log_account_creation_use_case.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

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)