Files
michaelschiemer/docs/components/analytics/examples.md
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

22 KiB

Analytics Framework Beispiele

Dokumentationshinweis: Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Analytics Frameworks korrekt dar.

Übersicht

Diese Dokumentation enthält praktische Beispiele für die Verwendung des Analytics Frameworks in verschiedenen Szenarien. Die Beispiele zeigen, wie Sie Analytics-Daten erfassen, analysieren und in Ihre Anwendung integrieren können.

Grundlegende Verwendung

Benutzeraktionen erfassen

use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;

class UserController
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector
    ) {}
    
    public function handleLogin(Request $request): Response
    {
        // Login-Logik
        $success = $this->authService->login($request->getParam('email'), $request->getParam('password'));
        
        // Login-Aktion erfassen
        $this->analyticsCollector->trackAction(
            'user_login',
            AnalyticsCategory::USER,
            [
                'success' => $success,
                'email_domain' => explode('@', $request->getParam('email'))[1] ?? 'unknown',
                'ip' => $request->getClientIp(),
                'user_agent' => $request->getUserAgent()
            ]
        );
        
        // Antwort zurückgeben
        return $success
            ? $this->redirect('/dashboard')
            : $this->renderForm('login', ['error' => 'Ungültige Anmeldedaten']);
    }
}

Seitenaufrufe erfassen

use App\Framework\Analytics\AnalyticsCollector;

class ProductController
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly ProductRepository $productRepository
    ) {}
    
    public function showProduct(Request $request, string $productId): Response
    {
        $product = $this->productRepository->find($productId);
        
        if (!$product) {
            return $this->notFound();
        }
        
        // Seitenaufruf erfassen
        $this->analyticsCollector->trackPageView(
            "/products/{$productId}",
            [
                'product_id' => $productId,
                'product_name' => $product->name,
                'product_category' => $product->category,
                'referrer' => $request->getHeader('Referer'),
                'user_id' => $this->session->get('user_id')
            ]
        );
        
        return $this->render('product', ['product' => $product]);
    }
}

Fehler erfassen

use App\Framework\Analytics\AnalyticsCollector;

class ErrorHandler
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly Logger $logger
    ) {}
    
    public function handleException(\Throwable $exception): Response
    {
        // Fehler loggen
        $this->logger->error('Unbehandelte Ausnahme: ' . $exception->getMessage(), [
            'exception' => $exception
        ]);
        
        // Fehler für Analytics erfassen
        $this->analyticsCollector->trackError(
            get_class($exception),
            [
                'message' => $exception->getMessage(),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'trace' => $exception->getTraceAsString(),
                'request_uri' => $_SERVER['REQUEST_URI'] ?? null,
                'user_id' => $this->session->get('user_id')
            ]
        );
        
        // Fehlerseite anzeigen
        return new Response(500, [], 'Ein Fehler ist aufgetreten');
    }
}

Geschäftsereignisse erfassen

use App\Framework\Analytics\AnalyticsCollector;

class OrderService
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly OrderRepository $orderRepository
    ) {}
    
    public function placeOrder(Order $order): bool
    {
        // Bestellung speichern
        $success = $this->orderRepository->save($order);
        
        if ($success) {
            // Geschäftsereignis erfassen
            $this->analyticsCollector->trackBusinessEvent(
                'order_placed',
                [
                    'order_id' => $order->id,
                    'user_id' => $order->userId,
                    'total_amount' => $order->totalAmount,
                    'items_count' => count($order->items),
                    'payment_method' => $order->paymentMethod,
                    'shipping_country' => $order->shippingAddress->country
                ]
            );
        }
        
        return $success;
    }
}

API-Aufrufe erfassen

use App\Framework\Analytics\AnalyticsCollector;

class ApiClient
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly HttpClient $httpClient
    ) {}
    
    public function sendRequest(string $endpoint, string $method, array $data = []): Response
    {
        $startTime = microtime(true);
        
        try {
            $response = $this->httpClient->request($method, $endpoint, $data);
            $statusCode = $response->getStatusCode();
            $success = $statusCode >= 200 && $statusCode < 300;
        } catch (\Exception $e) {
            $statusCode = 0;
            $success = false;
        }
        
        $duration = (microtime(true) - $startTime) * 1000; // in ms
        
        // API-Aufruf erfassen
        $this->analyticsCollector->trackApiCall(
            $endpoint,
            $method,
            $statusCode,
            [
                'duration' => $duration,
                'success' => $success,
                'data_size' => strlen(json_encode($data)),
                'user_id' => $this->session->get('user_id')
            ]
        );
        
        return $response;
    }
}

Fortgeschrittene Verwendung

Automatische Erfassung mit Middleware

Die AnalyticsMiddleware erfasst automatisch Seitenaufrufe und API-Aufrufe:

