perfbase / laravel
A Laravel extension for the Perfbase profiling tool.
Requires
- php: >=7.4 <8.6
- ext-json: *
- ext-zlib: *
- guzzlehttp/guzzle: ^7.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
- perfbase/php-sdk: ^1.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^6|^7|^8|^9|^10|11.x-dev
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^9|^10|^11|^12
README
Perfbase for Laravel
Laravel integration for Perfbase.
This package is a thin adapter over perfbase/php-sdk. It wires Laravel request, console, and queue lifecycles into the SDK and leaves trace transport, submission, and extension handling to the shared SDK.
What it profiles
- HTTP requests when the Perfbase middleware is installed
- Artisan commands through Laravel console events
- Queue jobs through Laravel queue events
- Manual custom spans through the
Perfbasefacade or injected SDK client
Requirements
- PHP
7.4to8.5 - Laravel
8.x,9.x,10.x,11.x,12.x, or13.x ext-jsonext-zlibext-perfbase
Installation
Install the package from Packagist:
composer require perfbase/laravel:^1.0
Install the native Perfbase extension if it is not already available:
bash -c "$(curl -fsSL https://cdn.perfbase.com/install.sh)"
Restart PHP-FPM, Octane workers, Horizon workers, or your web server after installing the extension.
Publish the config file:
php artisan vendor:publish --tag="perfbase-config"
Add the minimum environment variables:
PERFBASE_ENABLED=true PERFBASE_API_KEY=your_api_key_here PERFBASE_SAMPLE_RATE=0.1
HTTP middleware
HTTP profiling is enabled only when the middleware is present.
For Laravel 8 to 10, add it to app/Http/Kernel.php:
protected $middleware = [ // ... \Perfbase\Laravel\Middleware\PerfbaseMiddleware::class, ];
Or attach it to a middleware group:
protected $middlewareGroups = [ 'web' => [ // ... \Perfbase\Laravel\Middleware\PerfbaseMiddleware::class, ], ];
For Laravel 11+, register it in bootstrap/app.php:
use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Middleware; use Perfbase\Laravel\Middleware\PerfbaseMiddleware; return Application::configure(dirname(__DIR__)) ->withMiddleware(function (Middleware $middleware) { $middleware->append(PerfbaseMiddleware::class); }) ->create();
Console and queue profiling do not need middleware. They are wired through the package service provider.
Configuration
Published config lives at config/perfbase.php.
return [ 'enabled' => env('PERFBASE_ENABLED', false), 'debug' => env('PERFBASE_DEBUG', false), 'log_errors' => env('PERFBASE_LOG_ERRORS', true), 'api_key' => env('PERFBASE_API_KEY'), 'sample_rate' => env('PERFBASE_SAMPLE_RATE', 0.1), 'timeout' => env('PERFBASE_TIMEOUT', 5), 'proxy' => env('PERFBASE_PROXY'), 'flags' => env('PERFBASE_FLAGS', \Perfbase\SDK\FeatureFlags::DefaultFlags), 'include' => [ 'http' => ['.*'], 'console' => ['.*'], 'queue' => ['.*'], ], 'exclude' => [ 'http' => [], 'console' => ['queue:work'], 'queue' => [], ], ];
Environment variables
| Variable | Default | Purpose |
|---|---|---|
PERFBASE_ENABLED |
false |
Global on/off switch |
PERFBASE_API_KEY |
null |
Perfbase API key |
PERFBASE_SAMPLE_RATE |
0.1 |
Sampling rate from 0.0 to 1.0 |
PERFBASE_DEBUG |
false |
Re-throw profiling exceptions |
PERFBASE_LOG_ERRORS |
true |
Log profiling failures when debug is off |
PERFBASE_TIMEOUT |
5 |
Trace submission timeout in seconds |
PERFBASE_PROXY |
null |
Optional outbound proxy |
PERFBASE_FLAGS |
FeatureFlags::DefaultFlags |
Perfbase extension feature flags |
Feature flags
use Perfbase\SDK\FeatureFlags; 'flags' => FeatureFlags::DefaultFlags; 'flags' => FeatureFlags::AllFlags; 'flags' => FeatureFlags::TrackCpuTime | FeatureFlags::TrackPdo;
Common flags:
UseCoarseClockTrackCpuTimeTrackMemoryAllocationTrackPdoTrackHttpTrackCachesTrackMongodbTrackElasticsearchTrackQueuesTrackAwsSdkTrackFileOperationsTrackFileCompilationTrackFileDefinitionsTrackExceptions
Include and exclude filters
Filters are split by context: http, console, and queue.
'include' => [ 'http' => ['GET /api/*', 'POST /checkout'], 'console' => ['migrate*', 'app:*'], 'queue' => ['App\\Jobs\\Important*'], ], 'exclude' => [ 'http' => ['GET /health*', '_debugbar/*'], 'console' => ['queue:work', 'horizon:*'], 'queue' => ['App\\Jobs\\NoisyDebugJob'], ],
Supported filter styles:
- Wildcards like
GET /api/* - Regex patterns like
/^POST \/checkout/ - Command patterns like
queue:* - Job class patterns like
App\\Jobs\\* - Controller or action strings matched through Laravel's string matcher
How it behaves
HTTP requests
PerfbaseMiddleware creates an HttpTraceLifecycle for the current request.
Recorded attributes include:
source=httpactionhttp_methodhttp_urlhttp_status_codeuser_ipuser_agentuser_idwhen availableenvironmentapp_versionhostnamephp_version
Console commands
The service provider listens to Laravel console events and creates a ConsoleTraceLifecycle.
Recorded attributes include:
source=consoleactionexit_codeexceptionwhen presentenvironmentapp_versionhostnamephp_version
Queue jobs
The service provider listens to queue worker events and creates a QueueTraceLifecycle.
Recorded attributes include:
source=queueactionqueueconnectionexceptionwhen presentenvironmentapp_versionhostnamephp_version
Manual spans
Use the facade when you want custom spans inside your own application code:
use Perfbase\Laravel\Facades\Perfbase; Perfbase::startTraceSpan('custom-operation', [ 'operation_type' => 'data_processing', 'record_count' => '1000', ]); Perfbase::setAttribute('processing_method', 'batch'); Perfbase::setAttribute('memory_usage', (string) memory_get_usage()); try { processLargeDataset(); Perfbase::setAttribute('status', 'success'); } catch (\Exception $e) { Perfbase::setAttribute('status', 'error'); Perfbase::setAttribute('error_message', $e->getMessage()); throw $e; } finally { Perfbase::stopTraceSpan('custom-operation'); } $result = Perfbase::submitTrace(); if (!$result->isSuccess()) { logger()->warning('Perfbase trace submission failed', [ 'status' => $result->getStatus(), 'message' => $result->getMessage(), 'status_code' => $result->getStatusCode(), ]); }
Note that Perfbase trace attributes are string values. Cast integers and booleans before passing them to setAttribute().
Dependency injection
You can inject the SDK client directly:
use Perfbase\SDK\Perfbase; class DataProcessingService { /** @var Perfbase */ private $perfbase; public function __construct(Perfbase $perfbase) { $this->perfbase = $perfbase; } public function processData(array $data): array { $this->perfbase->startTraceSpan('data-processing', [ 'record_count' => (string) count($data), 'data_type' => 'user_records', ]); try { $result = $this->performProcessing($data); $this->perfbase->setAttribute('processed_count', (string) count($result)); return $result; } finally { $this->perfbase->stopTraceSpan('data-processing'); } } }
User-specific request profiling
If your authenticated user model implements Perfbase\Laravel\Interfaces\ProfiledUser, HTTP request profiling will respect shouldBeProfiled().
use Perfbase\Laravel\Interfaces\ProfiledUser; class User extends Authenticatable implements ProfiledUser { public function shouldBeProfiled(): bool { return $this->isAdmin() || $this->isBetaTester(); } }
If the authenticated user does not implement ProfiledUser, the package falls back to normal request filtering rules.
Facade methods
| Method | Description |
|---|---|
startTraceSpan($name, $attributes = []) |
Start a named span |
stopTraceSpan($name) |
Stop a named span |
setAttribute($key, $value) |
Add a string attribute to the current trace |
setFlags($flags) |
Change extension feature flags |
submitTrace() |
Submit trace data and return a SubmitResult |
getTraceData($spanName = '') |
Get raw trace data |
reset() |
Clear the current trace session |
isExtensionAvailable() |
Check whether the native extension is loaded |
Error handling
The package is designed to fail open in normal operation. When profiling cannot start or trace submission fails, your Laravel request, command, or job should continue running.
Use PERFBASE_DEBUG=true if you want profiling exceptions to surface during local development.
Testing
In application tests, it is often simplest to disable profiling:
<env name="PERFBASE_ENABLED" value="false"/>
You can also mock the facade:
use Perfbase\Laravel\Facades\Perfbase; public function test_something() { Perfbase::shouldReceive('startTraceSpan')->once(); Perfbase::shouldReceive('stopTraceSpan')->once(); // ... }
Troubleshooting
Extension not loaded
php -m | grep perfbase php --ini bash -c "$(curl -fsSL https://cdn.perfbase.com/install.sh)"
High overhead
- Lower
PERFBASE_SAMPLE_RATE - Use
FeatureFlags::UseCoarseClock - Disable feature flags you do not need
- Narrow your
includefilters and expand yourexcludefilters
Documentation
Full documentation is available at perfbase.com/docs.
- Docs: perfbase.com/docs
- Issues: github.com/perfbaseorg/laravel/issues
- Support: support@perfbase.com
License
Apache-2.0. See LICENSE.txt.