promphp/prometheus_client_php

repository·main·Indexed 19 days ago

https://github.com/promphp/prometheus_client_php

A Prometheus client library for PHP that enables application instrumentation. It supports various storage adapters, including Redis, Predis, APCu (APC and APCng), and PDO, to aggregate metrics across stateless PHP processes. The library provides support for Counters, Gauges, Histograms, and Summaries via the CollectorRegistry.

Tokens
10.1K
Snippets
40
Records
51
Agent score
68%

What's inside prometheus_client_php

  1. Configure Histogram buckets

    main

    When creating a Histogram, you can provide a custom array of buckets. If you pass an empty array, default buckets are used. To generate exponential/geometric buckets, use the Histogram::exponentialBuckets helper.

    Example: Histogram::exponentialBuckets(0.05, 1.5, 10) creates 10 buckets starting at 0.05, where each bucket is 1.5x larger than the previous one.

    // Example of generating exponential buckets
    // Note: This is a conceptual usage of the helper method
    Histogram::exponentialBuckets(0.05, 1.5, 10);
  2. Compare APC vs APCng performance

    main

    The APCng engine is designed to avoid the $O(n)$ complexity of APCUIterator() scans that plague the original APC engine. While APCng might be slightly slower when creating new metrics, it is orders of magnitude faster during the collect() phase (when Prometheus scrapes the server) when the APCu cache is large.

    Key Performance Characteristics:

    • APC: Performance degrades significantly as the number of keys in APCu increases because it requires repeated scans of the entire keyspace.
    • APCng: Uses a "metadata cache" to avoid full scans. It is optimized for scenarios with 10,000+ keys and high metric counts.
  3. How the Prometheus client works

    main

    Since PHP worker processes typically do not share state, this library uses storage adapters to perform client-side aggregation. You can choose from several adapters depending on your environment and persistence requirements:

    • Redis: Recommended for production. Requires a separate Redis instance. Best for sharing metrics across multiple PHP workers.
    • Predis: A PHP implementation of the Redis protocol (requires predis/predis).
    • APC / APCng: Uses the APCU extension. Good for shared memory without a separate binary.
    • InMemory: Suitable for long-running scripts or cron jobs where metrics do not need to persist between different requests.
    • PDO: Uses a database connection (e.g., MySQL, SQLite) for storage.

    Note: If using Redis or Predis, setPrefix() shares the same prefix. You cannot use both adapters with different prefixes in the same application.

  4. Run engine performance tests

    main

    To quantify the performance impact of changes to the APC or APCng code, you can run the performance test suite using Docker and PHPUnit. Note that these tests are not part of the default unit test run because they are time-consuming.

    docker-compose run phpunit vendor/bin/phpunit tests/Test --group Performance
  5. Expose metrics via HTTP

    main

    To allow Prometheus to scrape your metrics, use the RenderTextFormat class to render the registry's samples and serve them with the correct MIME type.

    $registry = \Prometheus\CollectorRegistry::getDefault();
    
    $renderer = new RenderTextFormat();
    $result = $renderer->render($registry->getMetricFamilySamples());
    
    header('Content-type: ' . RenderTextFormat::MIME_TYPE);
    echo $result;
  6. Use the APC or APCng storage engines

    main

    You can use either the APC or APCng storage engine when initializing a CollectorRegistry.

    • APC: The original engine. Suitable for smaller APCu caches.
    • APCng: A redesigned engine optimized for high-performance servers with large APCu caches (millions of entries) or high request volumes (hundreds to thousands of requests per second). It is significantly faster at collecting metrics when the APCu cache contains 10,000+ keys.

    Recommendation: If your APCu cache contains more than 1,000 keys, consider using the APCng engine.

    $registry = new CollectorRegistry(new APCng());
    // or...
    $registry = new CollectorRegistry(new APC());
    
    // then register and use metrics
    $counter = $registry->registerCounter('test', 'some_counter', 'it increases', ['type']);
    $counter->incBy(3, ['blue']);
    
    // render for Prometheus
    $renderer = new RenderTextFormat();
    $result = $renderer->render($registry->getMetricFamilySamples());
  7. Use the CollectorRegistry to manage metrics

    main

    The CollectorRegistry is the central entry point for managing Prometheus metrics in your application. It is responsible for registering different types of metrics (Gauges, Counters, Histograms, and Summaries) and coordinating with a storage adapter to persist them. You can use a singleton-style default registry or instantiate your own with a specific Adapter (e.g., Redis).

    use Prometheus\CollectorRegistry;
    use Prometheus\Storage\Redis;
    
    // Option 1: Use the default singleton registry (uses Redis by default)
    $registry = CollectorRegistry::getDefault();
    
    // Option 2: Create a custom registry with a specific storage adapter
    $adapter = new Redis();
    $registry = new CollectorRegistry($adapter);
  8. Use the InMemory storage adapter

    main

    The Prometheus\Storage\InMemory class is an implementation of the Adapter interface that stores metrics in the current PHP process's memory. This is useful for short-lived scripts or environments where a persistent storage backend like Redis is unavailable.

    Note that because metrics are stored in memory, they will be lost once the PHP process terminates. This adapter is suitable for single-request monitoring or environments where the process persists across multiple metric updates.

  9. Initialize the APCng storage adapter

    main

    The Prometheus\Storage\APCng class is a storage adapter that uses the APCu extension to persist Prometheus metrics. It requires the apcu extension to be installed and enabled on your PHP environment.

    When instantiating, you can optionally provide a custom prefix for the APCu keys and specify decimal precision for storing floating-point numbers as integers (to ensure atomic operations via apcu_inc/apcu_dec).

    Parameters:

    • $prometheusPrefix (string): A prefix for all APCu keys. Defaults to prom.
    • $decimalPrecision (int): The number of decimal places to preserve. Must be between 0 and 6. Defaults to 3.
    use Prometheus\Storage\APCng;
    
    // Default: prefix 'prom', precision 3
    $adapter = new APCng();
    
    // Custom: prefix 'myapp', precision 2
    $adapter = new APCng('myapp', 2);
  10. Configure the development environment with Docker Compose

    main

    The project provides a docker-compose.yml file to orchestrate a development environment consisting of Nginx, PHP-FPM, Redis, and a PHPUnit service.

    To run the environment, ensure you have Docker and Docker Compose installed, then execute:

    docker-compose up

    Service Details

    • nginx: Serves web traffic on port 8080 and links to php-fpm.
    • php-fpm: The PHP processing engine. It mounts the current directory to /var/www/html and uses the REDIS_HOST environment variable to locate the Redis instance.
    • redis: A standard Redis image running on port 6379.
    • phpunit: A dedicated service for running tests, built from the php-fpm/ directory, with access to both redis and nginx.
  11. Initialize the RedisNg storage adapter

    main

    The RedisNg class is a storage adapter used for Redis-based metric aggregation. You can initialize it in two ways:

    1. Via configuration array: Pass an array of options to the constructor.
    2. From an existing connection: Use the fromExistingConnection static method if you have already instantiated a edis object.

    Configuration Options

    When using the constructor, you can provide the following options:

    • host: Redis server hostname (default: 127.0.0.1)
    • port: Redis server port (default: 6379)
    • timeout: Connection timeout in seconds (default: 0.1)
    • read_timeout: Redis read timeout (default: '10')
    • persistent_connections: Boolean to enable/disable persistent connections (default: false)
    • password: Redis authentication password
    • user: Redis username
    • database: Redis database index
    // Option 1: Using configuration
    $adapter = new //Prometheus/Storage/RedisNg(['host' => '192.168.1.10', 'port' => 6379]);
    
    // Option 2: Using an existing <Redis> connection
    $redis = new \Redis();
    $redis->connect('127.0.0.1');
    $adapter = \Prometheus\Storage\RedisNg::fromExistingConnection($redis);