use App\Framework\Analytics\Middleware\AnalyticsMiddleware;

// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(AnalyticsMiddleware::class);

Anpassung der Middleware für bestimmte Routen:

use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
use App\Framework\Http\MiddlewareContext;
use App\Framework\Http\Next;

class CustomAnalyticsMiddleware extends AnalyticsMiddleware
{
    public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext
    {
        $request = $context->request;
        
        // Bestimmte Routen ausschließen
        if (str_starts_with($request->path, '/api/health') || str_starts_with($request->path, '/static/')) {
            return $next($context);
        }
        
        // Zusätzliche Daten für bestimmte Routen hinzufügen
        $additionalData = [];
        if (str_starts_with($request->path, '/products/')) {
            $productId = substr($request->path, 10);
            $additionalData['product_id'] = $productId;
        }
        
        // Standardverhalten mit zusätzlichen Daten
        return parent::__invoke($context, $next, $additionalData);
    }
}

Sicherheitsereignisse erfassen

Integration mit dem Security-System:

use App\Framework\Analytics\Listeners\SecurityAnalyticsListener;
use App\Framework\Analytics\Bridges\SecurityEventBridge;
use App\Framework\Security\Events\LoginAttemptEvent;

// In der Bootstrap-Datei
$securityEventBridge = SecurityEventBridge::create(
    $container->get(SecurityAnalyticsListener::class),
    $config->securityAnalyticsEnabled
);

$eventDispatcher->addListener(LoginAttemptEvent::class, [$securityEventBridge, 'handleSecurityEvent']);

Benutzerdefinierter Security-Event-Listener:

use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;
use App\Framework\Security\Events\LoginAttemptEvent;

class LoginAnalyticsListener
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector
    ) {}
    
    public function onLoginAttempt(LoginAttemptEvent $event): void
    {
        $this->analyticsCollector->trackAction(
            'login_attempt',
            AnalyticsCategory::SECURITY,
            [
                'username' => $event->getUsername(),
                'success' => $event->isSuccessful(),
                'ip' => $event->getIp(),
                'user_agent' => $event->getUserAgent(),
                'timestamp' => $event->getTimestamp()->format('Y-m-d H:i:s')
            ]
        );
    }
}

Asynchrone Datenerfassung

Für maximale Leistung kann die Analytics-Datenerfassung asynchron erfolgen:

use App\Framework\Analytics\AsyncAnalyticsCollector;
use App\Framework\Queue\QueueInterface;

class AsyncAnalyticsService
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly QueueInterface $queue
    ) {}
    
    public function initialize(): void
    {
        // Asynchronen Collector erstellen
        $asyncCollector = new AsyncAnalyticsCollector(
            $this->analyticsCollector,
            $this->queue
        );
        
        // Asynchronen Collector registrieren
        $this->container->set(AnalyticsCollector::class, $asyncCollector);
    }
}

Benutzerdefinierte Ereignistypen

Sie können benutzerdefinierte Ereignistypen für spezifische Anforderungen erstellen:

use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;

class CustomAnalyticsService
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector
    ) {}
    
    public function trackProductView(string $productId, string $productName, string $category): void
    {
        $this->analyticsCollector->trackAction(
            'product_view',
            AnalyticsCategory::BUSINESS,
            [
                'product_id' => $productId,
                'product_name' => $productName,
                'category' => $category,
                'timestamp' => time(),
                'user_id' => $this->session->get('user_id')
            ]
        );
    }
    
    public function trackAddToCart(string $productId, int $quantity, float $price): void
    {
        $this->analyticsCollector->trackAction(
            'add_to_cart',
            AnalyticsCategory::BUSINESS,
            [
                'product_id' => $productId,
                'quantity' => $quantity,
                'price' => $price,
                'total' => $quantity * $price,
                'timestamp' => time(),
                'user_id' => $this->session->get('user_id')
            ]
        );
    }
}

Datenanalyse

Rohdaten abfragen

use App\Framework\Analytics\Storage\AnalyticsStorage;

class AnalyticsReportService
{
    public function __construct(
        private readonly AnalyticsStorage $analyticsStorage
    ) {}
    
    public function getPageViewsReport(\DateTimeInterface $from, \DateTimeInterface $to): array
    {
        // Rohdaten für Seitenaufrufe abrufen
        $pageViews = $this->analyticsStorage->getRawData(
            'page_view',
            $from,
            $to
        );
        
        // Daten nach Seite gruppieren
        $pageViewsByPath = [];
        foreach ($pageViews as $pageView) {
            $path = $pageView['path'] ?? 'unknown';
            if (!isset($pageViewsByPath[$path])) {
                $pageViewsByPath[$path] = 0;
            }
            $pageViewsByPath[$path]++;
        }
        
        // Nach Anzahl sortieren
        arsort($pageViewsByPath);
        
        return $pageViewsByPath;
    }
    
