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:
331
src/Framework/Analytics/AnalyticsCollector.php
Normal file
331
src/Framework/Analytics/AnalyticsCollector.php
Normal file
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Analytics;
|
||||
|
||||
use App\Framework\Analytics\Storage\AnalyticsStorage;
|
||||
use App\Framework\Http\ServerEnvironment;
|
||||
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
|
||||
use App\Framework\Performance\PerformanceCategory;
|
||||
use App\Framework\Random\RandomGenerator;
|
||||
|
||||
/**
|
||||
* Moderner Analytics-Collector basierend auf dem Performance-System
|
||||
*
|
||||
* Sammelt Business- und User-Analytics-Daten und nutzt das bewährte
|
||||
* Performance-Framework für effiziente Datensammlung.
|
||||
*/
|
||||
final class AnalyticsCollector
|
||||
{
|
||||
/** @var array<string, mixed> */
|
||||
private array $sessionData = [];
|
||||
|
||||
/** @var array<string, int> */
|
||||
private array $counters = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly PerformanceCollectorInterface $performanceCollector,
|
||||
private readonly AnalyticsStorage $storage,
|
||||
private readonly RandomGenerator $random,
|
||||
private readonly ServerEnvironment $serverEnvironment,
|
||||
private readonly bool $enabled = true,
|
||||
private readonly float $samplingRate = 1.0
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackt eine Benutzeraktion
|
||||
*/
|
||||
public function trackAction(
|
||||
string $action,
|
||||
AnalyticsCategory $category,
|
||||
array $properties = []
|
||||
): void {
|
||||
error_log("Analytics: trackAction called with action={$action}, category={$category->value}");
|
||||
|
||||
if (! $this->shouldTrack()) {
|
||||
error_log("Analytics: trackAction skipped (shouldTrack=false)");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$context = array_merge([
|
||||
'action' => $action,
|
||||
'category' => $category->value,
|
||||
'session_id' => $this->getSessionId(),
|
||||
'timestamp' => time(),
|
||||
'user_agent' => $this->serverEnvironment->getUserAgent()->value,
|
||||
'ip' => $this->serverEnvironment->getClientIp()->value,
|
||||
], $properties);
|
||||
|
||||
// Nutze Performance-System für Analytics
|
||||
$this->performanceCollector->recordMetric(
|
||||
"analytics_action_{$action}",
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
|
||||
$this->performanceCollector->increment(
|
||||
'analytics_actions_total',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
|
||||
// Speichere in Analytics-Storage
|
||||
error_log("Analytics: About to call storage->storeRawData and storeAggregatedData");
|
||||
$this->storage->storeRawData($context, $this->samplingRate);
|
||||
$this->storeAggregatedData('user_actions', $action, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackt eine Seitenansicht
|
||||
*/
|
||||
public function trackPageView(
|
||||
string $path,
|
||||
string $title = '',
|
||||
array $properties = []
|
||||
): void {
|
||||
if (! $this->shouldTrack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$context = array_merge([
|
||||
'path' => $path,
|
||||
'title' => $title,
|
||||
'referer' => $this->serverEnvironment->getReferer(),
|
||||
'session_id' => $this->getSessionId(),
|
||||
'timestamp' => time(),
|
||||
], $properties);
|
||||
|
||||
$this->performanceCollector->recordMetric(
|
||||
'analytics_page_view',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
|
||||
$this->performanceCollector->increment(
|
||||
'analytics_page_views_total',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
|
||||
// Speichere in Analytics-Storage
|
||||
$this->storage->storeRawData($context, $this->samplingRate);
|
||||
$this->storeAggregatedData('page_views', $path, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackt einen Fehler
|
||||
*/
|
||||
public function trackError(
|
||||
string $errorType,
|
||||
string $message,
|
||||
array $context = []
|
||||
): void {
|
||||
if (! $this->shouldTrack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$errorContext = array_merge([
|
||||
'error_type' => $errorType,
|
||||
'message' => $message,
|
||||
'session_id' => $this->getSessionId(),
|
||||
'timestamp' => time(),
|
||||
'url' => $this->serverEnvironment->getRequestUri()->value,
|
||||
], $context);
|
||||
|
||||
$this->performanceCollector->recordMetric(
|
||||
"analytics_error_{$errorType}",
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$errorContext
|
||||
);
|
||||
|
||||
$this->performanceCollector->increment(
|
||||
'analytics_errors_total',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$errorContext
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackt ein Business-Event (Conversion, Purchase, etc.)
|
||||
*/
|
||||
public function trackBusinessEvent(
|
||||
string $event,
|
||||
float $value = 0.0,
|
||||
string $currency = 'EUR',
|
||||
array $properties = []
|
||||
): void {
|
||||
if (! $this->shouldTrack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$context = array_merge([
|
||||
'event' => $event,
|
||||
'value' => $value,
|
||||
'currency' => $currency,
|
||||
'session_id' => $this->getSessionId(),
|
||||
'timestamp' => time(),
|
||||
], $properties);
|
||||
|
||||
$this->performanceCollector->recordMetric(
|
||||
"analytics_business_{$event}",
|
||||
PerformanceCategory::CUSTOM,
|
||||
$value,
|
||||
$context
|
||||
);
|
||||
|
||||
$this->performanceCollector->increment(
|
||||
'analytics_business_events_total',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackt API-Nutzung
|
||||
*/
|
||||
public function trackApiCall(
|
||||
string $endpoint,
|
||||
string $method,
|
||||
int $responseCode,
|
||||
float $responseTime,
|
||||
array $properties = []
|
||||
): void {
|
||||
if (! $this->shouldTrack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$context = array_merge([
|
||||
'endpoint' => $endpoint,
|
||||
'method' => $method,
|
||||
'response_code' => $responseCode,
|
||||
'response_time' => $responseTime,
|
||||
'session_id' => $this->getSessionId(),
|
||||
'timestamp' => time(),
|
||||
], $properties);
|
||||
|
||||
$this->performanceCollector->recordMetric(
|
||||
'analytics_api_call',
|
||||
PerformanceCategory::CUSTOM,
|
||||
$responseTime,
|
||||
$context
|
||||
);
|
||||
|
||||
$this->performanceCollector->increment(
|
||||
'analytics_api_calls_total',
|
||||
PerformanceCategory::CUSTOM,
|
||||
1,
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt Session-Daten
|
||||
*/
|
||||
public function setSessionData(string $key, mixed $value): void
|
||||
{
|
||||
$this->sessionData[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt Session-Daten
|
||||
*/
|
||||
public function getSessionData(string $key): mixed
|
||||
{
|
||||
return $this->sessionData[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erhöht einen Counter
|
||||
*/
|
||||
public function incrementCounter(string $name, int $amount = 1): void
|
||||
{
|
||||
if (! isset($this->counters[$name])) {
|
||||
$this->counters[$name] = 0;
|
||||
}
|
||||
$this->counters[$name] += $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt Counter-Wert
|
||||
*/
|
||||
public function getCounter(string $name): int
|
||||
{
|
||||
return $this->counters[$name] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt alle Counter
|
||||
*/
|
||||
public function getCounters(): array
|
||||
{
|
||||
return $this->counters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob Tracking durchgeführt werden soll (Sampling)
|
||||
*/
|
||||
private function shouldTrack(): bool
|
||||
{
|
||||
error_log("Analytics: shouldTrack check - enabled={$this->enabled}, samplingRate={$this->samplingRate}");
|
||||
|
||||
if (! $this->enabled) {
|
||||
error_log("Analytics: Tracking disabled");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->samplingRate >= 1.0) {
|
||||
error_log("Analytics: Tracking enabled (no sampling)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->random->float() <= $this->samplingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert oder holt Session-ID
|
||||
*/
|
||||
private function getSessionId(): string
|
||||
{
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
return session_id();
|
||||
}
|
||||
|
||||
// Fallback: Cookie-basierte Session-ID
|
||||
if (isset($_COOKIE['analytics_session'])) {
|
||||
return $_COOKIE['analytics_session'];
|
||||
}
|
||||
|
||||
// Generiere neue Session-ID
|
||||
$sessionId = bin2hex($this->random->bytes(16));
|
||||
setcookie('analytics_session', $sessionId, time() + 1800); // 30 Min
|
||||
|
||||
return $sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Speichert aggregierte Daten im Storage
|
||||
*/
|
||||
private function storeAggregatedData(string $category, string $action, array $context): void
|
||||
{
|
||||
$period = 'hour'; // Standard-Aggregations-Periode
|
||||
$aggregatedData = [
|
||||
"{$category}_total" => 1,
|
||||
"{$category}_{$action}" => 1,
|
||||
'unique_sessions' => [$context['session_id'] ?? 'unknown' => 1],
|
||||
];
|
||||
|
||||
$this->storage->storeAggregated($period, $aggregatedData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user