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
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,760 @@
# 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
```php
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
```php
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
```php
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
```php
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
```php
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:
```php
use App\Framework\Analytics\Middleware\AnalyticsMiddleware;
// In der Bootstrap-Datei oder Router-Konfiguration
$app->addMiddleware(AnalyticsMiddleware::class);
```
Anpassung der Middleware für bestimmte Routen:
```php
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:
```php
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:
```php
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:
```php
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:
```php
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
```php
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
```php
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
```php
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
```php
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
```php
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
```php
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
```php
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
```php
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
```php
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
- [Analytics Framework Übersicht](index.md)
- [Analytics Konfiguration](configuration.md)
- [Performance-Monitoring](/components/performance/index.md)