- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
209 lines
6.1 KiB
PHP
209 lines
6.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Monitoring;
|
|
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\Core\ValueObjects\Percentage;
|
|
use App\Framework\Core\ValueObjects\Timestamp;
|
|
|
|
/**
|
|
* Metrics value object for error boundary monitoring
|
|
*/
|
|
final readonly class ErrorBoundaryMetrics
|
|
{
|
|
public function __construct(
|
|
public string $boundaryName,
|
|
public int $totalExecutions,
|
|
public int $totalSuccesses,
|
|
public int $totalFallbacks,
|
|
public int $totalErrors,
|
|
public Duration $averageExecutionTime,
|
|
public Duration $peakExecutionTime,
|
|
public Timestamp $lastExecution,
|
|
public int $consecutiveFailures,
|
|
public array $errorTypes = [], // Array of error class names with counts
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Get success rate as percentage
|
|
*/
|
|
public function getSuccessRate(): Percentage
|
|
{
|
|
if ($this->totalExecutions === 0) {
|
|
return Percentage::fromFloat(0.0);
|
|
}
|
|
|
|
return Percentage::fromFloat($this->totalSuccesses / $this->totalExecutions);
|
|
}
|
|
|
|
/**
|
|
* Get fallback rate as percentage
|
|
*/
|
|
public function getFallbackRate(): Percentage
|
|
{
|
|
if ($this->totalExecutions === 0) {
|
|
return Percentage::fromFloat(0.0);
|
|
}
|
|
|
|
return Percentage::fromFloat($this->totalFallbacks / $this->totalExecutions);
|
|
}
|
|
|
|
/**
|
|
* Get error rate as percentage
|
|
*/
|
|
public function getErrorRate(): Percentage
|
|
{
|
|
if ($this->totalExecutions === 0) {
|
|
return Percentage::fromFloat(0.0);
|
|
}
|
|
|
|
return Percentage::fromFloat($this->totalErrors / $this->totalExecutions);
|
|
}
|
|
|
|
/**
|
|
* Check if boundary is healthy
|
|
*/
|
|
public function isHealthy(): bool
|
|
{
|
|
return $this->getFallbackRate()->toFloat() < 0.1 && // Less than 10% fallback rate
|
|
$this->getErrorRate()->toFloat() < 0.05; // Less than 5% error rate
|
|
}
|
|
|
|
/**
|
|
* Check if boundary is degraded
|
|
*/
|
|
public function isDegraded(): bool
|
|
{
|
|
return ($this->getFallbackRate()->toFloat() >= 0.1 && $this->getFallbackRate()->toFloat() < 0.25) ||
|
|
($this->getErrorRate()->toFloat() >= 0.05 && $this->getErrorRate()->toFloat() < 0.15);
|
|
}
|
|
|
|
/**
|
|
* Check if boundary is failed
|
|
*/
|
|
public function isFailed(): bool
|
|
{
|
|
return $this->getFallbackRate()->toFloat() >= 0.25 || // More than 25% fallback rate
|
|
$this->getErrorRate()->toFloat() >= 0.15; // More than 15% error rate
|
|
}
|
|
|
|
/**
|
|
* Get health status string
|
|
*/
|
|
public function getHealthStatus(): string
|
|
{
|
|
if ($this->isFailed()) {
|
|
return 'failed';
|
|
}
|
|
|
|
if ($this->isDegraded()) {
|
|
return 'degraded';
|
|
}
|
|
|
|
return 'healthy';
|
|
}
|
|
|
|
/**
|
|
* Get time since last execution
|
|
*/
|
|
public function getTimeSinceLastExecution(Timestamp $currentTime): Duration
|
|
{
|
|
return $this->lastExecution->diff($currentTime);
|
|
}
|
|
|
|
/**
|
|
* Get most common error type
|
|
*/
|
|
public function getMostCommonErrorType(): ?string
|
|
{
|
|
if (empty($this->errorTypes)) {
|
|
return null;
|
|
}
|
|
|
|
$maxCount = 0;
|
|
$mostCommon = null;
|
|
|
|
foreach ($this->errorTypes as $errorType => $count) {
|
|
if ($count > $maxCount) {
|
|
$maxCount = $count;
|
|
$mostCommon = $errorType;
|
|
}
|
|
}
|
|
|
|
return $mostCommon;
|
|
}
|
|
|
|
/**
|
|
* Get error type distribution
|
|
*/
|
|
public function getErrorTypeDistribution(): array
|
|
{
|
|
if (empty($this->errorTypes) || $this->totalErrors === 0) {
|
|
return [];
|
|
}
|
|
|
|
$distribution = [];
|
|
foreach ($this->errorTypes as $errorType => $count) {
|
|
$distribution[$errorType] = [
|
|
'count' => $count,
|
|
'percentage' => ($count / $this->totalErrors) * 100,
|
|
];
|
|
}
|
|
|
|
// Sort by count descending
|
|
uasort($distribution, fn ($a, $b) => $b['count'] <=> $a['count']);
|
|
|
|
return $distribution;
|
|
}
|
|
|
|
/**
|
|
* Convert to array for serialization
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'boundary_name' => $this->boundaryName,
|
|
'total_executions' => $this->totalExecutions,
|
|
'total_successes' => $this->totalSuccesses,
|
|
'total_fallbacks' => $this->totalFallbacks,
|
|
'total_errors' => $this->totalErrors,
|
|
'success_rate' => $this->getSuccessRate()->toFloat(),
|
|
'fallback_rate' => $this->getFallbackRate()->toFloat(),
|
|
'error_rate' => $this->getErrorRate()->toFloat(),
|
|
'average_execution_time_ms' => $this->averageExecutionTime->toMilliseconds(),
|
|
'peak_execution_time_ms' => $this->peakExecutionTime->toMilliseconds(),
|
|
'last_execution' => $this->lastExecution->toIsoString(),
|
|
'consecutive_failures' => $this->consecutiveFailures,
|
|
'error_types' => $this->errorTypes,
|
|
'most_common_error_type' => $this->getMostCommonErrorType(),
|
|
'error_type_distribution' => $this->getErrorTypeDistribution(),
|
|
'health_status' => $this->getHealthStatus(),
|
|
'is_healthy' => $this->isHealthy(),
|
|
'is_degraded' => $this->isDegraded(),
|
|
'is_failed' => $this->isFailed(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Create from array
|
|
*/
|
|
public static function fromArray(array $data): self
|
|
{
|
|
return new self(
|
|
boundaryName: $data['boundary_name'],
|
|
totalExecutions: $data['total_executions'],
|
|
totalSuccesses: $data['total_successes'],
|
|
totalFallbacks: $data['total_fallbacks'],
|
|
totalErrors: $data['total_errors'],
|
|
averageExecutionTime: Duration::fromMilliseconds($data['average_execution_time_ms']),
|
|
peakExecutionTime: Duration::fromMilliseconds($data['peak_execution_time_ms']),
|
|
lastExecution: Timestamp::fromFloat(strtotime($data['last_execution'])),
|
|
consecutiveFailures: $data['consecutive_failures'],
|
|
errorTypes: $data['error_types'] ?? [],
|
|
);
|
|
}
|
|
}
|