- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
22 KiB
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;
}
}