Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Prometheus Client Php Laravel Package

promphp/prometheus_client_php

Prometheus client library for PHP with counters, gauges, histograms, and summaries. Supports Redis, Predis, APCu/APCng, or in-memory storage for metric aggregation across workers, with simple APIs to register, update, and expose metrics for scraping.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require promphp/prometheus_client_php
    
  2. Basic metric collection (e.g., in routes/web.php or a controller):

    use Prometheus\CollectorRegistry;
    use Prometheus\RenderTextFormat;
    
    $registry = CollectorRegistry::getDefault();
    $counter = $registry->getOrRegisterCounter('app', 'requests_total', 'Total HTTP requests', ['method']);
    $counter->inc(['GET']); // Increment counter with label 'method=GET'
    
  3. Expose metrics endpoint (e.g., /metrics):

    Route::get('/metrics', function () {
        $registry = CollectorRegistry::getDefault();
        $renderer = new RenderTextFormat();
        header('Content-type: ' . RenderTextFormat::MIME_TYPE);
        return $renderer->render($registry->getMetricFamilySamples());
    });
    

First Use Case: HTTP Request Tracking

Track HTTP requests with labels for method, status, and route:

$requestCounter = $registry->getOrRegisterCounter(
    'http',
    'requests_total',
    'Total HTTP requests',
    ['method', 'status', 'route']
);
$requestCounter->inc([
    'method' => request()->method(),
    'status' => response()->getStatusCode(),
    'route' => request()->path()
]);

Implementation Patterns

1. Metric Types and Workflows

Metric Type Use Case Laravel Integration Example
Counter Monotonically increasing values Track API calls, errors, or events.
Gauge Current value (can increase/decrease) Track queue size, memory usage, or active users.
Histogram Distribution of values Measure request latency or response sizes.
Summary Quantiles + distribution Track request durations with quantiles.

Example: Request Latency Histogram

$latencyHistogram = $registry->getOrRegisterHistogram(
    'http',
    'request_latency_seconds',
    'HTTP request latency in seconds',
    ['method', 'route'],
    Histogram::exponentialBuckets(0.001, 2, 10) // Buckets: 0.001, 0.002, 0.004, etc.
);

// In middleware or controller:
$start = microtime(true);
$response = $kernel->handle($request);
$latency = microtime(true) - $start;
$latencyHistogram->observe($latency, [
    'method' => $request->method(),
    'route'  => $request->path()
]);

2. Storage Adapters

Choose an adapter based on your environment:

  • Redis/Predis: Best for distributed systems (e.g., Laravel Forge/Vagrant, Kubernetes).
    $registry = new CollectorRegistry(new \Prometheus\Storage\Redis());
    
  • APCu/APCng: Lightweight, shared-memory (single server).
    $registry = new CollectorRegistry(new \Prometheus\Storage\APCng());
    
  • InMemory: Ephemeral (e.g., CLI scripts, tests).
    $registry = new CollectorRegistry(new \Prometheus\Storage\InMemory());
    
  • PDO: Persistent storage (e.g., MySQL/PostgreSQL for long-term metrics).
    $registry = new CollectorRegistry(new \PDO('mysql:host=localhost;dbname=prometheus'));
    

Redis Configuration (Laravel .env)

PROMETHEUS_REDIS_HOST=127.0.0.1
PROMETHEUS_REDIS_PORT=6379
PROMETHEUS_REDIS_PASSWORD=
\Prometheus\Storage\Redis::setDefaultOptions([
    'host'     => env('PROMETHEUS_REDIS_HOST'),
    'port'     => env('PROMETHEUS_REDIS_PORT'),
    'password' => env('PROMETHEUS_REDIS_PASSWORD'),
]);

3. Laravel-Specific Patterns

Service Provider Integration

Register the registry in AppServiceProvider:

public function register()
{
    $this->app->singleton('prometheus.registry', function () {
        return new CollectorRegistry(
            new \Prometheus\Storage\Redis()
        );
    });
}

Middleware for Automatic Metrics

public function handle($request, Closure $next)
{
    $registry = app('prometheus.registry');
    $start = microtime(true);

    $response = $next($request);
    $latency = microtime(true) - $start;

    $registry->getOrRegisterCounter('http', 'requests_total')->inc();
    $registry->getOrRegisterHistogram(
        'http',
        'request_latency_seconds'
    )->observe($latency);

    return $response;
}

Queue Job Metrics

public function handle()
{
    $registry = app('prometheus.registry');
    $jobGauge = $registry->getOrRegisterGauge(
        'queue',
        'jobs_active',
        'Number of active jobs'
    );
    $jobGauge->inc();

    try {
        // Job logic
    } finally {
        $jobGauge->dec();
    }
}

4. Custom Metrics and Labels

Dynamic Labels (e.g., User ID)

$userId = auth()->id();
$registry->getOrRegisterCounter(
    'auth',
    'login_attempts_total',
    'Total login attempts',
    ['user_id', 'result']
)->inc(['user_id' => $userId, 'result' => 'success']);

Conditional Metrics (e.g., Errors)

try {
    // Risky operation
} catch (\Exception $e) {
    $registry->getOrRegisterCounter(
        'errors',
        'exceptions_total',
        'Total exceptions',
        ['type', 'message']
    )->inc([
        'type'   => get_class($e),
        'message' => $e->getMessage()
    ]);
}

5. Rendering and Scraping

Custom Renderer (e.g., JSON for Grafana)

use Prometheus\Render\JsonFormat;

Route::get('/metrics/json', function () {
    $renderer = new JsonFormat();
    return response()->json($renderer->render(
        app('prometheus.registry')->getMetricFamilySamples()
    ));
});

Prometheus Scrape Configuration

# prometheus.yml
scrape_configs:
  - job_name: 'laravel_app'
    static_configs:
      - targets: ['laravel-app:8000']  # Docker service name or IP

Gotchas and Tips

1. Adapter-Specific Pitfalls

Adapter Gotcha Solution
Redis Connection timeouts Use persistent_connections: true in config.
Redis evictions Monitor memory usage; adjust maxmemory-policy.
APCu Shared-memory limits Avoid large metrics; use Redis for distributed setups.
PDO Slow queries Index tables properly (e.g., metric_name).
InMemory Data loss on restart Only for testing/CLI scripts.

Redis Connection Tips

  • Connection Pooling: Enable persistent_connections to avoid overhead:
    \Prometheus\Storage\Redis::setDefaultOptions([
        'persistent_connections' => true,
    ]);
    
  • Prefix Conflicts: Avoid mixing Redis and Predis with different prefixes in the same app.

2. Label Value Quirks

  • Non-String Labels: All label values must be strings. Convert numeric/boolean values:
    $counter->inc(['user_id' => (string) $userId]);
    
  • Label Keys: Use underscores (_) instead of spaces/camelCase for Prometheus compatibility:
    // Good:
    $counter->inc(['http_method' => 'GET']);
    // Bad (Prometheus will escape):
    $counter->inc(['http-method' => 'GET']);
    

3. Performance Considerations

  • Histogram Buckets: Default buckets may not suit your data. Use exponentialBuckets() for skewed distributions:
    Histogram::exponentialBuckets(0.001, 2, 10); // 0.001, 0.002, 0.004, ..., 1.024
    
  • APCu Memory: APCu can bloat memory with many metrics. Use Redis for production.
  • Batch Writes: For high-throughput apps, batch metric updates (e.g., in a queue worker).

4. Debugging and Logging

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php
trappistes/laravel-custom-fields
splash/sonata-admin
splash/metadata