    public function getUserActivityReport(string $userId, \DateTimeInterface $from, \DateTimeInterface $to): array
    {
        // Alle Aktionen für einen bestimmten Benutzer abrufen
        $actions = $this->analyticsStorage->getRawData(
            'user_action',
            $from,
            $to,
            ['user_id' => $userId]
        );
        
        // Nach Zeitstempel sortieren
        usort($actions, function ($a, $b) {
            return $a['timestamp'] <=> $b['timestamp'];
        });
        
        return $actions;
    }
}

Aggregierte Daten abfragen

use App\Framework\Analytics\Storage\AnalyticsStorage;

class PerformanceReportService
{
    public function __construct(
        private readonly AnalyticsStorage $analyticsStorage
    ) {}
    
    public function getApiPerformanceReport(\DateTimeInterface $from, \DateTimeInterface $to): array
    {
        // Aggregierte Daten für API-Aufrufe abrufen
        $apiCallStats = $this->analyticsStorage->getAggregatedData(
            'analytics_api_calls_total',
            $from,
            $to
        );
        
        // Durchschnittliche Antwortzeit pro Endpunkt berechnen
        $responseTimeByEndpoint = [];
        foreach ($apiCallStats as $stat) {
            $endpoint = $stat['tags']['path'] ?? 'unknown';
            $method = $stat['tags']['method'] ?? 'unknown';
            $key = "{$method} {$endpoint}";
            
            if (!isset($responseTimeByEndpoint[$key])) {
                $responseTimeByEndpoint[$key] = [
                    'count' => 0,
                    'total_time' => 0,
                    'min_time' => PHP_FLOAT_MAX,
                    'max_time' => 0,
                ];
            }
            
            $duration = $stat['tags']['duration'] ?? 0;
            $responseTimeByEndpoint[$key]['count']++;
            $responseTimeByEndpoint[$key]['total_time'] += $duration;
            $responseTimeByEndpoint[$key]['min_time'] = min($responseTimeByEndpoint[$key]['min_time'], $duration);
            $responseTimeByEndpoint[$key]['max_time'] = max($responseTimeByEndpoint[$key]['max_time'], $duration);
        }
        
        // Durchschnitt berechnen
        foreach ($responseTimeByEndpoint as $key => $data) {
            $responseTimeByEndpoint[$key]['avg_time'] = $data['total_time'] / $data['count'];
        }
        
        // Nach durchschnittlicher Antwortzeit sortieren
        uasort($responseTimeByEndpoint, function ($a, $b) {
            return $b['avg_time'] <=> $a['avg_time'];
        });
        
        return $responseTimeByEndpoint;
    }
}

Dashboard-Integration

use App\Framework\Analytics\Dashboard\AnalyticsDashboard;

class AdminController
{
    public function __construct(
        private readonly AnalyticsDashboard $dashboard,
        private readonly TemplateEngine $templateEngine
    ) {}
    
    public function showDashboard(Request $request): Response
    {
        // Zeitraum aus Anfrage oder Standardwerte
        $from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
        $to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
        
        // Dashboard-Daten abrufen
        $stats = $this->dashboard->getStats($from, $to);
        
        // Spezifische Statistiken abrufen
        $pageViewStats = $this->dashboard->getPageViewStats($from, $to);
        $errorStats = $this->dashboard->getErrorStats($from, $to);
        $performanceStats = $this->dashboard->getPerformanceStats($from, $to);
        $businessStats = $this->dashboard->getBusinessStats($from, $to);
        
        // Dashboard rendern
        return $this->templateEngine->render('admin/dashboard', [
            'stats' => $stats,
            'pageViewStats' => $pageViewStats,
            'errorStats' => $errorStats,
            'performanceStats' => $performanceStats,
            'businessStats' => $businessStats,
            'from' => $from,
            'to' => $to
        ]);
    }
}

Datenexport

CSV-Export

use App\Framework\Analytics\Export\AnalyticsExporter;

class ExportController
{
    public function __construct(
        private readonly AnalyticsExporter $exporter
    ) {}
    
    public function exportPageViews(Request $request): Response
    {
        // Zeitraum aus Anfrage
        $from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
        $to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
        
        // Daten exportieren
        $csvData = $this->exporter->exportToCsv(
            'page_view',
            $from,
            $to
        );
        
        // CSV-Datei zurückgeben
        return new Response(
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="page_views.csv"'
            ],
            $csvData
        );
    }
}

JSON-Export

use App\Framework\Analytics\Export\AnalyticsExporter;

class ApiController
{
    public function __construct(
        private readonly AnalyticsExporter $exporter
    ) {}
    
