feat(Production): Complete production deployment infrastructure

- 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.
This commit is contained in:
2025-10-25 19:18:37 +02:00
parent caa85db796
commit fc3d7e6357
83016 changed files with 378904 additions and 20919 deletions

View File

@@ -0,0 +1,857 @@
# Performance Profiling
Comprehensive Performance Profiling System mit Flamegraph-Visualisierung und Timeline-Analyse.
## Übersicht
Das Framework bietet ein leistungsstarkes Performance Profiling System mit:
- **Nested Performance Tracking**: Hierarchische Performance-Messungen
- **Flamegraph Visualization**: Brendan Gregg Flamegraph Format
- **Timeline Analysis**: Chronologische Event-Visualisierung
- **Memory Tracking**: Speicherverbrauch-Überwachung
- **LiveComponent Integration**: Spezialisiertes Component-Profiling
## NestedPerformanceTracker
### Grundlegende Verwendung
```php
use App\Framework\Performance\NestedPerformanceTracker;
use App\Framework\Performance\PerformanceCategory;
use App\Framework\Core\ValueObjects\Duration;
// Tracker initialisieren
$tracker = $container->get(NestedPerformanceTracker::class);
// Einfache Operation messen
$result = $tracker->measure(
'database.query',
PerformanceCategory::DATABASE,
function () use ($userRepository) {
return $userRepository->findAll();
}
);
// Mit Context-Informationen
$result = $tracker->measure(
'api.request',
PerformanceCategory::API,
function () {
return $this->apiClient->fetch('/users');
},
context: ['endpoint' => '/users', 'method' => 'GET']
);
```
### Verschachtelte Operationen
```php
// Nested Performance Tracking
$tracker->measure(
'http.request',
PerformanceCategory::CONTROLLER,
function () use ($tracker) {
// Controller-Logik
usleep(5000);
// Nested Database Query
$tracker->measure(
'database.query',
PerformanceCategory::DATABASE,
function () {
usleep(3000);
return ['user_id' => 123];
}
);
// Nested Cache Operation
$tracker->measure(
'cache.get',
PerformanceCategory::CACHE,
function () {
usleep(1000);
return ['cached' => true];
}
);
return ['status' => 'success'];
}
);
```
### Manuelle Start/Stop
```php
// Für komplexere Szenarien
$operationId = $tracker->startOperation(
'complex.operation',
PerformanceCategory::CUSTOM,
context: ['user_id' => 123]
);
try {
// Business Logic
$this->processData();
$this->saveResults();
} finally {
$measurement = $tracker->endOperation($operationId);
}
```
## Flamegraph Visualisierung
### Flamegraph Daten Generieren
```php
// Nach Performance-Messungen
$tracker->measure('parent.operation', PerformanceCategory::CONTROLLER, function () {
$this->tracker->measure('child.operation.1', PerformanceCategory::DATABASE, fn() => sleep(1));
$this->tracker->measure('child.operation.2', PerformanceCategory::CACHE, fn() => sleep(1));
});
// Flamegraph-Daten exportieren
$flamegraphData = $tracker->generateFlamegraph();
/*
Ausgabe-Format:
[
['stack_trace' => 'parent.operation', 'samples' => 50.5],
['stack_trace' => 'parent.operation;child.operation.1', 'samples' => 1000.2],
['stack_trace' => 'parent.operation;child.operation.2', 'samples' => 1000.1]
]
*/
```
### Flamegraph Visualisierung mit flamegraph.pl
```php
// Flamegraph-Format für Brendan Gregg's flamegraph.pl Tool
$flamegraphData = $tracker->generateFlamegraph();
// In Brendan Gregg Format konvertieren
$output = [];
foreach ($flamegraphData as $entry) {
$output[] = sprintf(
"%s %d",
$entry['stack_trace'],
(int) ceil($entry['samples'])
);
}
// In Datei schreiben
file_put_contents('/tmp/flamegraph.txt', implode("\n", $output));
// SVG generieren mit flamegraph.pl
// flamegraph.pl /tmp/flamegraph.txt > /tmp/flamegraph.svg
```
### Flamegraph in HTML einbetten
```html
<!DOCTYPE html>
<html>
<head>
<title>Performance Flamegraph</title>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-flame-graph@4"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/d3-flame-graph@4/dist/d3-flamegraph.css">
</head>
<body>
<div id="chart"></div>
<script>
// Flamegraph-Daten vom Server laden
fetch('/api/performance/flamegraph')
.then(response => response.json())
.then(data => {
// Daten in d3-flame-graph Format konvertieren
const hierarchyData = convertToHierarchy(data);
const flamegraph = d3.flamegraph()
.width(1200)
.cellHeight(18)
.transitionDuration(750)
.minFrameSize(5)
.transitionEase(d3.easeCubic)
.sort(true)
.title("")
.onClick(d => console.log("Clicked:", d.data.name));
d3.select("#chart")
.datum(hierarchyData)
.call(flamegraph);
});
function convertToHierarchy(flamegraphData) {
// Konvertierung von Flamegraph-Format zu d3-hierarchy
const root = { name: "root", value: 0, children: [] };
flamegraphData.forEach(entry => {
const parts = entry.stack_trace.split(';');
let current = root;
parts.forEach((part, index) => {
let child = current.children?.find(c => c.name === part);
if (!child) {
child = {
name: part,
value: entry.samples,
children: index < parts.length - 1 ? [] : undefined
};
if (!current.children) current.children = [];
current.children.push(child);
}
current = child;
});
});
return root;
}
</script>
</body>
</html>
```
## Timeline Visualisierung
### Timeline Daten Generieren
```php
// Nach Performance-Messungen
$timeline = $tracker->generateTimeline();
/*
Ausgabe-Format:
[
[
'name' => 'database.query',
'category' => 'database',
'start_time' => 1704067200.123456,
'end_time' => 1704067200.234567,
'duration_ms' => 111.111,
'depth' => 0,
'operation_id' => 'database_query_1_abc123',
'parent_id' => null,
'self_time_ms' => 111.111,
'memory_delta_mb' => 2.5,
'context' => ['query' => 'SELECT * FROM users']
],
// ... weitere Events
]
*/
```
### Chrome DevTools Timeline Format
```php
// Timeline für Chrome DevTools Performance Tab
$timeline = $tracker->generateTimeline();
// In Chrome Trace Event Format konvertieren
$traceEvents = [];
foreach ($timeline as $event) {
// Begin Event
$traceEvents[] = [
'name' => $event['name'],
'cat' => $event['category'],
'ph' => 'B', // Begin
'ts' => (int)($event['start_time'] * 1_000_000), // Microseconds
'pid' => 1,
'tid' => 1,
'args' => $event['context']
];
// End Event
$traceEvents[] = [
'name' => $event['name'],
'cat' => $event['category'],
'ph' => 'E', // End
'ts' => (int)($event['end_time'] * 1_000_000),
'pid' => 1,
'tid' => 1
];
}
$chromeTrace = [
'traceEvents' => $traceEvents,
'displayTimeUnit' => 'ms',
'otherData' => [
'version' => '1.0'
]
];
// Als JSON speichern
file_put_contents('/tmp/chrome-trace.json', json_encode($chromeTrace));
// In Chrome öffnen: chrome://tracing → Load → chrome-trace.json
```
### Waterfall Visualisierung mit HTML/CSS
```html
<!DOCTYPE html>
<html>
<head>
<style>
.timeline-container {
position: relative;
width: 100%;
height: 600px;
background: #f5f5f5;
padding: 20px;
overflow-x: auto;
}
.timeline-event {
position: absolute;
height: 30px;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
color: white;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border: 1px solid rgba(0,0,0,0.2);
}
.category-database { background-color: #3b82f6; }
.category-cache { background-color: #10b981; }
.category-controller { background-color: #f59e0b; }
.category-view { background-color: #8b5cf6; }
.category-api { background-color: #ec4899; }
.timeline-axis {
position: absolute;
top: 0;
bottom: 0;
border-left: 1px solid #ccc;
}
</style>
</head>
<body>
<div id="timeline-container" class="timeline-container"></div>
<script>
fetch('/api/performance/timeline')
.then(response => response.json())
.then(timeline => {
renderTimeline(timeline);
});
function renderTimeline(timeline) {
const container = document.getElementById('timeline-container');
// Berechne Zeitrahmen
const startTime = Math.min(...timeline.map(e => e.start_time));
const endTime = Math.max(...timeline.map(e => e.end_time));
const totalDuration = (endTime - startTime) * 1000; // ms
const containerWidth = 1200;
const rowHeight = 40;
timeline.forEach((event, index) => {
const eventDiv = document.createElement('div');
eventDiv.className = `timeline-event category-${event.category}`;
// Position berechnen
const left = ((event.start_time - startTime) * 1000 / totalDuration) * containerWidth;
const width = (event.duration_ms / totalDuration) * containerWidth;
const top = event.depth * rowHeight + 10;
eventDiv.style.left = `${left}px`;
eventDiv.style.width = `${width}px`;
eventDiv.style.top = `${top}px`;
eventDiv.innerHTML = `
${event.name}
<small>(${event.duration_ms.toFixed(2)}ms)</small>
`;
eventDiv.title = `
${event.name}
Duration: ${event.duration_ms.toFixed(2)}ms
Self Time: ${event.self_time_ms.toFixed(2)}ms
Memory: ${event.memory_delta_mb.toFixed(2)}MB
`;
container.appendChild(eventDiv);
});
// Set container height
const maxDepth = Math.max(...timeline.map(e => e.depth));
container.style.height = `${(maxDepth + 2) * rowHeight}px`;
}
</script>
</body>
</html>
```
### Gantt Chart Visualisierung
```php
// Gantt Chart Daten vorbereiten
$timeline = $tracker->generateTimeline();
$ganttData = array_map(function($event) {
return [
'id' => $event['operation_id'],
'name' => $event['name'],
'start' => date('Y-m-d H:i:s', (int)$event['start_time']),
'end' => date('Y-m-d H:i:s', (int)$event['end_time']),
'duration' => $event['duration_ms'],
'category' => $event['category'],
'parent' => $event['parent_id'],
'metadata' => [
'self_time' => $event['self_time_ms'],
'memory' => $event['memory_delta_mb'],
'context' => $event['context']
]
];
}, $timeline);
// JSON für Frontend
header('Content-Type: application/json');
echo json_encode($ganttData);
```
## API Controller Integration
### Performance Profiling Endpoint
```php
use App\Framework\Attributes\Route;
use App\Framework\Http\Method;
use App\Framework\Http\Responses\JsonResult;
final readonly class PerformanceProfilingController
{
public function __construct(
private NestedPerformanceTracker $tracker
) {}
#[Route(path: '/api/performance/flamegraph', method: Method::GET)]
public function getFlamegraph(): JsonResult
{
$flamegraphData = $this->tracker->generateFlamegraph();
return new JsonResult([
'data' => $flamegraphData,
'total_operations' => count($flamegraphData),
'generated_at' => date('Y-m-d H:i:s')
]);
}
#[Route(path: '/api/performance/timeline', method: Method::GET)]
public function getTimeline(): JsonResult
{
$timeline = $this->tracker->generateTimeline();
return new JsonResult([
'events' => $timeline,
'total_events' => count($timeline),
'generated_at' => date('Y-m-d H:i:s')
]);
}
#[Route(path: '/api/performance/chrome-trace', method: Method::GET)]
public function getChromeTrace(): JsonResult
{
$timeline = $this->tracker->generateTimeline();
// In Chrome Trace Event Format konvertieren
$traceEvents = $this->convertToChromeTrace($timeline);
return new JsonResult([
'traceEvents' => $traceEvents,
'displayTimeUnit' => 'ms',
'otherData' => [
'version' => '1.0',
'framework' => 'Custom PHP Framework'
]
]);
}
#[Route(path: '/api/performance/summary', method: Method::GET)]
public function getSummary(): JsonResult
{
$summary = $this->tracker->getSummary();
return new JsonResult($summary);
}
#[Route(path: '/api/performance/reset', method: Method::POST)]
public function reset(): JsonResult
{
$this->tracker->reset();
return new JsonResult([
'status' => 'reset',
'message' => 'Performance tracker reset successfully'
]);
}
private function convertToChromeTrace(array $timeline): array
{
$traceEvents = [];
foreach ($timeline as $event) {
// Begin Event
$traceEvents[] = [
'name' => $event['name'],
'cat' => $event['category'],
'ph' => 'B',
'ts' => (int)($event['start_time'] * 1_000_000),
'pid' => 1,
'tid' => 1,
'args' => $event['context']
];
// End Event
$traceEvents[] = [
'name' => $event['name'],
'cat' => $event['category'],
'ph' => 'E',
'ts' => (int)($event['end_time'] * 1_000_000),
'pid' => 1,
'tid' => 1
];
}
return $traceEvents;
}
}
```
## LiveComponent Profiling
### Component-spezifisches Profiling
```php
use App\Framework\LiveComponents\Profiling\LiveComponentProfiler;
final readonly class UserProfileComponent
{
public function __construct(
private LiveComponentProfiler $profiler
) {}
public function resolve(array $data): array
{
// Session-basiertes Profiling starten
$sessionId = $this->profiler->startSession('user-profile');
// Resolve Phase profilen
$userData = $this->profiler->profileResolve(
'user-profile',
fn() => $this->userRepository->find($data['user_id'])
);
// Render Phase profilen
$html = $this->profiler->profileRender(
'user-profile',
fn() => $this->renderTemplate($userData)
);
// Session beenden und Ergebnisse erhalten
$result = $this->profiler->endSession($sessionId);
// Flamegraph exportieren
$flamegraph = $result->exportFlamegraph();
// Timeline exportieren
$timeline = $result->exportTimeline();
return [
'html' => $html,
'profiling' => [
'flamegraph' => $flamegraph,
'timeline' => $timeline,
'total_duration' => $result->getTotalDuration()->toMilliseconds()
]
];
}
}
```
## Performance-Metriken Sammeln
### Metriken zu Prometheus exportieren
```php
use App\Framework\Performance\NestedPerformanceTracker;
final readonly class PerformanceMetricsExporter
{
public function __construct(
private NestedPerformanceTracker $tracker
) {}
public function exportToPrometheus(): string
{
$summary = $this->tracker->getSummary();
$timeline = $this->tracker->generateTimeline();
$metrics = [];
// Total operations counter
$metrics[] = sprintf(
"# HELP performance_operations_total Total number of operations\n" .
"# TYPE performance_operations_total counter\n" .
"performance_operations_total %d",
$summary['total_operations']
);
// Average duration gauge
$metrics[] = sprintf(
"# HELP performance_average_duration_ms Average operation duration in milliseconds\n" .
"# TYPE performance_average_duration_ms gauge\n" .
"performance_average_duration_ms %.2f",
$summary['average_duration_ms']
);
// Per-category metrics
$byCategory = $this->groupByCategory($timeline);
foreach ($byCategory as $category => $events) {
$avgDuration = array_sum(array_column($events, 'duration_ms')) / count($events);
$metrics[] = sprintf(
"performance_category_duration_ms{category=\"%s\"} %.2f",
$category,
$avgDuration
);
}
return implode("\n\n", $metrics) . "\n";
}
private function groupByCategory(array $timeline): array
{
$grouped = [];
foreach ($timeline as $event) {
$category = $event['category'];
if (!isset($grouped[$category])) {
$grouped[$category] = [];
}
$grouped[$category][] = $event;
}
return $grouped;
}
}
```
## Best Practices
### 1. Performance Budget Monitoring
```php
// Performance Budget definieren
$budgets = [
'database.query' => 100, // max 100ms
'api.request' => 500, // max 500ms
'cache.get' => 10, // max 10ms
];
// Nach Messung validieren
$timeline = $tracker->generateTimeline();
foreach ($timeline as $event) {
$budget = $budgets[$event['name']] ?? null;
if ($budget && $event['duration_ms'] > $budget) {
$this->logger->warning('Performance budget exceeded', [
'operation' => $event['name'],
'duration' => $event['duration_ms'],
'budget' => $budget,
'exceeded_by' => $event['duration_ms'] - $budget
]);
}
}
```
### 2. Production Performance Monitoring
```php
// Nur bei langsamen Requests profilen
final readonly class PerformanceMiddleware implements Middleware
{
public function process(Request $request, callable $next): Response
{
$startTime = microtime(true);
$response = $next($request);
$duration = (microtime(true) - $startTime) * 1000;
// Nur bei langsamen Requests (>500ms) Profiling-Daten speichern
if ($duration > 500) {
$flamegraph = $this->tracker->generateFlamegraph();
$timeline = $this->tracker->generateTimeline();
$this->performanceLogger->logSlowRequest([
'url' => (string) $request->uri,
'duration_ms' => $duration,
'flamegraph' => $flamegraph,
'timeline' => $timeline
]);
}
$this->tracker->reset();
return $response;
}
}
```
### 3. Automatische Bottleneck-Erkennung
```php
// Bottlenecks automatisch identifizieren
$timeline = $tracker->generateTimeline();
// Sortiere nach self_time_ms (Zeit ohne Children)
usort($timeline, fn($a, $b) => $b['self_time_ms'] <=> $a['self_time_ms']);
// Top 5 Bottlenecks
$bottlenecks = array_slice($timeline, 0, 5);
foreach ($bottlenecks as $bottleneck) {
$this->logger->info('Performance bottleneck detected', [
'operation' => $bottleneck['name'],
'category' => $bottleneck['category'],
'self_time_ms' => $bottleneck['self_time_ms'],
'total_time_ms' => $bottleneck['duration_ms'],
'percentage' => ($bottleneck['self_time_ms'] / $bottleneck['duration_ms']) * 100
]);
}
```
### 4. Memory Leak Detection
```php
// Memory Leaks über Timeline identifizieren
$timeline = $tracker->generateTimeline();
$totalMemoryDelta = 0;
$suspiciousOperations = [];
foreach ($timeline as $event) {
$totalMemoryDelta += $event['memory_delta_mb'];
// Operationen mit hohem Memory-Verbrauch markieren
if ($event['memory_delta_mb'] > 10) { // > 10MB
$suspiciousOperations[] = [
'operation' => $event['name'],
'memory_mb' => $event['memory_delta_mb'],
'context' => $event['context']
];
}
}
if (!empty($suspiciousOperations)) {
$this->logger->warning('High memory usage detected', [
'total_memory_delta_mb' => $totalMemoryDelta,
'suspicious_operations' => $suspiciousOperations
]);
}
```
## Testing Performance Profiling
```php
// Performance Profiling in Tests
it('profiles nested operations correctly', function () {
$tracker = new NestedPerformanceTracker(
new SystemClock(),
new SystemHighResolutionClock(),
new MemoryMonitor()
);
// Perform tracked operations
$tracker->measure('parent', PerformanceCategory::CONTROLLER, function () use ($tracker) {
usleep(5000);
$tracker->measure('child', PerformanceCategory::DATABASE, function () {
usleep(3000);
});
});
// Validate flamegraph
$flamegraph = $tracker->generateFlamegraph();
expect($flamegraph)->toHaveCount(2);
expect($flamegraph[0]['stack_trace'])->toBe('parent');
expect($flamegraph[1]['stack_trace'])->toBe('parent;child');
// Validate timeline
$timeline = $tracker->generateTimeline();
expect($timeline)->toHaveCount(2);
expect($timeline[0]['name'])->toBe('parent');
expect($timeline[1]['name'])->toBe('child');
expect($timeline[1]['parent_id'])->toBe($timeline[0]['operation_id']);
});
```
## Troubleshooting
### Flamegraph zeigt keine Daten
**Problem**: `generateFlamegraph()` gibt leeres Array zurück
**Lösung**:
```php
// Überprüfe ob Operationen completed sind
$summary = $tracker->getSummary();
dd($summary);
// Stelle sicher dass measure() verwendet wird
$tracker->measure('operation', PerformanceCategory::CUSTOM, fn() => doWork());
// Nicht: startOperation() ohne endOperation()
```
### Timeline Events haben 0ms Duration
**Problem**: Events zeigen `duration_ms: 0`
**Lösung**:
```php
// usleep() verwenden für Tests (mindestens 1000 microseconds)
usleep(1000); // 1ms
// Oder echte Operationen durchführen
$data = $repository->findAll(); // Reale Database Query
```
### Memory Delta ist immer 0
**Problem**: `memory_delta_mb` zeigt 0.00
**Lösung**:
```php
// Memory-intensive Operationen durchführen
$tracker->measure('memory-test', PerformanceCategory::CUSTOM, function () {
$data = array_fill(0, 10000, 'test'); // Allocate memory
return $data;
});
```
## Zusammenfassung
Das Performance Profiling System bietet:
-**Nested Performance Tracking** mit hierarchischen Messungen
-**Flamegraph Export** im Brendan Gregg Format
-**Timeline Visualisierung** mit Chrome DevTools Support
-**Memory Tracking** für Leak Detection
-**LiveComponent Integration** für Component-spezifisches Profiling
-**Production Monitoring** mit Performance Budget Validation
-**Automatische Bottleneck Detection** und Alerting
**Verwendung**:
1. Operations mit `measure()` tracken
2. `generateFlamegraph()` für Flamegraph-Visualisierung
3. `generateTimeline()` für Timeline-Analyse
4. In Visualisierungs-Tools integrieren (Chrome DevTools, flamegraph.pl, D3.js)
5. Performance Budgets definieren und monitoren