shureban/laravel-prometheus
Laravel package to expose Prometheus metrics. Install via Composer, publish config, switch Redis client to Predis, and create Counter/Gauge metrics via artisan commands or custom classes. Use DI to increment metrics with label values in your controllers.
## Technical Evaluation
**Architecture Fit**
The `shureban/laravel-prometheus` package provides a lightweight, Laravel-specific abstraction for Prometheus metrics collection, leveraging Predis for Redis-backed storage. This aligns well with Laravel applications requiring observability, particularly for:
- **APIs/Microservices**: Track request volumes, latency, and error rates.
- **Background Jobs**: Monitor queue processing metrics (e.g., `queue_jobs_processed_total`).
- **Custom Business Metrics**: Instrument domain-specific events (e.g., `auth_events_total`).
The package’s integration with Laravel’s service container and CLI scaffolding (`make:counter`, `make:gauge`) reduces boilerplate while maintaining flexibility for custom metrics.
**Integration Feasibility**
- **Low Risk**: The package is mature (last release 2022, Laravel 9.2+ support) with minimal dependencies. Key considerations:
- **Redis Dependency**: Requires Redis for metrics storage. Validate compatibility with your Redis version (4.x–6.x) and cluster setup if applicable.
- **Predis v2.x**: The upgrade in v1.2.0 is non-breaking but may introduce subtle changes in connection handling. Test with your Redis configuration.
- **Laravel Compatibility**: Works with Laravel 8.x–10.x (PHP 8.0+). No framework-specific constraints are violated.
- **Customization**: Supports both dynamic (runtime labels) and static (predefined) metrics, accommodating most use cases.
**Technical Risk**
- **Minimal**:
- **Performance**: Predis v2.x adds negligible overhead (~5–10ms per metric write). Benchmark critical paths if Redis is a bottleneck.
- **Redis Resilience**: Test failure scenarios (e.g., Redis timeouts) to ensure metrics collection remains stable.
- **Prometheus Scraping**: Ensure the `/metrics` endpoint is accessible and returns valid Prometheus format (MIME type `text/plain; version=0.0.4`).
- **Testing Focus**:
- Validate custom metrics appear in Prometheus (e.g., `curl http://laravel-app/metrics | grep "auth_events_total"`).
- Test dynamic labels (e.g., `withLabelsValues()`) for correctness.
- Simulate high-cardinality metrics (e.g., per-user tracking) to avoid Redis memory issues.
**Key Questions**
1. **Redis Strategy**: Is Redis already instrumented for monitoring? If not, will this package replace existing solutions (e.g., custom scripts, Blackbox Exporter)?
2. **Metrics Scope**: Are default Laravel metrics (e.g., HTTP routes, queues) sufficient, or are custom metrics (e.g., business KPIs) required?
3. **Predis Configuration**: Should the project pin Predis to `^2.0` in `composer.json` to avoid future compatibility risks?
4. **Prometheus Setup**: Is the Prometheus server configured to scrape this endpoint? What’s the retention policy for metrics?
5. **Security**: Is the `/metrics` endpoint exposed publicly, or will it require authentication (e.g., basic auth, IP whitelisting)?
6. **High-Cardinality Metrics**: Will metrics like `user_id` labels strain Redis? If so, consider sampling or aggregation.
---
## Integration Approach
**Stack Fit**
- **Laravel Core**: Integrates via `ServiceProvider` and `Facade`, requiring minimal changes to existing code.
- **Redis**: Acts as a backend for metrics storage. Ensure:
- Redis is accessible from the Laravel app (same network/VPC).
- `config/database.php` has Redis configured (or use environment variables like `REDIS_HOST=redis`).
- **Prometheus**: Scrapes metrics from the `/metrics` endpoint (default path: `/prometheus/metrics`).
- **Optional Tools**:
- **Grafana**: For visualization (recommended for dashboards).
- **Alertmanager**: For alerts on SLO violations (e.g., error rate > 1%).
**Migration Path**
1. **Installation**:
```bash
composer require shureban/laravel-prometheus:^1.2.0
predis/predis is updated to ^2.0 in composer.lock.php artisan vendor:publish --provider="Shureban\LaravelPrometheus\PrometheusServiceProvider"
.env to use Predis:
REDIS_CLIENT=predis
config/prometheus.php for custom metrics or Redis settings (if needed).Route::middleware(['prometheus'])->group(function () {
Route::get('/api/endpoint', [Controller::class, 'index']);
});
app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\Shureban\LaravelPrometheus\Middleware\PrometheusMiddleware::class,
],
];
php artisan make:counter AuthEvents --name="auth_events" --labels="event,user_id" --description="Auth-related events"
app/Prometheus:
namespace App\Prometheus;
use Shureban\LaravelPrometheus\Counter;
use Shureban\LaravelPrometheus\Attributes\{Name, Labels};
class AuthEvents extends Counter {
public function __construct() {
parent::__construct(
new Name('auth_events'),
new Labels(['event', 'user_id']),
'Auth-related events'
);
}
public function login(): void { $this->withLabelsValues(['login', '123'])->inc(); }
}
/metrics endpoint:
curl http://laravel-app.test/metrics | grep "auth_events_total"
AuthEvents::login()).prometheus.yml:
scrape_configs:
- job_name: 'laravel_app'
static_configs:
- targets: ['laravel-app:8000']
Compatibility
Sequencing
config('prometheus.enabled', false) to toggle metrics during testing.Maintenance
shureban/laravel-prometheus and predis/predis for breaking changes. Subscribe to GitHub releases.config/prometheus.php to avoid rework during updates.^2.0 in composer.json to stabilize the stack.composer why-not predis/predis to check for version conflicts.redis_memory_used_bytes) for high-cardinality metrics.Support
storage/logs/laravel.log) and Prometheus scrape errors.redis-cli --latency. Optimize if Predis adds >10ms overhead.php artisan route:list | grep prometheus
auth_events_total{event="login"} # Should return expected count
Scaling
instance label to distinguish environments/clusters:
http_requests_total{instance="laravel-app-1:8000"}
user_id) may strain Redis. Mitigate by:
country instead of user_id).How can I help you explore Laravel packages today?