Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
140 lines
5.1 KiB
PHP
140 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Application\LiveComponents\Dashboard;
|
|
|
|
use App\Framework\Core\ValueObjects\Byte;
|
|
use App\Framework\Core\ValueObjects\Percentage;
|
|
use App\Framework\DateTime\Clock;
|
|
use App\Framework\LiveComponents\Attributes\Action;
|
|
use App\Framework\LiveComponents\Attributes\LiveComponent;
|
|
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
|
|
use App\Framework\LiveComponents\Contracts\Pollable;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
|
|
use App\Framework\Performance\MemoryMonitor;
|
|
|
|
/**
|
|
* Performance Metrics LiveComponent
|
|
*
|
|
* Displays real-time performance metrics:
|
|
* - Memory usage (current, peak, limit, percentage)
|
|
* - Load average
|
|
* - Execution time
|
|
* - OPCache statistics
|
|
*
|
|
* Polls every 3 seconds for real-time monitoring.
|
|
*/
|
|
#[LiveComponent('performance-metrics')]
|
|
final readonly class PerformanceMetricsComponent implements LiveComponentContract, Pollable
|
|
{
|
|
public function __construct(
|
|
public ComponentId $id,
|
|
public PerformanceMetricsState $state,
|
|
private MemoryMonitor $memoryMonitor,
|
|
private Clock $clock
|
|
) {}
|
|
|
|
public function getRenderData(): ComponentRenderData
|
|
{
|
|
// Initial poll if state is empty (lastUpdated is empty string)
|
|
$state = $this->state->lastUpdated === ''
|
|
? $this->poll()
|
|
: $this->state;
|
|
|
|
return new ComponentRenderData(
|
|
templatePath: 'livecomponent-performance-metrics',
|
|
data: [
|
|
// LiveComponent integration
|
|
'componentId' => $this->id->toString(),
|
|
'stateJson' => json_encode($state->toArray()),
|
|
'pollInterval' => $this->getPollInterval(),
|
|
|
|
// Component data
|
|
'currentMemory' => $state->currentMemory,
|
|
'peakMemory' => $state->peakMemory,
|
|
'memoryLimit' => $state->memoryLimit,
|
|
'memoryUsagePercentage' => $state->memoryUsagePercentage,
|
|
'loadAverage' => $state->loadAverage,
|
|
'executionTime' => $state->executionTime,
|
|
'includedFiles' => $state->includedFiles,
|
|
'opcacheEnabled' => $state->opcacheEnabled,
|
|
'opcacheMemoryUsage' => $state->opcacheMemoryUsage,
|
|
'opcacheCacheHits' => $state->opcacheCacheHits,
|
|
'opcacheMissRate' => $state->opcacheMissRate,
|
|
'lastUpdated' => $state->lastUpdated,
|
|
]
|
|
);
|
|
}
|
|
|
|
#[Action]
|
|
public function poll(): PerformanceMetricsState
|
|
{
|
|
// Get memory metrics
|
|
$currentMemory = $this->memoryMonitor->getCurrentMemory();
|
|
$peakMemory = $this->memoryMonitor->getPeakMemory();
|
|
$memoryLimit = $this->memoryMonitor->getMemoryLimit();
|
|
$usagePercentage = $this->memoryMonitor->getMemoryUsagePercentage();
|
|
|
|
// Get load average
|
|
$loadAverage = function_exists('sys_getloadavg') ? sys_getloadavg() : ['N/A', 'N/A', 'N/A'];
|
|
|
|
// Calculate execution time
|
|
$executionTime = number_format(
|
|
microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true)),
|
|
4
|
|
) . ' Sekunden';
|
|
|
|
// Get included files count
|
|
$includedFiles = count(get_included_files());
|
|
|
|
// Check OPCache status
|
|
$opcacheEnabled = function_exists('opcache_get_status');
|
|
$opcacheMemoryUsage = null;
|
|
$opcacheCacheHits = null;
|
|
$opcacheMissRate = null;
|
|
|
|
if ($opcacheEnabled) {
|
|
try {
|
|
$opcacheStatus = opcache_get_status(false);
|
|
if ($opcacheStatus !== false) {
|
|
$memoryUsed = Byte::fromBytes($opcacheStatus['memory_usage']['used_memory']);
|
|
$opcacheMemoryUsage = $memoryUsed->toHumanReadable();
|
|
$opcacheCacheHits = number_format($opcacheStatus['opcache_statistics']['hits']);
|
|
|
|
$hits = $opcacheStatus['opcache_statistics']['hits'];
|
|
$misses = $opcacheStatus['opcache_statistics']['misses'];
|
|
$total = $hits + $misses;
|
|
if ($total > 0) {
|
|
$missRate = Percentage::from(($misses / $total) * 100);
|
|
$opcacheMissRate = $missRate->format(2) . '%';
|
|
}
|
|
}
|
|
} catch (\Throwable) {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
|
|
return $this->state->withMetrics(
|
|
currentMemory: $currentMemory->toHumanReadable(),
|
|
peakMemory: $peakMemory->toHumanReadable(),
|
|
memoryLimit: $memoryLimit->toHumanReadable(),
|
|
memoryUsagePercentage: (float) $usagePercentage->format(2),
|
|
loadAverage: $loadAverage,
|
|
executionTime: $executionTime,
|
|
includedFiles: $includedFiles,
|
|
opcacheEnabled: $opcacheEnabled,
|
|
opcacheMemoryUsage: $opcacheMemoryUsage,
|
|
opcacheCacheHits: $opcacheCacheHits,
|
|
opcacheMissRate: $opcacheMissRate
|
|
);
|
|
}
|
|
|
|
public function getPollInterval(): int
|
|
{
|
|
return 3000; // Poll every 3 seconds for real-time updates
|
|
}
|
|
}
|
|
|