- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
330 lines
10 KiB
PHP
330 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\LiveComponents\Controllers;
|
|
|
|
use App\Framework\Attributes\Route;
|
|
use App\Framework\Auth\Auth;
|
|
use App\Framework\Http\Enums\Method;
|
|
use App\Framework\Http\Result\JsonResult;
|
|
use App\Framework\LiveComponents\Cache\CacheMetricsCollector;
|
|
use App\Framework\LiveComponents\Cache\ComponentStateCache;
|
|
use App\Framework\LiveComponents\ComponentRegistry;
|
|
use App\Framework\LiveComponents\Performance\ComponentMetadataCache;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
|
use App\Framework\View\ProcessorPerformanceTracker;
|
|
|
|
/**
|
|
* LiveComponent Monitoring Controller
|
|
*
|
|
* Production monitoring endpoints for LiveComponents system.
|
|
*
|
|
* Features:
|
|
* - Cache metrics and performance assessment
|
|
* - Component registry statistics
|
|
* - Template processor performance (if enabled)
|
|
* - System health status
|
|
* - Performance warnings and alerts
|
|
* - Component inspection for debugging
|
|
*
|
|
* Security: All endpoints require admin authentication
|
|
*/
|
|
|
|
final readonly class LiveComponentMonitoringController
|
|
{
|
|
public function __construct(
|
|
private CacheMetricsCollector $metricsCollector,
|
|
private ComponentRegistry $registry,
|
|
private ComponentMetadataCache $metadataCache,
|
|
private ComponentStateCache $stateCache,
|
|
private ?ProcessorPerformanceTracker $performanceTracker = null
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Get comprehensive metrics
|
|
*
|
|
* Returns detailed metrics for all caching layers, component registry,
|
|
* and optional template processor performance.
|
|
*
|
|
* @route GET /api/livecomponents/metrics
|
|
*/
|
|
#[Route('/api/livecomponents/metrics', method: Method::GET)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function metrics(): JsonResult
|
|
{
|
|
$metrics = [
|
|
'cache' => $this->getCacheMetrics(),
|
|
'registry' => $this->getRegistryStats(),
|
|
'timestamp' => time(),
|
|
'system' => [
|
|
'memory_usage' => memory_get_usage(true),
|
|
'peak_memory' => memory_get_peak_usage(true),
|
|
],
|
|
];
|
|
|
|
// Include processor performance if tracking is enabled
|
|
if ($this->performanceTracker !== null && $this->performanceTracker->isEnabled()) {
|
|
$metrics['processors'] = $this->performanceTracker->generateReport()->toArray();
|
|
}
|
|
|
|
return new JsonResult($metrics);
|
|
}
|
|
|
|
/**
|
|
* Get health status
|
|
*
|
|
* Quick health check for monitoring systems.
|
|
* Returns 200 if healthy, 503 if unhealthy.
|
|
*
|
|
* @route GET /api/livecomponents/health
|
|
*/
|
|
#[Route('/api/livecomponents/health', method: Method::GET)]
|
|
public function health(): JsonResult
|
|
{
|
|
$hasIssues = $this->metricsCollector->hasPerformanceIssues();
|
|
$warnings = $this->metricsCollector->getPerformanceWarnings();
|
|
|
|
$status = [
|
|
'status' => $hasIssues ? 'degraded' : 'healthy',
|
|
'components' => [
|
|
'registry' => $this->isRegistryHealthy(),
|
|
'cache' => ! $hasIssues,
|
|
],
|
|
'warnings' => $warnings,
|
|
'timestamp' => time(),
|
|
];
|
|
|
|
// Return 503 if unhealthy for monitoring systems
|
|
$httpStatus = $hasIssues ? 503 : 200;
|
|
|
|
return new JsonResult($status, $httpStatus);
|
|
}
|
|
|
|
/**
|
|
* Get cache performance summary
|
|
*
|
|
* Focused metrics for cache system performance.
|
|
*
|
|
* @route GET /api/livecomponents/metrics/cache
|
|
*/
|
|
#[Route('/api/livecomponents/metrics/cache', method: Method::GET)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function cacheMetrics(): JsonResult
|
|
{
|
|
return new JsonResult($this->getCacheMetrics());
|
|
}
|
|
|
|
/**
|
|
* Get registry statistics
|
|
*
|
|
* Component registry stats and metadata.
|
|
*
|
|
* @route GET /api/livecomponents/metrics/registry
|
|
*/
|
|
#[Route('/api/livecomponents/metrics/registry', method: Method::GET)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function registryMetrics(): JsonResult
|
|
{
|
|
return new JsonResult($this->getRegistryStats());
|
|
}
|
|
|
|
/**
|
|
* Reset metrics (development only)
|
|
*
|
|
* Resets all collected metrics. Only available in development.
|
|
*
|
|
* @route POST /api/livecomponents/metrics/reset
|
|
*/
|
|
#[Route('/api/livecomponents/metrics/reset', method: Method::POST)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function resetMetrics(): JsonResult
|
|
{
|
|
// Only allow in development
|
|
if (getenv('APP_ENV') !== 'development') {
|
|
return new JsonResult(
|
|
['error' => 'Metric reset only available in development'],
|
|
403
|
|
);
|
|
}
|
|
|
|
$this->metricsCollector->reset();
|
|
|
|
if ($this->performanceTracker !== null) {
|
|
$this->performanceTracker->reset();
|
|
}
|
|
|
|
return new JsonResult([
|
|
'message' => 'Metrics reset successfully',
|
|
'timestamp' => time(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get cache metrics data
|
|
*/
|
|
private function getCacheMetrics(): array
|
|
{
|
|
return $this->metricsCollector->getSummary();
|
|
}
|
|
|
|
/**
|
|
* Get registry statistics
|
|
*/
|
|
private function getRegistryStats(): array
|
|
{
|
|
$componentNames = $this->registry->getAvailableComponentNames();
|
|
|
|
return [
|
|
'total_components' => count($componentNames),
|
|
'component_names' => $componentNames,
|
|
'memory_estimate' => $this->estimateRegistryMemoryUsage(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Check if registry is healthy
|
|
*/
|
|
private function isRegistryHealthy(): bool
|
|
{
|
|
try {
|
|
$components = $this->registry->getAvailableComponentNames();
|
|
|
|
return ! empty($components);
|
|
} catch (\Throwable $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Estimate registry memory usage
|
|
*/
|
|
private function estimateRegistryMemoryUsage(): int
|
|
{
|
|
// Rough estimate: ~5KB per component
|
|
$componentCount = count($this->registry->getAvailableComponentNames());
|
|
|
|
return $componentCount * 5 * 1024; // bytes
|
|
}
|
|
|
|
/**
|
|
* Inspect specific component
|
|
*
|
|
* Returns detailed information about a specific component instance
|
|
* for debugging and development purposes.
|
|
*
|
|
* @route GET /api/livecomponents/inspect/{componentId}
|
|
*/
|
|
#[Route('/api/livecomponents/inspect/{componentId}', method: Method::GET)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function inspectComponent(string $componentId): JsonResult
|
|
{
|
|
try {
|
|
// Parse component ID
|
|
$id = ComponentId::fromString($componentId);
|
|
[$componentName, $instanceId] = explode(':', $componentId, 2);
|
|
|
|
// Get component class name
|
|
$className = $this->registry->getClassName($componentName);
|
|
|
|
if ($className === null) {
|
|
return new JsonResult([
|
|
'error' => 'Component not found',
|
|
'component_id' => $componentId,
|
|
], 404);
|
|
}
|
|
|
|
// Get metadata
|
|
$metadata = $this->metadataCache->get($className);
|
|
|
|
// Try to get cached state
|
|
$cachedState = $this->stateCache->get($id);
|
|
|
|
// Build inspection data
|
|
$inspection = [
|
|
'component' => [
|
|
'id' => $componentId,
|
|
'name' => $componentName,
|
|
'instance_id' => $instanceId,
|
|
'class' => $className,
|
|
],
|
|
'metadata' => [
|
|
'properties' => array_map(
|
|
fn ($prop) => [
|
|
'name' => $prop->name,
|
|
'type' => $prop->type,
|
|
'nullable' => $prop->nullable,
|
|
'hasDefault' => $prop->hasDefaultValue,
|
|
],
|
|
$metadata->properties
|
|
),
|
|
'actions' => array_map(
|
|
fn ($action) => [
|
|
'name' => $action->name,
|
|
'parameters' => $action->parameters,
|
|
],
|
|
$metadata->actions
|
|
),
|
|
'constructor_params' => $metadata->constructorParams,
|
|
'compiled_at' => date('Y-m-d H:i:s', $metadata->compiledAt),
|
|
],
|
|
'state' => $cachedState !== null ? [
|
|
'cached' => true,
|
|
'data' => $cachedState->toArray(),
|
|
] : [
|
|
'cached' => false,
|
|
'message' => 'No cached state found',
|
|
],
|
|
'cache_info' => [
|
|
'metadata_cached' => $this->metadataCache->has($className),
|
|
'state_cached' => $cachedState !== null,
|
|
],
|
|
'timestamp' => time(),
|
|
];
|
|
|
|
return new JsonResult($inspection);
|
|
} catch (\Throwable $e) {
|
|
return new JsonResult([
|
|
'error' => 'Inspection failed',
|
|
'message' => $e->getMessage(),
|
|
'component_id' => $componentId,
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* List all component instances
|
|
*
|
|
* Returns a list of all active component instances with their IDs.
|
|
* Useful for discovering what components to inspect.
|
|
*
|
|
* @route GET /api/livecomponents/instances
|
|
*/
|
|
#[Route('/api/livecomponents/instances', method: Method::GET)]
|
|
#[Auth(roles: ['admin'])]
|
|
public function listInstances(): JsonResult
|
|
{
|
|
$componentNames = $this->registry->getAvailableComponentNames();
|
|
|
|
$instances = [];
|
|
foreach ($componentNames as $name) {
|
|
$className = $this->registry->getClassName($name);
|
|
|
|
if ($className !== null) {
|
|
$instances[] = [
|
|
'name' => $name,
|
|
'class' => $className,
|
|
'metadata_cached' => $this->metadataCache->has($className),
|
|
];
|
|
}
|
|
}
|
|
|
|
return new JsonResult([
|
|
'total' => count($instances),
|
|
'instances' => $instances,
|
|
'timestamp' => time(),
|
|
]);
|
|
}
|
|
}
|