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:
208
src/Framework/Monitoring/ErrorBoundaryMetrics.php
Normal file
208
src/Framework/Monitoring/ErrorBoundaryMetrics.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?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'] ?? [],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user