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:
278
src/Framework/Discovery/Exceptions/DiscoveryException.php
Normal file
278
src/Framework/Discovery/Exceptions/DiscoveryException.php
Normal file
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Discovery\Exceptions;
|
||||
|
||||
use App\Framework\Exception\ErrorCode;
|
||||
use App\Framework\Exception\ExceptionContext;
|
||||
use App\Framework\Exception\FrameworkException;
|
||||
|
||||
/**
|
||||
* Base exception for Discovery system operations
|
||||
*
|
||||
* Provides specialized error handling for discovery-related
|
||||
* operations with appropriate error codes and recovery hints.
|
||||
*/
|
||||
final class DiscoveryException extends FrameworkException
|
||||
{
|
||||
/**
|
||||
* Discovery process failed due to memory constraints
|
||||
*/
|
||||
public static function memoryExhausted(string $operation, int $currentMemory, int $memoryLimit): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.memory_exhausted', 'DiscoveryService')
|
||||
->withData([
|
||||
'operation' => $operation,
|
||||
'current_memory_mb' => round($currentMemory / 1024 / 1024, 2),
|
||||
'memory_limit_mb' => round($memoryLimit / 1024 / 1024, 2),
|
||||
'memory_usage_percent' => round(($currentMemory / $memoryLimit) * 100, 1),
|
||||
])
|
||||
->withDebug([
|
||||
'current_memory_bytes' => $currentMemory,
|
||||
'memory_limit_bytes' => $memoryLimit,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery operation '{$operation}' failed due to memory exhaustion",
|
||||
$context,
|
||||
ErrorCode::MEMORY_LIMIT_EXCEEDED
|
||||
)->withRetryAfter(300); // Suggest retry after 5 minutes
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory scanning failed
|
||||
*/
|
||||
public static function scanFailed(string $directory, string $reason, ?\Throwable $previous = null): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.scan_failed', 'FileScanner')
|
||||
->withData([
|
||||
'directory' => $directory,
|
||||
'reason' => $reason,
|
||||
'is_readable' => is_readable($directory),
|
||||
'exists' => file_exists($directory),
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Failed to scan directory '{$directory}': {$reason}",
|
||||
$context,
|
||||
ErrorCode::FILESYSTEM_READ_ERROR,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache operation failed
|
||||
*/
|
||||
public static function cacheFailed(string $operation, string $key, ?\Throwable $previous = null): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.cache_failed', 'DiscoveryCacheManager')
|
||||
->withData([
|
||||
'cache_operation' => $operation,
|
||||
'cache_key' => $key,
|
||||
])
|
||||
->withDebug([
|
||||
'key_hash' => md5($key),
|
||||
'operation_timestamp' => time(),
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery cache operation '{$operation}' failed for key '{$key}'",
|
||||
$context,
|
||||
ErrorCode::CACHE_OPERATION_FAILED,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* File processing failed
|
||||
*/
|
||||
public static function fileProcessingFailed(string $file, string $reason, ?\Throwable $previous = null): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.file_processing_failed', 'FileProcessor')
|
||||
->withData([
|
||||
'file_path' => $file,
|
||||
'file_size' => file_exists($file) ? filesize($file) : null,
|
||||
'file_extension' => pathinfo($file, PATHINFO_EXTENSION),
|
||||
'reason' => $reason,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Failed to process file '{$file}': {$reason}",
|
||||
$context,
|
||||
ErrorCode::FILE_PROCESSING_FAILED,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute reflection failed
|
||||
*/
|
||||
public static function attributeReflectionFailed(string $className, string $attributeType, ?\Throwable $previous = null): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.attribute_reflection_failed', 'AttributeProcessor')
|
||||
->withData([
|
||||
'class_name' => $className,
|
||||
'attribute_type' => $attributeType,
|
||||
'class_exists' => class_exists($className),
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Failed to reflect attribute '{$attributeType}' on class '{$className}'",
|
||||
$context,
|
||||
ErrorCode::REFLECTION_FAILED,
|
||||
$previous
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory guard emergency stop
|
||||
*/
|
||||
public static function emergencyStop(string $reason, array $memoryStats): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.emergency_stop', 'MemoryGuard')
|
||||
->withData([
|
||||
'reason' => $reason,
|
||||
'memory_usage_mb' => round($memoryStats['current_usage'] / 1024 / 1024, 2),
|
||||
'memory_limit_mb' => round($memoryStats['memory_limit'] / 1024 / 1024, 2),
|
||||
'memory_pressure' => $memoryStats['memory_pressure'] ?? 'unknown',
|
||||
])
|
||||
->withDebug($memoryStats);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery process stopped by memory guard: {$reason}",
|
||||
$context,
|
||||
ErrorCode::EMERGENCY_STOP_TRIGGERED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration validation failed
|
||||
*/
|
||||
public static function configurationInvalid(string $field, string $reason): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.configuration_invalid', 'DiscoveryConfiguration')
|
||||
->withData([
|
||||
'invalid_field' => $field,
|
||||
'validation_error' => $reason,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery configuration invalid - {$field}: {$reason}",
|
||||
$context,
|
||||
ErrorCode::VAL_CONFIGURATION_INVALID
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovery timeout
|
||||
*/
|
||||
public static function timeout(int $timeoutSeconds, int $actualSeconds): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.timeout', 'DiscoveryService')
|
||||
->withData([
|
||||
'timeout_seconds' => $timeoutSeconds,
|
||||
'actual_seconds' => $actualSeconds,
|
||||
'exceeded_by_seconds' => $actualSeconds - $timeoutSeconds,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery operation timed out after {$actualSeconds}s (limit: {$timeoutSeconds}s)",
|
||||
$context,
|
||||
ErrorCode::OPERATION_TIMEOUT
|
||||
)->withRetryAfter(60); // Suggest retry after 1 minute
|
||||
}
|
||||
|
||||
/**
|
||||
* Concurrent discovery conflict
|
||||
*/
|
||||
public static function concurrentDiscovery(string $lockId): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.concurrent_conflict', 'DiscoveryService')
|
||||
->withData([
|
||||
'lock_id' => $lockId,
|
||||
'conflict_type' => 'concurrent_discovery',
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery already in progress (lock: {$lockId})",
|
||||
$context,
|
||||
ErrorCode::RESOURCE_CONFLICT
|
||||
)->withRetryAfter(30); // Suggest retry after 30 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Corrupted discovery data
|
||||
*/
|
||||
public static function corruptedData(string $source, string $reason): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.corrupted_data', 'DiscoveryService')
|
||||
->withData([
|
||||
'data_source' => $source,
|
||||
'corruption_reason' => $reason,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Discovery data corrupted in {$source}: {$reason}",
|
||||
$context,
|
||||
ErrorCode::DATA_CORRUPTION_DETECTED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insufficient permissions
|
||||
*/
|
||||
public static function insufficientPermissions(string $path, string $requiredPermission): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.insufficient_permissions', 'FileScanner')
|
||||
->withData([
|
||||
'path' => $path,
|
||||
'required_permission' => $requiredPermission,
|
||||
'current_permissions' => file_exists($path) ? substr(sprintf('%o', fileperms($path)), -4) : null,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Insufficient permissions to access '{$path}' (required: {$requiredPermission})",
|
||||
$context,
|
||||
ErrorCode::PERMISSION_DENIED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource limit exceeded
|
||||
*/
|
||||
public static function resourceLimitExceeded(string $resource, int $current, int $limit): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.resource_limit_exceeded', 'DiscoveryService')
|
||||
->withData([
|
||||
'resource_type' => $resource,
|
||||
'current_usage' => $current,
|
||||
'resource_limit' => $limit,
|
||||
'usage_percentage' => round(($current / $limit) * 100, 1),
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Resource limit exceeded for {$resource}: {$current}/{$limit}",
|
||||
$context,
|
||||
ErrorCode::RESOURCE_LIMIT_EXCEEDED
|
||||
)->withRetryAfter(60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependency missing
|
||||
*/
|
||||
public static function dependencyMissing(string $dependency, string $requiredFor): self
|
||||
{
|
||||
$context = ExceptionContext::forOperation('discovery.dependency_missing', 'DiscoveryService')
|
||||
->withData([
|
||||
'missing_dependency' => $dependency,
|
||||
'required_for' => $requiredFor,
|
||||
]);
|
||||
|
||||
return self::fromContext(
|
||||
"Missing dependency '{$dependency}' required for {$requiredFor}",
|
||||
$context,
|
||||
ErrorCode::DEPENDENCY_MISSING
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user