    public function getAnalyticsData(Request $request): Response
    {
        // Parameter aus Anfrage
        $eventType = $request->getQueryParam('type', 'page_view');
        $from = new \DateTimeImmutable($request->getQueryParam('from', '-7 days'));
        $to = new \DateTimeImmutable($request->getQueryParam('to', 'now'));
        
        // Daten exportieren
        $data = $this->exporter->exportToArray(
            $eventType,
            $from,
            $to
        );
        
        // JSON-Daten zurückgeben
        return new Response(
            200,
            ['Content-Type' => 'application/json'],
            json_encode($data)
        );
    }
}

Integration mit anderen Systemen

Event-System-Integration

use App\Framework\Analytics\EventSubscribers\AnalyticsEventSubscriber;
use App\Framework\EventDispatcher\EventDispatcherInterface;

class AnalyticsBootstrap
{
    public function initialize(EventDispatcherInterface $eventDispatcher): void
    {
        // Analytics-Event-Subscriber registrieren
        $eventDispatcher->addSubscriber(new AnalyticsEventSubscriber(
            $this->container->get(AnalyticsCollector::class)
        ));
    }
}

Externe Analytics-Integration

use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;

class ExternalAnalyticsService
{
    public function __construct(
        private readonly AnalyticsCollector $analyticsCollector,
        private readonly ExternalAnalyticsClient $externalClient
    ) {}
    
    public function trackEvent(string $eventName, array $properties): void
    {
        // Intern erfassen
        $this->analyticsCollector->trackAction(
            $eventName,
            AnalyticsCategory::BUSINESS,
            $properties
        );
        
        // An externes System senden
        $this->externalClient->trackEvent($eventName, $properties);
    }
    
    public function syncData(\DateTimeInterface $from, \DateTimeInterface $to): void
    {
        // Daten aus internem Analytics abrufen
        $internalData = $this->analyticsStorage->getRawData('*', $from, $to);
        
        // Daten an externes System senden
        $this->externalClient->batchImport($internalData);
    }
}

Fehlerbehebung

Debugging der Datenerfassung

use App\Framework\Analytics\AnalyticsCollector;
use App\Framework\Analytics\AnalyticsCategory;

class DebugAnalyticsCollector extends AnalyticsCollector
{
    public function trackAction(string $action, AnalyticsCategory $category, array $data = []): void
    {
        // Debug-Ausgabe
        echo "Tracking action: {$action}, category: {$category->value}\n";
        echo "Data: " . json_encode($data, JSON_PRETTY_PRINT) . "\n";
        
        // Original-Methode aufrufen
        parent::trackAction($action, $category, $data);
    }
    
    public function trackPageView(string $path, array $data = []): void
    {
        // Debug-Ausgabe
        echo "Tracking page view: {$path}\n";
        echo "Data: " . json_encode($data, JSON_PRETTY_PRINT) . "\n";
        
        // Original-Methode aufrufen
        parent::trackPageView($path, $data);
    }
}

Überprüfung der Datenspeicherung

use App\Framework\Analytics\Storage\AnalyticsStorage;

class AnalyticsDebugService
{
    public function __construct(
        private readonly AnalyticsStorage $analyticsStorage,
        private readonly string $dataPath
    ) {}
    
    public function checkStorage(): array
    {
        $result = [
            'status' => 'ok',
            'messages' => [],
            'files' => []
        ];
        
        // Prüfen, ob der Datenpfad existiert
        if (!is_dir($this->dataPath)) {
            $result['status'] = 'error';
            $result['messages'][] = "Datenpfad existiert nicht: {$this->dataPath}";
            return $result;
        }
        
        // Prüfen, ob der Datenpfad beschreibbar ist
        if (!is_writable($this->dataPath)) {
            $result['status'] = 'error';
            $result['messages'][] = "Datenpfad ist nicht beschreibbar: {$this->dataPath}";
            return $result;
        }
        
        // Dateien im Datenpfad auflisten
        $files = glob($this->dataPath . '/*.json');
        foreach ($files as $file) {
            $size = filesize($file);
            $modified = date('Y-m-d H:i:s', filemtime($file));
            $result['files'][] = [
                'name' => basename($file),
                'size' => $size,
                'modified' => $modified
            ];
        }
        
        // Testdaten speichern
        try {
            $this->analyticsStorage->storeRawData('debug_test', [
                'timestamp' => time(),
                'message' => 'Debug test'
            ]);
            $result['messages'][] = "Testdaten erfolgreich gespeichert";
        } catch (\Exception $e) {
            $result['status'] = 'error';
            $result['messages'][] = "Fehler beim Speichern von Testdaten: " . $e->getMessage();
        }
        
        return $result;
    }
}

Weiterführende Informationen