Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Prometheus Client PHP
https://github.com/promphp/prometheus_client_php
Admin
Prometheus Client PHP is a PHP client library for Prometheus, enabling client-side metric
...
Tokens:
7,493
Snippets:
41
Trust Score:
5.5
Update:
5 months ago
Context
Skills
Chat
Benchmark
89.3
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Prometheus Client PHP ## Introduction Prometheus Client PHP is a comprehensive instrumentation library designed to collect, aggregate, and expose application metrics in Prometheus format. This library provides a PHP implementation of the Prometheus client, enabling developers to monitor their PHP applications using counters, gauges, histograms, and summaries. The library addresses the challenge of metric aggregation in PHP's shared-nothing architecture by supporting multiple storage adapters including Redis, APCu, APCng, and in-memory storage. The library implements the Prometheus exposition format and provides a complete solution for metric collection and rendering. It offers a flexible registry system for managing metrics, supports multiple metric types with labels for multi-dimensional data, and includes built-in metric persistence across requests. The client handles the complexity of metric aggregation in stateless PHP environments, making it suitable for both traditional web applications and long-running CLI scripts. ## APIs and Functions ### CollectorRegistry::getDefault() - Default Registry Singleton Returns the default collector registry instance with Redis storage adapter, providing a convenient way to start collecting metrics without explicit configuration. ```php <?php use Prometheus\CollectorRegistry; // Quick counter increment using default registry CollectorRegistry::getDefault() ->getOrRegisterCounter('', 'page_views', 'Total page views') ->inc(); // Multiple metrics with default registry $registry = CollectorRegistry::getDefault(); $counter = $registry->getOrRegisterCounter('app', 'requests_total', 'Total requests', ['method', 'status']); $counter->incBy(1, ['GET', '200']); $gauge = $registry->getOrRegisterGauge('app', 'active_users', 'Currently active users'); $gauge->set(42); ``` ### CollectorRegistry::__construct() - Custom Storage Configuration Creates a collector registry with a specific storage adapter, enabling fine-grained control over metric persistence and performance characteristics. ```php <?php use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; use Prometheus\Storage\InMemory; use Prometheus\Storage\APCng; // Redis storage with custom configuration Redis::setDefaultOptions([ 'host' => '192.168.1.100', 'port' => 6379, 'password' => 'secret', 'timeout' => 0.1, 'read_timeout' => '10', 'persistent_connections' => true, 'database' => 1 ]); $redisRegistry = new CollectorRegistry(new Redis()); // In-memory storage for CLI scripts $memoryRegistry = new CollectorRegistry(new InMemory()); $counter = $memoryRegistry->registerCounter('cli', 'jobs_processed', 'Jobs processed', ['type']); $counter->incBy(10, ['import']); // APCng storage for single-server setups $apcRegistry = new CollectorRegistry(new APCng()); // Disable default metrics (php_info gauge) $customRegistry = new CollectorRegistry(new InMemory(), false); ``` ### Counter::inc() and Counter::incBy() - Monotonic Counter Operations Increments a counter metric by 1 or a specific amount, ideal for tracking events, requests, errors, and other cumulative values that only increase. ```php <?php use Prometheus\CollectorRegistry; $registry = CollectorRegistry::getDefault(); // Simple counter without labels $requestCounter = $registry->getOrRegisterCounter('app', 'http_requests_total', 'Total HTTP requests'); $requestCounter->inc(); // Counter with labels for multi-dimensional metrics $errorCounter = $registry->getOrRegisterCounter( 'app', 'errors_total', 'Total errors by type and severity', ['error_type', 'severity'] ); try { // Application code throw new \Exception('Database connection failed'); } catch (\Exception $e) { $errorCounter->inc(['database', 'critical']); } // Increment by custom amount (integer or float) $bytesCounter = $registry->getOrRegisterCounter('app', 'bytes_sent', 'Total bytes sent', ['endpoint']); $bytesCounter->incBy(1024, ['/api/users']); $bytesCounter->incBy(2048.5, ['/api/products']); // Track API calls per client $apiCounter = $registry->getOrRegisterCounter('api', 'calls_total', 'API calls', ['client_id', 'method']); $apiCounter->incBy(5, ['client_123', 'POST']); ``` ### Gauge::set(), Gauge::inc(), Gauge::dec() - Current Value Tracking Sets, increments, or decrements a gauge metric to track values that can go up or down, such as temperature, memory usage, queue length, or active connections. ```php <?php use Prometheus\CollectorRegistry; $registry = CollectorRegistry::getDefault(); // Set absolute value $memoryGauge = $registry->getOrRegisterGauge('system', 'memory_usage_bytes', 'Memory usage', ['type']); $memoryGauge->set(memory_get_usage(true), ['allocated']); $memoryGauge->set(memory_get_peak_usage(true), ['peak']); // Track active connections $connectionsGauge = $registry->getOrRegisterGauge('app', 'active_connections', 'Active connections', ['pool']); $connectionsGauge->set(15, ['database']); // Increment and decrement operations $queueGauge = $registry->getOrRegisterGauge('jobs', 'queue_size', 'Current queue size', ['queue_name']); // Job added to queue $queueGauge->inc(['email']); // Increment by 1 $queueGauge->incBy(5, ['email']); // Add 5 jobs // Job completed $queueGauge->dec(['email']); // Decrement by 1 $queueGauge->decBy(3, ['email']); // Remove 3 jobs // Temperature monitoring $tempGauge = $registry->getOrRegisterGauge('hardware', 'cpu_temperature_celsius', 'CPU temperature'); $tempGauge->set(67.5); ``` ### Histogram::observe() - Distribution Measurement Records observations in predefined buckets to measure the distribution of values, commonly used for request durations, response sizes, and other measurable quantities. ```php <?php use Prometheus\CollectorRegistry; use Prometheus\Histogram; $registry = CollectorRegistry::getDefault(); // Default buckets suitable for web latency (in seconds) $durationHistogram = $registry->getOrRegisterHistogram( 'app', 'request_duration_seconds', 'Request duration in seconds', ['method', 'endpoint'] ); $startTime = microtime(true); // Process request sleep(1); $duration = microtime(true) - $startTime; $durationHistogram->observe($duration, ['GET', '/api/users']); // Custom buckets for specific use cases $sizeHistogram = $registry->getOrRegisterHistogram( 'app', 'response_size_bytes', 'Response size in bytes', ['endpoint'], [100, 500, 1000, 5000, 10000, 50000, 100000] ); $sizeHistogram->observe(2048, ['/api/products']); // Exponential buckets for wide value ranges $exponentialBuckets = Histogram::exponentialBuckets(0.05, 1.5, 10); // Creates buckets: 0.05, 0.075, 0.1125, 0.16875, ... $queryHistogram = $registry->getOrRegisterHistogram( 'database', 'query_duration_seconds', 'Database query duration', ['query_type'], $exponentialBuckets ); foreach (['SELECT', 'INSERT', 'UPDATE'] as $type) { $queryStart = microtime(true); // Execute query $queryDuration = microtime(true) - $queryStart; $queryHistogram->observe($queryDuration, [$type]); } // Default buckets for typical web app latency $defaultHistogram = $registry->getOrRegisterHistogram( 'http', 'request_latency_seconds', 'HTTP request latency' ); $defaultHistogram->observe(0.125); // Uses default buckets ``` ### Summary::observe() - Quantile Calculation Records observations and calculates quantiles over a sliding time window, useful for percentile calculations without the memory overhead of storing all values. ```php <?php use Prometheus\CollectorRegistry; $registry = CollectorRegistry::getDefault(); // Default quantiles (0.01, 0.05, 0.5, 0.95, 0.99) with 10-minute window $responseSummary = $registry->getOrRegisterSummary( 'app', 'response_time_seconds', 'Response time summary', ['service'] ); $responseSummary->observe(0.25, ['user_service']); $responseSummary->observe(0.15, ['user_service']); $responseSummary->observe(0.45, ['user_service']); // Custom quantiles and time window (24 hours = 86400 seconds) $latencySummary = $registry->getOrRegisterSummary( 'api', 'endpoint_latency_seconds', 'API endpoint latency percentiles', ['endpoint', 'method'], 86400, // 24-hour sliding window [0.5, 0.9, 0.95, 0.99, 0.999] // 50th, 90th, 95th, 99th, 99.9th percentiles ); for ($i = 0; $i < 100; $i++) { $latency = rand(50, 500) / 1000; // Random latency between 0.05-0.5 seconds $latencySummary->observe($latency, ['/api/users', 'GET']); } // Processing time summary with 1-hour window $processSummary = $registry->getOrRegisterSummary( 'batch', 'processing_time_seconds', 'Batch processing time', ['job_type'], 3600, // 1-hour window [0.01, 0.05, 0.5, 0.95, 0.99] ); $processSummary->observe(12.5, ['import']); $processSummary->observe(8.3, ['export']); ``` ### RenderTextFormat::render() - Metrics Export Renders collected metrics in Prometheus text exposition format, ready to be scraped by Prometheus or viewed by monitoring tools. ```php <?php use Prometheus\CollectorRegistry; use Prometheus\RenderTextFormat; $registry = CollectorRegistry::getDefault(); // Add some metrics $counter = $registry->getOrRegisterCounter('app', 'requests', 'Total requests', ['status']); $counter->incBy(150, ['200']); $counter->incBy(10, ['404']); $counter->incBy(5, ['500']); $gauge = $registry->getOrRegisterGauge('app', 'memory_bytes', 'Memory usage'); $gauge->set(33554432); // Render metrics $renderer = new RenderTextFormat(); $output = $renderer->render($registry->getMetricFamilySamples()); // Expose as HTTP endpoint header('Content-type: ' . RenderTextFormat::MIME_TYPE); echo $output; /* Output format: # HELP app_memory_bytes Memory usage # TYPE app_memory_bytes gauge app_memory_bytes 33554432 # HELP app_requests Total requests # TYPE app_requests counter app_requests{status="200"} 150 app_requests{status="404"} 10 app_requests{status="500"} 5 # HELP php_info Information about the PHP environment. # TYPE php_info gauge php_info{version="8.1.0"} 1 */ // Silent mode to handle label mismatches gracefully $silentOutput = $renderer->render($registry->getMetricFamilySamples(), true); // Complete metrics endpoint $adapter = new \Prometheus\Storage\Redis(); $customRegistry = new CollectorRegistry($adapter); $requestCounter = $customRegistry->getOrRegisterCounter( 'http', 'requests_total', 'Total HTTP requests', ['method', 'path', 'status'] ); $requestCounter->inc(['GET', '/', '200']); $metricFamilySamples = $customRegistry->getMetricFamilySamples(); $result = $renderer->render($metricFamilySamples); echo $result; ``` ### CollectorRegistry::wipeStorage() - Storage Cleanup Removes all previously stored metrics from the underlying storage adapter, useful for testing, development, or resetting metrics. ```php <?php use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; use Prometheus\Storage\InMemory; // Wipe Redis storage Redis::setDefaultOptions(['host' => '127.0.0.1', 'port' => 6379]); $redisRegistry = new CollectorRegistry(new Redis()); // Add metrics $counter = $redisRegistry->getOrRegisterCounter('test', 'counter', 'Test counter'); $counter->incBy(100); // Clear all metrics from Redis $redisRegistry->wipeStorage(); // Wipe in-memory storage between test runs $memoryRegistry = new CollectorRegistry(new InMemory()); $gauge = $memoryRegistry->getOrRegisterGauge('test', 'gauge', 'Test gauge'); $gauge->set(50); // Reset for next test $memoryRegistry->wipeStorage(); // Scheduled cleanup in long-running processes function cleanupOldMetrics(CollectorRegistry $registry): void { static $lastCleanup = 0; $now = time(); // Cleanup every hour if ($now - $lastCleanup > 3600) { $registry->wipeStorage(); $lastCleanup = $now; } } ``` ### Redis::fromExistingConnection() - External Redis Integration Creates a Redis storage adapter from an existing Redis connection, enabling integration with existing Redis infrastructure and connection pooling. ```php <?php use Prometheus\Storage\Redis; use Prometheus\CollectorRegistry; // Use existing Redis connection $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth(['username', 'password']); $redis->select(2); // Create storage adapter from existing connection $adapter = Redis::fromExistingConnection($redis); $registry = new CollectorRegistry($adapter); $counter = $registry->getOrRegisterCounter('app', 'events', 'Application events', ['type']); $counter->inc(['login']); // Connection pooling example class RedisPool { private static $connections = []; public static function getConnection(string $name): \Redis { if (!isset(self::$connections[$name])) { $redis = new \Redis(); $redis->pconnect('127.0.0.1', 6379); self::$connections[$name] = $redis; } return self::$connections[$name]; } } $pooledRedis = RedisPool::getConnection('metrics'); $pooledAdapter = Redis::fromExistingConnection($pooledRedis); $pooledRegistry = new CollectorRegistry($pooledAdapter); ``` ### Storage Adapter Configuration - Multi-Environment Setup Configure different storage adapters based on environment requirements, balancing performance, persistence, and scalability needs. ```php <?php use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; use Prometheus\Storage\APCng; use Prometheus\Storage\APC; use Prometheus\Storage\InMemory; function createRegistryForEnvironment(string $env): CollectorRegistry { switch ($env) { case 'production': // Redis for production: persistent, shared across workers Redis::setDefaultOptions([ 'host' => getenv('REDIS_HOST') ?: '127.0.0.1', 'port' => (int)(getenv('REDIS_PORT') ?: 6379), 'password' => getenv('REDIS_PASSWORD') ?: null, 'timeout' => 0.1, 'read_timeout' => '10', 'persistent_connections' => true, 'database' => 0 ]); return new CollectorRegistry(new Redis()); case 'testing': // In-memory for tests: fast, isolated return new CollectorRegistry(new InMemory()); case 'development': // APCng for development: persistent across requests, single server return new CollectorRegistry(new APCng()); default: return new CollectorRegistry(new InMemory()); } } $registry = createRegistryForEnvironment(getenv('APP_ENV') ?: 'development'); // Web application metrics $httpRequests = $registry->getOrRegisterCounter( 'http', 'requests_total', 'Total HTTP requests', ['method', 'path', 'status'] ); $requestDuration = $registry->getOrRegisterHistogram( 'http', 'request_duration_seconds', 'HTTP request duration', ['method', 'path'] ); // Application logic $method = $_SERVER['REQUEST_METHOD']; $path = $_SERVER['REQUEST_URI']; $startTime = microtime(true); // Handle request http_response_code(200); // Record metrics $duration = microtime(true) - $startTime; $httpRequests->inc([$method, $path, '200']); $requestDuration->observe($duration, [$method, $path]); ``` ### Complete Metrics Endpoint Implementation Full implementation of a /metrics endpoint for Prometheus scraping with proper error handling and metric collection. ```php <?php // metrics.php - Prometheus metrics endpoint require __DIR__ . '/vendor/autoload.php'; use Prometheus\CollectorRegistry; use Prometheus\RenderTextFormat; use Prometheus\Storage\Redis; use Prometheus\Storage\APCng; use Prometheus\Storage\InMemory; try { // Determine storage adapter $adapter = $_GET['adapter'] ?? 'redis'; switch ($adapter) { case 'redis': Redis::setDefaultOptions([ 'host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1', 'port' => (int)($_SERVER['REDIS_PORT'] ?? 6379), 'timeout' => 0.1, 'read_timeout' => '10' ]); $storage = new Redis(); break; case 'apcng': $storage = new APCng(); break; case 'in-memory': $storage = new InMemory(); break; default: throw new \InvalidArgumentException("Unknown adapter: {$adapter}"); } // Create registry and collect metrics $registry = new CollectorRegistry($storage); $renderer = new RenderTextFormat(); // Get all metric families and render $metricFamilySamples = $registry->getMetricFamilySamples(); $result = $renderer->render($metricFamilySamples); // Set proper content type and output header('Content-Type: ' . RenderTextFormat::MIME_TYPE); http_response_code(200); echo $result; } catch (\Exception $e) { http_response_code(500); header('Content-Type: text/plain'); echo "Error collecting metrics: " . $e->getMessage(); error_log("Metrics error: " . $e->getMessage()); } ``` ## Summary Prometheus Client PHP provides a robust solution for application monitoring in PHP environments, addressing the unique challenges of metric collection in stateless PHP architectures. The library's flexible storage adapter system allows developers to choose between Redis for distributed environments, APCu/APCng for single-server deployments, or in-memory storage for CLI scripts and testing. By implementing all four Prometheus metric types (Counter, Gauge, Histogram, Summary) with full label support, the library enables comprehensive multi-dimensional metric collection suitable for complex production systems. The library excels in scenarios requiring distributed metric aggregation across multiple PHP-FPM workers or web servers, real-time monitoring of web application performance metrics, custom business metrics tracking with flexible labeling, and integration with existing Prometheus monitoring infrastructure. Common integration patterns include exposing a dedicated /metrics endpoint for Prometheus scraping, instrumenting application code with strategic metric collection points, using middleware to automatically track HTTP request metrics, and leveraging different storage adapters based on deployment architecture. The library's support for exponential histogram buckets, custom summary quantiles, and metric persistence makes it suitable for both simple monitoring needs and sophisticated observability requirements in production PHP applications.