This package provides you an ability to collect and export Prometheus metrics from any modern PHP application.
- Until now, there was no working Prometheus client for modern PHP
- Framework-agnostic
- Almost zero dependencies
- Won't break your business logic even if something is wrong with Metrics Storage
- Ready to use with static analysis tools (PHPStan, Psalm)
- For Laravel: zlodes/prometheus-client-laravel
composer require zlodes/prometheus-client
TL;DR: Read Simple example.
- Set up a storage to store metrics. There are four interfaces can be implemented:
- Set up a Registry to register your metrics. ArrayRegistry is a default implementation.
- Register your metrics using the Registry from step 2.
- Get a collector for your metric from a CollectorFactory
- Call metric update method (e.g.
increment
on CounterCollector)
- Create a controller to export metrics. Your controller should use Exporter. FetcherExporter is a default implementation.
- Set up a Prometheus to scrape metrics from your application using the controller from step 1.
<?php
use Psr\Log\NullLogger;
use Zlodes\PrometheusClient\Collector\CollectorFactory;
use Zlodes\PrometheusClient\Exporter\FetcherExporter;
use Zlodes\PrometheusClient\Metric\Counter;
use Zlodes\PrometheusClient\Metric\Gauge;
use Zlodes\PrometheusClient\Metric\Histogram;
use Zlodes\PrometheusClient\Registry\ArrayRegistry;
use Zlodes\PrometheusClient\Storage\InMemoryStorage;
$registry = new ArrayRegistry();
$counterStorage = new InMemoryCounterStorage();
$gaugeStorage = new InMemoryGaugeStorage();
$histogramStorage = new InMemoryHistogramStorage();
$summaryStorage = new InMemorySummaryStorage();
// Register your metrics
$registry
->registerMetric(
new Gauge('body_temperature', 'Body temperature in Celsius')
)
->registerMetric(
new Counter('steps', 'Steps count')
)
->registerMetric(
(new Histogram('http_request_duration_seconds', 'HTTP Request duration'))
->withBuckets([0.1, 0.5, 1]),
)
->registerMetric(
(new Summary('memory_used', 'Used memory in bytes'))
->withQuantiles([0.5, 0.9, 0.99])
);
// Create a Collector factory
$collectorFactory = new CollectorFactory(
$registry,
$counterStorage,
$gaugeStorage,
$histogramStorage,
$summaryStorage,
new NullLogger(),
);
// Collect metrics
$bodyTemperatureGauge = $collectorFactory->gauge('body_temperature');
$bodyTemperatureGauge
->withLabels(['source' => 'armpit'])
->update(36.6);
$bodyTemperatureGauge
->withLabels(['source' => 'ass'])
->update(37.2);
$collectorFactory
->counter('steps')
->increment();
$requestTimer = $collectorFactory
->histogram('http_request_duration_seconds')
->startTimer();
usleep(50_000);
$requestTimer->stop();
$collectorFactory
->summary('memory_used')
->update(100);
$collectorFactory
->summary('memory_used')
->update(200);
// Export metrics
$fetcher = new StoredMetricsFetcher(
$registry,
$counterStorage,
$gaugeStorage,
$histogramStorage,
$summaryStorage,
);
$exporter = new FetcherExporter($fetcher);
foreach ($exporter->export() as $metricOutput) {
echo $metricOutput . "\n\n";
}
Output example:
# HELP steps Steps count
# TYPE steps counter
steps 1
# HELP body_temperature Body temperature in Celsius
# TYPE body_temperature gauge
body_temperature{source="armpit"} 36.6
body_temperature{source="ass"} 37.2
# HELP http_request_duration_seconds HTTP Request duration
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds{le="0.1"} 1
http_request_duration_seconds{le="0.5"} 1
http_request_duration_seconds{le="1"} 1
http_request_duration_seconds{le="+Inf"} 1
http_request_duration_seconds_sum 0.050071506
http_request_duration_seconds_count 1
# HELP memory_used Used memory in bytes
# TYPE memory_used summary
memory_used{quantile="0.5"} 150
memory_used{quantile="0.9"} 190
memory_used{quantile="0.99"} 199
memory_used_sum 300
memory_used_count 2
php ./vendor/bin/phpunit
There is a Serializer interface (with JSON-based implementation) to simplify work with a key-value storage.
Example can be found in InMemoryStorage.
There are four useful traits to simplify your storage testing:
They provide you a set of tests to check your storage implementation to be compatible with the library.
Example:
<?php
use PHPUnit\Framework\TestCase;
use Zlodes\PrometheusClient\Storage\Contracts\CounterStorage;
use Zlodes\PrometheusClient\Storage\InMemory\InMemoryCounterStorage;
use Zlodes\PrometheusClient\Storage\Testing\CounterStorageTesting;
class InMemoryCounterStorageTest extends TestCase
{
use CounterStorageTesting;
private function createStorage(): CounterStorage
{
return new InMemoryCounterStorage();
}
}