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

Laravel Prometheus Laravel Package

spatie/laravel-prometheus

Export Laravel app metrics to Prometheus via a /prometheus endpoint. Register custom gauges and counters in code, with built-in metrics for queues and Horizon. Includes optional security so your metrics aren’t publicly exposed; pair with Grafana for dashboards.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-prometheus
    

    Publish the config file:

    php artisan vendor:publish --provider="Spatie\Prometheus\PrometheusServiceProvider"
    
  2. Basic Metric Exposure: Add a gauge metric in a service provider's boot() method:

    use Spatie\Prometheus\Facades\Prometheus;
    
    Prometheus::addGauge('app.active_users')
        ->value(fn() => User::where('last_seen_at', '>', now()->subHours(1))->count());
    
  3. Access Metrics: Visit /prometheus endpoint to see metrics in Prometheus format. Configure Prometheus server to scrape this endpoint.

First Use Case: Monitoring API Requests

Track HTTP request counts by status code:

use Spatie\Prometheus\Facades\Prometheus;

Prometheus::addCounter('http_requests_total')
    ->labels(['method', 'status_code'])
    ->increment(fn() => request()->method(), fn() => response()->getStatusCode());

Implementation Patterns

Core Patterns

  1. Metric Types:

    • Gauges: For values that can increase/decrease (e.g., active_users).
      Prometheus::addGauge('memory_usage')
          ->value(fn() => memory_get_usage(true) / 1024 / 1024);
      
    • Counters: For monotonically increasing values (e.g., api_calls).
      Prometheus::addCounter('api_errors')
          ->increment(fn() => request()->wantsJson() && response()->isClientError());
      
    • Histograms: For measuring distributions (e.g., request latency).
      Prometheus::addHistogram('request_duration_seconds')
          ->observe(fn() => request()->getDuration());
      
  2. Conditional Metrics: Use the Conditionable trait for dynamic metrics:

    Prometheus::addGauge('high_traffic_users')
        ->when(fn() => request()->ip() === '192.168.1.1')
        ->value(fn() => User::count());
    
  3. Labels for Context: Add dimensions to metrics:

    Prometheus::addCounter('database_queries')
        ->labels(['connection', 'query_type'])
        ->increment(fn() => DB::connection()->getName(), fn() => 'select');
    

Integration Workflows

  1. Queue Monitoring: Built-in collectors for Laravel queues (including Horizon):

    // Auto-registered via config/prometheus.php
    'collectors' => [
        \Spatie\Prometheus\Collectors\QueueCollector::class,
        \Spatie\Prometheus\Collectors\HorizonCollector::class,
    ],
    
  2. Middleware Integration: Track request metrics in middleware:

    public function handle(Request $request, Closure $next) {
        $start = microtime(true);
        $response = $next($request);
        $duration = microtime(true) - $start;
    
        Prometheus::addHistogram('request_latency_seconds')
            ->observe($duration);
    
        return $response;
    }
    
  3. Event-Based Metrics: Use events to trigger metric updates:

    event(new UserRegistered($user));
    // In an event listener:
    Prometheus::addCounter('users_registered')->increment();
    
  4. Custom Collectors: Extend \Spatie\Prometheus\Collectors\Collector for reusable logic:

    class CacheCollector extends Collector {
        public function collect() {
            return collect([
                'cache_hits' => Cache::stats()['hits'],
                'cache_misses' => Cache::stats()['misses'],
            ]);
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. Metric Naming:

    • Use snake_case for metric names (Prometheus convention).
    • Avoid spaces or special characters.
    • Gotcha: Metrics with / or - may cause issues in some Prometheus setups.
  2. Performance Overhead:

    • Tip: Cache expensive metric calculations (e.g., User::count()) if scraped frequently.
      Prometheus::addGauge('user_count')
          ->value(fn() => Cache::remember('user_count', 60, fn() => User::count()));
      
    • Gotcha: Avoid blocking operations in metric value functions (e.g., long-running queries).
  3. Security:

    • Tip: Protect the /prometheus endpoint with middleware:
      'middleware' => ['auth:sanctum'], // config/prometheus.php
      
    • Gotcha: Unprotected endpoints expose internal metrics to public networks.
  4. Label Cardinality:

    • Tip: Limit label combinations to avoid "label explosion." Example: Avoid high-cardinality labels like user_id.
    • Gotcha: Prometheus struggles with metrics having >100k unique label combinations.
  5. Collector Registration:

    • Tip: Register collectors in boot() of a service provider to ensure they run after dependencies.
    • Gotcha: Collectors relying on Laravel services (e.g., Queue) must be registered after those services are bootstrapped.

Debugging Tips

  1. Verify Metrics:

    • Check the /prometheus endpoint directly in a browser or with curl:
      curl http://localhost:8000/prometheus
      
    • Use promtool to validate metrics:
      promtool check rules your_rules.yml
      
  2. Logging:

    • Enable debug logging in config/prometheus.php:
      'debug' => env('APP_DEBUG', false),
      
    • Gotcha: Debug logs may expose sensitive data if not filtered.
  3. Prometheus Configuration:

    • Tip: Test Prometheus scrape configuration locally:
      scrape_configs:
        - job_name: 'laravel_app'
          static_configs:
            - targets: ['localhost:8000']
      
    • Gotcha: Ensure the scrape interval matches your metric update frequency.

Extension Points

  1. Custom Metric Types: Extend the package by adding new metric types (e.g., Summary):

    // In a custom collector:
    Prometheus::addSummary('request_size_bytes')
        ->observe(fn() => strlen(request()->getContent()));
    
  2. Dynamic Metrics: Use Laravel's service container to bind dynamic metrics:

    $this->app->bind('prometheus.dynamic_metric', function () {
        return Prometheus::addGauge('dynamic_metric')
            ->value(fn() => rand(0, 100));
    });
    
  3. Grafana Dashboards:

  4. Testing:

    • Tip: Mock metrics in tests:
      Prometheus::shouldReceive('addGauge')->andReturnSelf();
      
    • Gotcha: Avoid testing metric values directly; test the logic that populates them.

Configuration Quirks

  1. Middleware Priority:

    • Tip: Set middleware priority in app/Http/Kernel.php to ensure metrics are collected before responses:
      protected $middleware = [
          // ...
          \Spatie\Prometheus\Middleware\PrometheusMiddleware::class,
      ];
      
  2. Environment-Specific Metrics:

    • Tip: Use environment variables to toggle metrics:
      if (env('ENABLE_ANALYTICS', false)) {
          Prometheus::addCounter('user_actions')->increment();
      }
      
  3. Prometheus Client Library:

    • Gotcha: The package uses promphp/prometheus_client_php under the hood. Version conflicts may arise; pin the dependency in composer.json:
      "promphp/prometheus_client_php": "^0.15.0"
      
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai