ez-php / metrics
Prometheus metrics endpoint for ez-php — Counter, Gauge, Histogram with a /metrics route and static Metrics facade.
Requires
- php: ^8.5
- ez-php/contracts: ^2.0
- ez-php/http: ^2.0
Requires (Dev)
- ez-php/docker: ^2.0
- ez-php/health: ^2.0
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^13.0
Suggests
- ez-php/health: Needed for HealthMetricsListener (probe status/latency as gauges)
Provides
None
Conflicts
None
Replaces
None
- dev-main
- 2.5.4
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.11
- 2.4.10
- 2.4.9
- 2.4.8
- 2.4.7
- 2.4.6
- 2.4.5
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.9
- 2.3.8
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.1
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.14.0
- 1.13.1
- 1.13.0
- 1.12.2
- 1.12.1
- 1.12.0
- 1.11.2
- 1.11.1
- 1.11.0
- 1.10.0
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.0
- 1.7.1
- 1.7.0
- 1.6.1
- 1.6.0
- 1.5.1
- 1.5.0
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.0
This package is auto-updated.
Last update: 2026-09-30 19:50:23 UTC
README
Prometheus metrics endpoint for the ez-php framework.
Exposes a /metrics route in the Prometheus text exposition format.
Supports the three standard Prometheus metric types: Counter, Gauge, and Histogram.
Installation
composer require ez-php/metrics
Register the provider in provider/modules.php:
\EzPhp\Metrics\MetricsServiceProvider::class,
Usage
Counter — monotonically increasing
use EzPhp\Metrics\Metrics; Metrics::counter('http_requests_total', 'Total HTTP requests') ->inc(['method' => 'GET', 'status' => '200']); Metrics::counter('bytes_sent_total', 'Total bytes sent') ->incBy(1024.0);
Gauge — current value (can increase or decrease)
Metrics::gauge('memory_usage_bytes', 'Current memory usage') ->set((float) memory_get_usage()); Metrics::gauge('active_connections', 'Active connections') ->inc(); Metrics::gauge('queue_depth', 'Queue depth') ->dec(['queue' => 'default']);
Histogram — distributions and latency
$start = microtime(true); // ... handle request ... Metrics::histogram('request_duration_seconds', 'Request duration in seconds') ->observe(microtime(true) - $start, ['route' => '/api/users']);
Custom bucket boundaries:
Metrics::histogram('response_size_bytes', 'Response size', [100, 1000, 10000, 100000]) ->observe((float) strlen($responseBody));
/metrics endpoint
MetricsServiceProvider registers GET /metrics automatically. The response body is the full Prometheus text exposition format output:
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 42
# HELP request_duration_seconds Request duration in seconds
# TYPE request_duration_seconds histogram
request_duration_seconds_bucket{route="/api/users",le="0.005"} 0
...
request_duration_seconds_bucket{route="/api/users",le="+Inf"} 5
request_duration_seconds_count{route="/api/users"} 5
request_duration_seconds_sum{route="/api/users"} 1.23
Content-Type: text/plain; version=0.0.4; charset=utf-8
Sharing values between workers
By default values live in the PHP process — fine for long-running processes, but under PHP-FPM
every request starts from zero. Pick a shared storage in config/metrics.php:
metrics.storage |
Shared by | Requires |
|---|---|---|
memory (default) |
nothing — one process | — |
apcu |
the PHP-FPM workers of one host | ext-apcu (apc.enable_cli=1 for CLI) |
redis |
every host | ext-redis, metrics.redis.* |
Metric descriptions are stored too, so the /metrics request lists series that were only touched in
other requests. APCu stores values with 6 decimal places.
Security
The endpoint is unprotected by default, and the provider registers the route itself, so there is
no route definition of yours to add middleware to. To protect it, turn off auto-registration in
config/metrics.php and register the controller yourself:
// config/metrics.php return [ 'endpoint' => false, // or METRICS_ENDPOINT= (empty) ]; // routes/web.php use EzPhp\Metrics\MetricsController; $router->get('/metrics', [MetricsController::class, '__invoke']) ->middleware(App\Middleware\MetricsAuthMiddleware::class);
metrics.endpoint also changes the path (default /metrics). Global middleware
($app->middleware(...)) works too, but applies to every route.
Relation to ez-php/health
| Module | Purpose |
|---|---|
ez-php/health |
Liveness check — is the service up? |
ez-php/metrics |
Time-series data — counters, gauges, histograms for alerting and dashboards |
Both are complementary production-observability tools.
HealthMetricsListener bridges the two directly, so a health check's status/latency shows up
as a metric without duplicating probe logic (requires ez-php/health — a soft dependency,
declared in require-dev here, install it separately):
use EzPhp\Metrics\HealthMetricsListener; $listener = new HealthMetricsListener($healthRegistry, $metricsRegistry); $listener->record(); // before serving /metrics, or on a schedule — your call
Sets health_probe_status{probe="<name>"} (1=ok, 0.5=degraded, 0=unhealthy) and
health_probe_latency_ms{probe="<name>"} for every probe in $healthRegistry.
License
MIT