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:
447
src/Framework/Discovery/Health/DiscoveryHealthCheck.php
Normal file
447
src/Framework/Discovery/Health/DiscoveryHealthCheck.php
Normal file
@@ -0,0 +1,447 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Discovery\Health;
|
||||
|
||||
use App\Framework\Discovery\Memory\DiscoveryMemoryManager;
|
||||
use App\Framework\Discovery\Memory\MemoryStatus;
|
||||
use App\Framework\Discovery\Storage\DiscoveryCacheManager;
|
||||
use App\Framework\Discovery\UnifiedDiscoveryService;
|
||||
use App\Framework\Health\HealthCheckCategory;
|
||||
use App\Framework\Health\HealthCheckInterface;
|
||||
use App\Framework\Health\HealthCheckResult;
|
||||
use App\Framework\Health\HealthStatus;
|
||||
|
||||
/**
|
||||
* Health check for the Discovery system
|
||||
*
|
||||
* Monitors discovery cache, memory management, and system performance
|
||||
* to ensure the discovery system is operating optimally.
|
||||
*/
|
||||
final readonly class DiscoveryHealthCheck implements HealthCheckInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ?UnifiedDiscoveryService $discoveryService = null,
|
||||
private ?DiscoveryCacheManager $cacheManager = null,
|
||||
private ?DiscoveryMemoryManager $memoryManager = null
|
||||
) {
|
||||
}
|
||||
|
||||
public function check(): HealthCheckResult
|
||||
{
|
||||
$checks = [];
|
||||
$overallHealth = HealthStatus::HEALTHY;
|
||||
$details = [];
|
||||
|
||||
// Check Discovery Service availability
|
||||
if ($this->discoveryService !== null) {
|
||||
$serviceCheck = $this->checkDiscoveryService();
|
||||
$checks['discovery_service'] = $serviceCheck;
|
||||
if ($serviceCheck['status'] !== 'healthy') {
|
||||
$overallHealth = $this->getWorseStatus($overallHealth, $serviceCheck['health_status']);
|
||||
}
|
||||
$details = array_merge($details, $serviceCheck['details']);
|
||||
}
|
||||
|
||||
// Check Cache System
|
||||
if ($this->cacheManager !== null) {
|
||||
$cacheCheck = $this->checkCacheSystem();
|
||||
$checks['cache_system'] = $cacheCheck;
|
||||
if ($cacheCheck['status'] !== 'healthy') {
|
||||
$overallHealth = $this->getWorseStatus($overallHealth, $cacheCheck['health_status']);
|
||||
}
|
||||
$details = array_merge($details, $cacheCheck['details']);
|
||||
}
|
||||
|
||||
// Check Memory Management
|
||||
if ($this->memoryManager !== null) {
|
||||
$memoryCheck = $this->checkMemoryManagement();
|
||||
$checks['memory_management'] = $memoryCheck;
|
||||
if ($memoryCheck['status'] !== 'healthy') {
|
||||
$overallHealth = $this->getWorseStatus($overallHealth, $memoryCheck['health_status']);
|
||||
}
|
||||
$details = array_merge($details, $memoryCheck['details']);
|
||||
}
|
||||
|
||||
// Overall system check
|
||||
$systemCheck = $this->checkOverallSystem($checks);
|
||||
$details = array_merge($details, $systemCheck['details']);
|
||||
|
||||
if ($systemCheck['status'] !== 'healthy') {
|
||||
$overallHealth = $this->getWorseStatus($overallHealth, $systemCheck['health_status']);
|
||||
}
|
||||
|
||||
$message = $this->generateHealthMessage($overallHealth, $checks);
|
||||
|
||||
return match ($overallHealth) {
|
||||
HealthStatus::HEALTHY => HealthCheckResult::healthy($message, $details),
|
||||
HealthStatus::WARNING => HealthCheckResult::warning($message, $details),
|
||||
HealthStatus::UNHEALTHY => HealthCheckResult::unhealthy($message, $details)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Discovery Service health
|
||||
*/
|
||||
private function checkDiscoveryService(): array
|
||||
{
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
// Test basic discovery functionality
|
||||
$testResult = $this->discoveryService->test();
|
||||
|
||||
$responseTime = (microtime(true) - $startTime) * 1000; // Convert to ms
|
||||
|
||||
$status = 'healthy';
|
||||
$healthStatus = HealthStatus::HEALTHY;
|
||||
$details = [
|
||||
'service_available' => true,
|
||||
'response_time_ms' => round($responseTime, 2),
|
||||
];
|
||||
|
||||
// Check response time
|
||||
if ($responseTime > 5000) { // 5 seconds
|
||||
$status = 'unhealthy';
|
||||
$healthStatus = HealthStatus::UNHEALTHY;
|
||||
$details['performance_issue'] = 'Response time too high';
|
||||
} elseif ($responseTime > 2000) { // 2 seconds
|
||||
$status = 'warning';
|
||||
$healthStatus = HealthStatus::WARNING;
|
||||
$details['performance_warning'] = 'Response time elevated';
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'health_status' => $healthStatus,
|
||||
'details' => $details,
|
||||
];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'status' => 'unhealthy',
|
||||
'health_status' => HealthStatus::UNHEALTHY,
|
||||
'details' => [
|
||||
'service_available' => false,
|
||||
'error' => $e->getMessage(),
|
||||
'error_type' => get_class($e),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Cache System health
|
||||
*/
|
||||
private function checkCacheSystem(): array
|
||||
{
|
||||
try {
|
||||
$healthStatus = $this->cacheManager->getHealthStatus();
|
||||
|
||||
$status = 'healthy';
|
||||
$health = HealthStatus::HEALTHY;
|
||||
$details = [
|
||||
'cache_driver' => $healthStatus['cache_driver'],
|
||||
'memory_aware' => $healthStatus['memory_aware'],
|
||||
];
|
||||
|
||||
// Check memory management if available
|
||||
if (isset($healthStatus['memory_management'])) {
|
||||
$memoryInfo = $healthStatus['memory_management'];
|
||||
$details['memory_status'] = $memoryInfo['status'];
|
||||
$details['memory_pressure'] = $memoryInfo['memory_pressure'];
|
||||
$details['cache_level'] = $memoryInfo['cache_level'];
|
||||
|
||||
// Evaluate memory status
|
||||
if ($memoryInfo['status'] === 'critical') {
|
||||
$status = 'unhealthy';
|
||||
$health = HealthStatus::UNHEALTHY;
|
||||
} elseif ($memoryInfo['status'] === 'warning') {
|
||||
$status = 'warning';
|
||||
$health = HealthStatus::WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
// Check cache metrics if available
|
||||
$cacheMetrics = $this->cacheManager->getCacheMetrics();
|
||||
if ($cacheMetrics !== null) {
|
||||
$details['hit_rate'] = $cacheMetrics->hitRate->toPercentage()->toString();
|
||||
$details['total_size'] = $cacheMetrics->totalSize->toHumanReadable();
|
||||
$details['compression_ratio'] = $cacheMetrics->compressionRatio->toPercentage()->toString();
|
||||
|
||||
// Check performance metrics
|
||||
$hitRate = $cacheMetrics->hitRate->toString();
|
||||
if ($hitRate < 0.3) { // Less than 30% hit rate
|
||||
$status = $this->getWorseStatusString($status, 'warning');
|
||||
$health = $this->getWorseStatus($health, HealthStatus::WARNING);
|
||||
$details['cache_performance_warning'] = 'Low cache hit rate';
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'health_status' => $health,
|
||||
'details' => $details,
|
||||
];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'status' => 'unhealthy',
|
||||
'health_status' => HealthStatus::UNHEALTHY,
|
||||
'details' => [
|
||||
'cache_available' => false,
|
||||
'error' => $e->getMessage(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Memory Management health
|
||||
*/
|
||||
private function checkMemoryManagement(): array
|
||||
{
|
||||
try {
|
||||
$memoryStatus = $this->memoryManager->getMemoryStatus('health_check');
|
||||
|
||||
$status = 'healthy';
|
||||
$health = HealthStatus::HEALTHY;
|
||||
$details = [
|
||||
'current_usage' => $memoryStatus->currentUsage->toHumanReadable(),
|
||||
'memory_pressure' => $memoryStatus->memoryPressure->toString(),
|
||||
'status' => $memoryStatus->status->value,
|
||||
];
|
||||
|
||||
// Evaluate memory status
|
||||
switch ($memoryStatus->status) {
|
||||
case MemoryStatus::CRITICAL:
|
||||
$status = 'unhealthy';
|
||||
$health = HealthStatus::UNHEALTHY;
|
||||
$details['critical_issue'] = 'Memory usage is critical';
|
||||
|
||||
break;
|
||||
|
||||
case MemoryStatus::WARNING:
|
||||
$status = 'warning';
|
||||
$health = HealthStatus::WARNING;
|
||||
$details['warning'] = 'Memory usage is elevated';
|
||||
|
||||
break;
|
||||
|
||||
case MemoryStatus::NORMAL:
|
||||
// Check if we're close to warning threshold
|
||||
if ($memoryStatus->memoryPressure->toDecimal() > 0.7) {
|
||||
$status = 'warning';
|
||||
$health = HealthStatus::WARNING;
|
||||
$details['approaching_limit'] = 'Memory usage approaching threshold';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Add memory statistics
|
||||
if (method_exists($this->memoryManager, 'getStatistics')) {
|
||||
$stats = $this->memoryManager->getStatistics();
|
||||
$details['cleanup_count'] = $stats['cleanup_operations_count'] ?? 0;
|
||||
$details['memory_freed'] = isset($stats['total_memory_freed'])
|
||||
? $stats['total_memory_freed']->toHumanReadable()
|
||||
: '0 B';
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'health_status' => $health,
|
||||
'details' => $details,
|
||||
];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'status' => 'unhealthy',
|
||||
'health_status' => HealthStatus::UNHEALTHY,
|
||||
'details' => [
|
||||
'memory_manager_available' => false,
|
||||
'error' => $e->getMessage(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check overall system health
|
||||
*/
|
||||
private function checkOverallSystem(array $checks): array
|
||||
{
|
||||
$details = [];
|
||||
$status = 'healthy';
|
||||
$health = HealthStatus::HEALTHY;
|
||||
|
||||
// Count health status distribution
|
||||
$healthyCounts = 0;
|
||||
$warningCounts = 0;
|
||||
$unhealthyCounts = 0;
|
||||
|
||||
foreach ($checks as $check) {
|
||||
switch ($check['status']) {
|
||||
case 'healthy':
|
||||
$healthyCounts++;
|
||||
|
||||
break;
|
||||
case 'warning':
|
||||
$warningCounts++;
|
||||
|
||||
break;
|
||||
case 'unhealthy':
|
||||
$unhealthyCounts++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$totalChecks = count($checks);
|
||||
|
||||
if ($totalChecks === 0) {
|
||||
$status = 'warning';
|
||||
$health = HealthStatus::WARNING;
|
||||
$details['no_components'] = 'No discovery components available for health check';
|
||||
} else {
|
||||
// Determine overall status based on component health
|
||||
if ($unhealthyCounts > 0) {
|
||||
$status = 'unhealthy';
|
||||
$health = HealthStatus::UNHEALTHY;
|
||||
$details['unhealthy_components'] = $unhealthyCounts;
|
||||
} elseif ($warningCounts > 0) {
|
||||
$status = 'warning';
|
||||
$health = HealthStatus::WARNING;
|
||||
$details['warning_components'] = $warningCounts;
|
||||
}
|
||||
|
||||
$details['health_summary'] = [
|
||||
'total_components' => $totalChecks,
|
||||
'healthy' => $healthyCounts,
|
||||
'warning' => $warningCounts,
|
||||
'unhealthy' => $unhealthyCounts,
|
||||
];
|
||||
}
|
||||
|
||||
// Add system recommendations
|
||||
$recommendations = $this->generateRecommendations($checks);
|
||||
if (! empty($recommendations)) {
|
||||
$details['recommendations'] = $recommendations;
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'health_status' => $health,
|
||||
'details' => $details,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate health message
|
||||
*/
|
||||
private function generateHealthMessage(HealthStatus $overallHealth, array $checks): string
|
||||
{
|
||||
$componentCount = count($checks);
|
||||
$healthyCount = 0;
|
||||
|
||||
foreach ($checks as $check) {
|
||||
if ($check['status'] === 'healthy') {
|
||||
$healthyCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return match ($overallHealth) {
|
||||
HealthStatus::HEALTHY => "Discovery system is healthy ({$healthyCount}/{$componentCount} components optimal)",
|
||||
HealthStatus::WARNING => "Discovery system has warnings ({$healthyCount}/{$componentCount} components optimal)",
|
||||
HealthStatus::UNHEALTHY => "Discovery system is unhealthy ({$healthyCount}/{$componentCount} components optimal)"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate recommendations based on check results
|
||||
*/
|
||||
private function generateRecommendations(array $checks): array
|
||||
{
|
||||
$recommendations = [];
|
||||
|
||||
foreach ($checks as $checkName => $check) {
|
||||
if ($check['status'] === 'unhealthy' || $check['status'] === 'warning') {
|
||||
switch ($checkName) {
|
||||
case 'discovery_service':
|
||||
if (isset($check['details']['performance_issue'])) {
|
||||
$recommendations[] = 'Consider optimizing discovery algorithms or enabling parallel processing';
|
||||
}
|
||||
if (isset($check['details']['service_available']) && ! $check['details']['service_available']) {
|
||||
$recommendations[] = 'Discovery service is unavailable - check configuration and dependencies';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'cache_system':
|
||||
if (isset($check['details']['cache_performance_warning'])) {
|
||||
$recommendations[] = 'Improve cache hit rate by reviewing cache strategy and warming critical data';
|
||||
}
|
||||
if (isset($check['details']['memory_status']) && $check['details']['memory_status'] === 'critical') {
|
||||
$recommendations[] = 'Enable memory pressure management and increase cleanup frequency';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'memory_management':
|
||||
if (isset($check['details']['critical_issue'])) {
|
||||
$recommendations[] = 'Immediate action required: reduce memory usage or increase system limits';
|
||||
}
|
||||
if (isset($check['details']['approaching_limit'])) {
|
||||
$recommendations[] = 'Monitor memory usage closely and consider optimization strategies';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($recommendations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get worse health status
|
||||
*/
|
||||
private function getWorseStatus(HealthStatus $current, HealthStatus $new): HealthStatus
|
||||
{
|
||||
if ($new->getPriority() < $current->getPriority()) {
|
||||
return $new;
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get worse status string
|
||||
*/
|
||||
private function getWorseStatusString(string $current, string $new): string
|
||||
{
|
||||
$priority = [
|
||||
'healthy' => 3,
|
||||
'warning' => 2,
|
||||
'unhealthy' => 1,
|
||||
];
|
||||
|
||||
return $priority[$new] < $priority[$current] ? $new : $current;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Discovery System Health';
|
||||
}
|
||||
|
||||
public function getCategory(): HealthCheckCategory
|
||||
{
|
||||
return HealthCheckCategory::DISCOVERY;
|
||||
}
|
||||
|
||||
public function getTimeout(): int
|
||||
{
|
||||
return 10000; // 10 seconds timeout
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user