- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
218 lines
5.8 KiB
Markdown
218 lines
5.8 KiB
Markdown
# Error Handling & Debugging
|
|
|
|
This guide covers error handling patterns and debugging strategies in the framework.
|
|
|
|
## Exception Handling
|
|
|
|
All custom exceptions in the framework must extend `FrameworkException` to ensure consistent error handling, logging, and recovery mechanisms.
|
|
|
|
### The FrameworkException System
|
|
|
|
The framework provides a sophisticated exception system with:
|
|
- **ExceptionContext**: Rich context information for debugging
|
|
- **ErrorCode**: Categorized error codes with recovery hints
|
|
- **RetryAfter**: Support for recoverable operations
|
|
- **Fluent Interface**: Easy context building
|
|
|
|
### Creating Custom Exceptions
|
|
|
|
```php
|
|
namespace App\Domain\User\Exceptions;
|
|
|
|
use App\Framework\Exception\FrameworkException;
|
|
use App\Framework\Exception\ErrorCode;
|
|
use App\Framework\Exception\ExceptionContext;
|
|
|
|
final class UserNotFoundException extends FrameworkException
|
|
{
|
|
public static function byId(UserId $id): self
|
|
{
|
|
return self::create(
|
|
ErrorCode::ENTITY_NOT_FOUND,
|
|
"User with ID '{$id->toString()}' not found"
|
|
)->withData([
|
|
'user_id' => $id->toString(),
|
|
'search_type' => 'by_id'
|
|
]);
|
|
}
|
|
|
|
public static function byEmail(Email $email): self
|
|
{
|
|
$context = ExceptionContext::forOperation('user.lookup', 'UserRepository')
|
|
->withData(['email' => $email->getMasked()]);
|
|
|
|
return self::fromContext(
|
|
"User with email not found",
|
|
$context,
|
|
ErrorCode::ENTITY_NOT_FOUND
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Using ErrorCode Enum
|
|
|
|
```php
|
|
// The framework provides predefined error codes:
|
|
ErrorCode::DB_CONNECTION_FAILED // Database errors
|
|
ErrorCode::AUTH_TOKEN_EXPIRED // Authentication errors
|
|
ErrorCode::VAL_BUSINESS_RULE_VIOLATION // Validation errors
|
|
ErrorCode::HTTP_RATE_LIMIT_EXCEEDED // HTTP errors
|
|
ErrorCode::SEC_CSRF_TOKEN_INVALID // Security errors
|
|
|
|
// Using error codes in exceptions:
|
|
throw FrameworkException::create(
|
|
ErrorCode::DB_QUERY_FAILED,
|
|
"Failed to execute user query"
|
|
)->withContext(
|
|
ExceptionContext::forOperation('user.find', 'UserRepository')
|
|
->withData(['query' => 'SELECT * FROM users WHERE id = ?'])
|
|
->withDebug(['bind_params' => [$userId]])
|
|
);
|
|
```
|
|
|
|
### Exception Context Building
|
|
|
|
```php
|
|
// Method 1: Using factory methods
|
|
$exception = FrameworkException::forOperation(
|
|
'payment.process',
|
|
'PaymentService',
|
|
'Payment processing failed',
|
|
ErrorCode::PAYMENT_GATEWAY_ERROR
|
|
)->withData([
|
|
'amount' => $amount->toArray(),
|
|
'gateway' => 'stripe',
|
|
'customer_id' => $customerId
|
|
])->withMetadata([
|
|
'attempt' => 1,
|
|
'idempotency_key' => $idempotencyKey
|
|
]);
|
|
|
|
// Method 2: Building context separately
|
|
$context = ExceptionContext::empty()
|
|
->withOperation('order.validate', 'OrderService')
|
|
->withData([
|
|
'order_id' => $orderId,
|
|
'total' => $total->toDecimal()
|
|
])
|
|
->withDebug([
|
|
'validation_rules' => ['min_amount', 'max_items'],
|
|
'failed_rule' => 'min_amount'
|
|
]);
|
|
|
|
throw FrameworkException::fromContext(
|
|
'Order validation failed',
|
|
$context,
|
|
ErrorCode::VAL_BUSINESS_RULE_VIOLATION
|
|
);
|
|
```
|
|
|
|
### Recoverable Exceptions
|
|
|
|
```php
|
|
// Creating recoverable exceptions with retry hints
|
|
final class RateLimitException extends FrameworkException
|
|
{
|
|
public static function exceeded(int $retryAfter): self
|
|
{
|
|
return self::create(
|
|
ErrorCode::HTTP_RATE_LIMIT_EXCEEDED,
|
|
'API rate limit exceeded'
|
|
)->withRetryAfter($retryAfter)
|
|
->withData(['retry_after_seconds' => $retryAfter]);
|
|
}
|
|
}
|
|
|
|
// Using in code
|
|
try {
|
|
$response = $apiClient->request($endpoint);
|
|
} catch (RateLimitException $e) {
|
|
if ($e->isRecoverable()) {
|
|
$waitTime = $e->getRetryAfter();
|
|
// Schedule retry after $waitTime seconds
|
|
}
|
|
throw $e;
|
|
}
|
|
```
|
|
|
|
### Exception Categories
|
|
|
|
```php
|
|
// Check exception category for handling strategies
|
|
try {
|
|
$result = $operation->execute();
|
|
} catch (FrameworkException $e) {
|
|
if ($e->isCategory('AUTH')) {
|
|
// Handle authentication errors
|
|
return $this->redirectToLogin();
|
|
}
|
|
|
|
if ($e->isCategory('VAL')) {
|
|
// Handle validation errors
|
|
return $this->validationErrorResponse($e);
|
|
}
|
|
|
|
if ($e->isErrorCode(ErrorCode::DB_CONNECTION_FAILED)) {
|
|
// Handle specific database connection errors
|
|
$this->notifyOps($e);
|
|
}
|
|
|
|
throw $e;
|
|
}
|
|
```
|
|
|
|
### Simple Exceptions for Quick Use
|
|
|
|
```php
|
|
// When you don't need the full context system
|
|
throw FrameworkException::simple('Quick error message');
|
|
|
|
// With previous exception
|
|
} catch (\PDOException $e) {
|
|
throw FrameworkException::simple(
|
|
'Database operation failed',
|
|
$e,
|
|
500
|
|
);
|
|
}
|
|
```
|
|
|
|
### Exception Data Sanitization
|
|
|
|
The framework automatically sanitizes sensitive data in exceptions:
|
|
|
|
```php
|
|
// Sensitive keys are automatically redacted
|
|
$exception->withData([
|
|
'username' => 'john@example.com',
|
|
'password' => 'secret123', // Will be logged as '[REDACTED]'
|
|
'api_key' => 'sk_live_...' // Will be logged as '[REDACTED]'
|
|
]);
|
|
```
|
|
|
|
### Best Practices
|
|
|
|
1. **Always extend FrameworkException** for custom exceptions
|
|
2. **Use ErrorCode enum** for categorizable errors
|
|
3. **Provide rich context** with operation, component, and data
|
|
4. **Use factory methods** for consistent exception creation
|
|
5. **Sanitize sensitive data** (automatic for common keys)
|
|
6. **Make exceptions domain-specific** (UserNotFoundException vs generic NotFoundException)
|
|
7. **Include recovery hints** for recoverable errors
|
|
|
|
## Logging Best Practices
|
|
|
|
TODO: Document logging patterns and levels
|
|
|
|
## Debug Strategies
|
|
|
|
TODO: Document debugging approaches and tools
|
|
|
|
## Error Recovery Patterns
|
|
|
|
TODO: Document error recovery and graceful degradation
|
|
|
|
## Common Error Scenarios
|
|
|
|
TODO: List common errors and solutions |