movemoveapp/laravel-prometheus
Laravel package to collect and expose Prometheus metrics using Redis storage. Friendly fork of shureban/laravel-prometheus with support for predis/predis ^3.0. Includes artisan generators for counter and gauge metrics and publishable configuration.
Installation:
composer require movemoveapp/laravel-prometheus
Update config/app.php to include the service provider:
Shureban\LaravelPrometheus\PrometheusServiceProvider::class,
Publish Config (if customization is needed):
php artisan vendor:publish --provider="Shureban\LaravelPrometheus\PrometheusServiceProvider"
Configure Redis Client (if using Redis):
Update .env:
REDIS_CLIENT=predis
First Metric Creation: Use Artisan to generate a counter metric:
php artisan make:counter AuthEvents --name=auth_events --labels=event --description="Auth-related events"
This creates a class like app/Prometheus/AuthEvents.php.
Expose Metrics Endpoint:
Ensure the web_route in config/prometheus.php is accessible (default: /prometheus/metrics).
Test Metrics:
Access the endpoint (/prometheus/metrics) and verify metrics appear in Prometheus format.
Track User Authentication Events:
php artisan make:counter AuthEvents --name=auth_events --labels=event,status --description="Auth events with status"
use App\Prometheus\AuthEvents;
class LoginController extends Controller {
public function login(AuthEvents $authEvents) {
// Auth logic...
$authEvents->withLabelsValues(['login', 'success'])->inc();
}
}
/prometheus/metrics:
# HELP auth_events Auth events with status
# TYPE auth_events counter
auth_events{event="login",status="success"} 1
CLI Generation: Use Artisan commands to scaffold metrics:
php artisan make:counter UserActions --name=user_actions --labels=action,outcome --dynamic
This generates a dynamic counter with action and outcome labels.
Manual Implementation:
For static metrics, manually create classes in app/Prometheus:
namespace App\Prometheus;
use Shureban\LaravelPrometheus\{Counter, Name, Labels};
class ApiErrors extends Counter {
public function __construct() {
parent::__construct(
new Name('api_errors'),
new Labels(['endpoint', 'http_status']),
'Count of API errors by endpoint and status'
);
}
}
Register the metric in a service provider:
$this->app->bind('apiErrors', function() {
return new ApiErrors();
});
Dependency Injection: Inject metrics into controllers/services:
class OrderService {
public function create(OrderRequest $request, ApiErrors $apiErrors) {
try {
// Logic...
} catch (\Exception $e) {
$apiErrors->withLabelsValues(['/orders', '500'])->inc();
throw $e;
}
}
}
Contextual Labels: Use dynamic labels for runtime context:
$userMetrics->withLabels([
'user_id' => auth()->id(),
'role' => auth()->user()->role
])->inc();
Helper Methods: Encapsulate label logic in metric classes:
class UserMetrics extends Counter {
public function loginFailed() {
$this->withLabelsValues(['event' => 'login', 'status' => 'failed'])->inc();
}
}
Web Route:
Configure web_route in config/prometheus.php (default: /prometheus/metrics).
The package auto-registers a route for text-format rendering.
Manual Rendering: For custom routes or formats:
use Shureban\LaravelPrometheus\RenderTextFormat;
Route::get('/custom-metrics', function() {
$renderer = new RenderTextFormat();
return response($renderer->render(), 200, ['Content-Type' => RenderTextFormat::MIME_TYPE]);
});
Listen to Laravel Events: Instrument events globally:
use Illuminate\Support\Facades\Event;
use App\Prometheus\AuthEvents;
Event::listen('auth.attempted', function($event) {
app(AuthEvents::class)->withLabelsValues(['event' => 'attempt', 'status' => $event->success ? 'success' : 'failed'])->inc();
});
Queue Job Metrics: Track job processing:
class ProcessPaymentJob implements ShouldQueue {
public function handle() {
app('paymentJobs')->withLabelsValues(['job' => 'process_payment', 'status' => 'started'])->inc();
try {
// Job logic...
app('paymentJobs')->withLabelsValues(['job' => 'process_payment', 'status' => 'completed'])->inc();
} catch (\Exception $e) {
app('paymentJobs')->withLabelsValues(['job' => 'process_payment', 'status' => 'failed'])->inc();
throw $e;
}
}
}
/prometheus/metrics endpoint:
scrape_configs:
- job_name: 'laravel_app'
static_configs:
- targets: ['your-laravel-app:8000']
// config/prometheus.php
'web_route' => env('PROMETHEUS_ROUTE', '/prometheus/metrics'),
environment=production).user_id, request_id).$counter = Mockery::mock(AuthEvents::class);
$counter->shouldReceive('withLabelsValues')->with(['login', 'success'])->once()->andReturnSelf();
$counter->shouldReceive('inc')->once();
/prometheus/metrics:
$response = $this->get('/prometheus/metrics');
$response->assertSeeText('# HELP auth_events Auth events with status');
^3.0 is optimized for your Redis cluster.Counter, Gauge, etc.:
namespace App\Prometheus;
use Shureban\LaravelPrometheus\Gauge;
class MemoryUsage extends Gauge {
public function setCurrentUsage(int $bytes) {
$this->set($bytes);
}
}
user_id) can explode cardinality, overwhelming Prometheus.user_segment instead of user_id).le (less-than-or-equal) or ge (greater-than-or-equal) labels for numeric ranges.app_auth_events).--name flag in Artisan commands to enforce consistency.How can I help you explore Laravel packages today?