Files
michaelschiemer/src/Framework/ErrorReporting/ErrorReportingInitializer.php
Michael Schiemer 70e45fb56e fix(Discovery): Add comprehensive debug logging for router initialization
- Add initializer count logging in DiscoveryServiceBootstrapper
- Add route structure analysis in RouterSetup
- Add request parameter logging in HttpRouter
- Update PHP production config for better OPcache handling
- Fix various config and error handling improvements
2025-10-27 22:23:18 +01:00

170 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\ErrorReporting;
use App\Framework\Config\Environment;
use App\Framework\Database\ConnectionInterface;
use App\Framework\DateTime\Clock;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\ErrorReporting\Analytics\ErrorAnalyticsEngine;
use App\Framework\ErrorReporting\Processors\RequestContextProcessor;
use App\Framework\ErrorReporting\Processors\UserContextProcessor;
use App\Framework\ErrorReporting\Storage\DatabaseErrorReportStorage;
use App\Framework\ErrorReporting\Storage\ErrorReportStorageInterface;
use App\Framework\Http\Session\Session;
use App\Framework\Logging\Logger;
use App\Framework\Queue\Queue;
/**
* Initializer for Error Reporting system
*/
final readonly class ErrorReportingInitializer
{
#[Initializer]
public function initialize(Container $container): void
{
$env = $container->get(Environment::class);
$enabled = $env->getBool('ERROR_REPORTING_ENABLED', true);
// Storage
$container->bind(ErrorReportStorageInterface::class, function (Container $container) use ($enabled) {
if (! $enabled) {
// Return storage even if disabled (might be used for queries)
return new DatabaseErrorReportStorage(
connection: $container->get(ConnectionInterface::class)
);
}
return new DatabaseErrorReportStorage(
connection: $container->get(ConnectionInterface::class)
);
});
// Analytics Engine
$container->bind(ErrorAnalyticsEngine::class, function (Container $container) {
return new ErrorAnalyticsEngine(
storage: $container->get(ErrorReportStorageInterface::class),
clock: $container->get(Clock::class)
);
});
// Error Reporter Interface - bind to concrete or Null implementation
$container->bind(ErrorReporterInterface::class, function (Container $container) use ($enabled) {
if (! $enabled) {
return new NullErrorReporter();
}
$env = $container->get(Environment::class);
$processors = [];
$filters = [];
// Add built-in processors
if ($container->has(RequestContextProcessor::class)) {
$processors[] = $container->get(RequestContextProcessor::class);
}
if ($container->has(UserContextProcessor::class)) {
$processors[] = $container->get(UserContextProcessor::class);
}
// Add environment-based filters
$filterLevels = $env->getString('ERROR_REPORTING_FILTER_LEVELS', '');
if ($filterLevels !== '') {
$allowedLevels = explode(',', $filterLevels);
$filters[] = function (ErrorReport $report) use ($allowedLevels) {
return in_array($report->level, $allowedLevels);
};
}
// Add environment filter for production
$appEnv = $env->getString('APP_ENV', 'production');
if ($appEnv === 'production') {
$filters[] = function (ErrorReport $report) {
// Don't report debug/info in production
return ! in_array($report->level, ['debug', 'info']);
};
}
return new ErrorReporter(
storage: $container->get(ErrorReportStorageInterface::class),
clock: $container->get(Clock::class),
logger: $container->has(Logger::class) ? $container->get(Logger::class) : null,
queue: $container->has(Queue::class) ? $container->get(Queue::class) : null,
asyncProcessing: $env->getBool('ERROR_REPORTING_ASYNC', true),
processors: $processors,
filters: $filters
);
});
// Error Reporter (concrete class) - delegate to interface
$container->bind(ErrorReporter::class, function (Container $container) use ($enabled) {
if (! $enabled) {
throw new \RuntimeException('ErrorReporter is disabled. Use ErrorReporterInterface instead.');
}
$env = $container->get(Environment::class);
$processors = [];
$filters = [];
// Add built-in processors
if ($container->has(RequestContextProcessor::class)) {
$processors[] = $container->get(RequestContextProcessor::class);
}
if ($container->has(UserContextProcessor::class)) {
$processors[] = $container->get(UserContextProcessor::class);
}
// Add environment-based filters
$filterLevels = $env->getString('ERROR_REPORTING_FILTER_LEVELS', '');
if ($filterLevels !== '') {
$allowedLevels = explode(',', $filterLevels);
$filters[] = function (ErrorReport $report) use ($allowedLevels) {
return in_array($report->level, $allowedLevels);
};
}
// Add environment filter for production
$appEnv = $env->getString('APP_ENV', 'production');
if ($appEnv === 'production') {
$filters[] = function (ErrorReport $report) {
// Don't report debug/info in production
return ! in_array($report->level, ['debug', 'info']);
};
}
return new ErrorReporter(
storage: $container->get(ErrorReportStorageInterface::class),
clock: $container->get(Clock::class),
logger: $container->has(Logger::class) ? $container->get(Logger::class) : null,
queue: $container->has(Queue::class) ? $container->get(Queue::class) : null,
asyncProcessing: $env->getBool('ERROR_REPORTING_ASYNC', true),
processors: $processors,
filters: $filters
);
});
// Middleware
$container->bind(ErrorReportingMiddleware::class, function (Container $container) use ($enabled) {
return new ErrorReportingMiddleware(
reporter: $container->get(ErrorReporter::class),
enabled: $enabled
);
});
// Processors
$container->bind(RequestContextProcessor::class, function (Container $container) {
return new RequestContextProcessor();
});
$container->bind(UserContextProcessor::class, function (Container $container) {
// Session is not a singleton service - it's created per-request by SessionManager
// Don't try to resolve it here as it may not exist or trigger circular dependencies
return new UserContextProcessor(null);
});
}
}