feat: add API Gateway, RapidMail and Shopify integrations, update WireGuard configs, add Redis override and architecture docs
This commit is contained in:
302
src/Framework/ApiGateway/Metrics/ApiMetrics.php
Normal file
302
src/Framework/ApiGateway/Metrics/ApiMetrics.php
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\ApiGateway\Metrics;
|
||||
|
||||
use App\Framework\Metrics\MetricsCollection;
|
||||
|
||||
/**
|
||||
* Collects and tracks metrics for API Gateway operations
|
||||
*/
|
||||
final class ApiMetrics
|
||||
{
|
||||
/** @var array<string, array{requests: int, successes: int, failures: int, total_duration_ms: float, avg_duration_ms: float}> */
|
||||
private array $statsByService = [];
|
||||
|
||||
/** @var array<string, array{requests: int, successes: int, failures: int, total_duration_ms: float, avg_duration_ms: float}> */
|
||||
private array $statsByRequestName = [];
|
||||
|
||||
private int $totalRequests = 0;
|
||||
private int $totalSuccesses = 0;
|
||||
private int $totalFailures = 0;
|
||||
private float $totalDurationMs = 0.0;
|
||||
|
||||
/** @var array<string, int> */
|
||||
private array $retryCountByService = [];
|
||||
|
||||
/** @var array<string, int> */
|
||||
private array $circuitBreakerOpenCountByService = [];
|
||||
|
||||
public function recordRequest(
|
||||
string $service,
|
||||
string $requestName,
|
||||
float $durationMs,
|
||||
bool $success,
|
||||
int $retryAttempts = 0,
|
||||
bool $circuitBreakerTriggered = false
|
||||
): void {
|
||||
// Total stats
|
||||
$this->totalRequests++;
|
||||
if ($success) {
|
||||
$this->totalSuccesses++;
|
||||
} else {
|
||||
$this->totalFailures++;
|
||||
}
|
||||
$this->totalDurationMs += $durationMs;
|
||||
|
||||
// Per-service stats
|
||||
if (!isset($this->statsByService[$service])) {
|
||||
$this->statsByService[$service] = [
|
||||
'requests' => 0,
|
||||
'successes' => 0,
|
||||
'failures' => 0,
|
||||
'total_duration_ms' => 0.0,
|
||||
'avg_duration_ms' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$this->statsByService[$service]['requests']++;
|
||||
if ($success) {
|
||||
$this->statsByService[$service]['successes']++;
|
||||
} else {
|
||||
$this->statsByService[$service]['failures']++;
|
||||
}
|
||||
$this->statsByService[$service]['total_duration_ms'] += $durationMs;
|
||||
$this->statsByService[$service]['avg_duration_ms'] =
|
||||
$this->statsByService[$service]['total_duration_ms'] / $this->statsByService[$service]['requests'];
|
||||
|
||||
// Per-request-name stats
|
||||
if (!isset($this->statsByRequestName[$requestName])) {
|
||||
$this->statsByRequestName[$requestName] = [
|
||||
'requests' => 0,
|
||||
'successes' => 0,
|
||||
'failures' => 0,
|
||||
'total_duration_ms' => 0.0,
|
||||
'avg_duration_ms' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$this->statsByRequestName[$requestName]['requests']++;
|
||||
if ($success) {
|
||||
$this->statsByRequestName[$requestName]['successes']++;
|
||||
} else {
|
||||
$this->statsByRequestName[$requestName]['failures']++;
|
||||
}
|
||||
$this->statsByRequestName[$requestName]['total_duration_ms'] += $durationMs;
|
||||
$this->statsByRequestName[$requestName]['avg_duration_ms'] =
|
||||
$this->statsByRequestName[$requestName]['total_duration_ms'] / $this->statsByRequestName[$requestName]['requests'];
|
||||
|
||||
// Retry tracking
|
||||
if ($retryAttempts > 0) {
|
||||
if (!isset($this->retryCountByService[$service])) {
|
||||
$this->retryCountByService[$service] = 0;
|
||||
}
|
||||
$this->retryCountByService[$service] += $retryAttempts;
|
||||
}
|
||||
|
||||
// Circuit breaker tracking
|
||||
if ($circuitBreakerTriggered) {
|
||||
if (!isset($this->circuitBreakerOpenCountByService[$service])) {
|
||||
$this->circuitBreakerOpenCountByService[$service] = 0;
|
||||
}
|
||||
$this->circuitBreakerOpenCountByService[$service]++;
|
||||
}
|
||||
}
|
||||
|
||||
public function getStats(): array
|
||||
{
|
||||
return [
|
||||
'total' => [
|
||||
'requests' => $this->totalRequests,
|
||||
'successes' => $this->totalSuccesses,
|
||||
'failures' => $this->totalFailures,
|
||||
'success_rate' => $this->getSuccessRate(),
|
||||
'avg_duration_ms' => $this->getAverageDuration(),
|
||||
],
|
||||
'by_service' => $this->statsByService,
|
||||
'by_request_name' => $this->statsByRequestName,
|
||||
'retry_counts' => $this->retryCountByService,
|
||||
'circuit_breaker_opens' => $this->circuitBreakerOpenCountByService,
|
||||
];
|
||||
}
|
||||
|
||||
public function getSuccessRate(): float
|
||||
{
|
||||
if ($this->totalRequests === 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return $this->totalSuccesses / $this->totalRequests;
|
||||
}
|
||||
|
||||
public function getAverageDuration(): float
|
||||
{
|
||||
if ($this->totalRequests === 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return $this->totalDurationMs / $this->totalRequests;
|
||||
}
|
||||
|
||||
public function getServiceStats(string $service): ?array
|
||||
{
|
||||
return $this->statsByService[$service] ?? null;
|
||||
}
|
||||
|
||||
public function getRequestNameStats(string $requestName): ?array
|
||||
{
|
||||
return $this->statsByRequestName[$requestName] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect metrics for Prometheus export
|
||||
*/
|
||||
public function collectMetrics(MetricsCollection $collection): void
|
||||
{
|
||||
// Total request counter
|
||||
$collection->counter(
|
||||
'api_gateway_requests_total',
|
||||
(float) $this->totalRequests,
|
||||
'Total number of API gateway requests'
|
||||
);
|
||||
|
||||
// Success counter
|
||||
$collection->counter(
|
||||
'api_gateway_requests_success_total',
|
||||
(float) $this->totalSuccesses,
|
||||
'Total number of successful API gateway requests'
|
||||
);
|
||||
|
||||
// Failure counter
|
||||
$collection->counter(
|
||||
'api_gateway_requests_failure_total',
|
||||
(float) $this->totalFailures,
|
||||
'Total number of failed API gateway requests'
|
||||
);
|
||||
|
||||
// Success rate gauge
|
||||
$collection->gauge(
|
||||
'api_gateway_success_rate',
|
||||
$this->getSuccessRate(),
|
||||
'Success rate of API gateway requests (0.0 to 1.0)'
|
||||
);
|
||||
|
||||
// Average duration gauge
|
||||
$collection->gauge(
|
||||
'api_gateway_request_duration_ms',
|
||||
$this->getAverageDuration(),
|
||||
'Average duration of API gateway requests in milliseconds'
|
||||
);
|
||||
|
||||
// Per-service metrics
|
||||
foreach ($this->statsByService as $service => $stats) {
|
||||
$labels = ['service' => $service];
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_total',
|
||||
(float) $stats['requests'],
|
||||
'Total requests per service',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_success_total',
|
||||
(float) $stats['successes'],
|
||||
'Successful requests per service',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_failure_total',
|
||||
(float) $stats['failures'],
|
||||
'Failed requests per service',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->gauge(
|
||||
'api_gateway_request_duration_ms',
|
||||
$stats['avg_duration_ms'],
|
||||
'Average request duration per service in milliseconds',
|
||||
$labels
|
||||
);
|
||||
|
||||
// Success rate per service
|
||||
$successRate = $stats['requests'] > 0
|
||||
? $stats['successes'] / $stats['requests']
|
||||
: 0.0;
|
||||
|
||||
$collection->gauge(
|
||||
'api_gateway_success_rate',
|
||||
$successRate,
|
||||
'Success rate per service',
|
||||
$labels
|
||||
);
|
||||
}
|
||||
|
||||
// Per-request-name metrics
|
||||
foreach ($this->statsByRequestName as $requestName => $stats) {
|
||||
$labels = ['request_name' => $requestName];
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_total',
|
||||
(float) $stats['requests'],
|
||||
'Total requests per request name',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_success_total',
|
||||
(float) $stats['successes'],
|
||||
'Successful requests per request name',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->counter(
|
||||
'api_gateway_requests_failure_total',
|
||||
(float) $stats['failures'],
|
||||
'Failed requests per request name',
|
||||
$labels
|
||||
);
|
||||
|
||||
$collection->gauge(
|
||||
'api_gateway_request_duration_ms',
|
||||
$stats['avg_duration_ms'],
|
||||
'Average request duration per request name in milliseconds',
|
||||
$labels
|
||||
);
|
||||
}
|
||||
|
||||
// Retry metrics per service
|
||||
foreach ($this->retryCountByService as $service => $retryCount) {
|
||||
$collection->counter(
|
||||
'api_gateway_retries_total',
|
||||
(float) $retryCount,
|
||||
'Total number of retry attempts per service',
|
||||
['service' => $service]
|
||||
);
|
||||
}
|
||||
|
||||
// Circuit breaker metrics per service
|
||||
foreach ($this->circuitBreakerOpenCountByService as $service => $openCount) {
|
||||
$collection->counter(
|
||||
'api_gateway_circuit_breaker_open_total',
|
||||
(float) $openCount,
|
||||
'Total number of circuit breaker opens per service',
|
||||
['service' => $service]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->statsByService = [];
|
||||
$this->statsByRequestName = [];
|
||||
$this->totalRequests = 0;
|
||||
$this->totalSuccesses = 0;
|
||||
$this->totalFailures = 0;
|
||||
$this->totalDurationMs = 0.0;
|
||||
$this->retryCountByService = [];
|
||||
$this->circuitBreakerOpenCountByService = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user