perfbase / slim
Slim integration for the Perfbase profiling tool.
Requires
- php: >=7.4 <8.6
- perfbase/php-sdk: ^1.0
- psr/http-message: ^1.0 || ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- slim/slim: ^3.0 || ^4.0
Requires (Dev)
- guzzlehttp/psr7: ^2.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^9
README
Perfbase for Slim
Slim framework integration for Perfbase.
perfbase/slim is the Slim framework adapter for Perfbase. It is a thin package on top of perfbase/php-sdk that adds:
- HTTP request profiling for Slim 3
- HTTP request profiling for Slim 4
- Manual CLI profiling for non-HTTP entrypoints
- Per-context include and exclude filters for
httpandcli - Low-cardinality span naming based on route patterns when available
- Fail-open behavior so profiling issues do not break the host application
Requirements
- PHP
>=7.4 <8.6 perfbase/php-sdk ^1.0slim/slim ^3.0 || ^4.0- The native Perfbase PHP extension
Installation
Install the package:
composer require perfbase/slim:^1.0
Install the Perfbase PHP extension if it is not already available:
bash -c "$(curl -fsSL https://cdn.perfbase.com/install.sh)"
What This Package Does
This package does not replace Slim’s container, router, or error handling. It adds middleware and a small CLI helper that profile work with the Perfbase SDK.
Supported public entrypoints:
Perfbase\Slim\Slim3\PerfbaseMiddlewarePerfbase\Slim\Slim4\PerfbaseMiddlewarePerfbase\Slim\Cli\CliTraceRunner
v1 is intentionally scoped to HTTP requests and manual CLI profiling. It does not include queue, worker, or async runtime integrations.
Quick Start
Slim 4
use Perfbase\Slim\Slim4\PerfbaseMiddleware; $config = [ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', ]; $app->add(new PerfbaseMiddleware($config));
Slim 3
use Perfbase\Slim\Slim3\PerfbaseMiddleware; $config = [ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', ]; $app->add(new PerfbaseMiddleware($config));
CLI
use Perfbase\Slim\Cli\CliTraceRunner; $config = [ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', ]; $runner = new CliTraceRunner($config); $exitCode = $runner->profile('cache:warm', function (): int { return 0; });
Configuration
You can pass either:
- a plain PHP array
- a normalized
Perfbase\Slim\Support\PerfbaseConfiginstance
Example:
use Perfbase\SDK\FeatureFlags; $config = [ 'enabled' => true, 'debug' => false, 'log_errors' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'api_url' => 'https://ingress.perfbase.cloud', 'sample_rate' => 0.1, 'timeout' => 10, 'proxy' => null, 'flags' => FeatureFlags::DefaultFlags, 'environment' => 'production', 'app_version' => '1.0.0', 'include' => [ 'http' => ['*'], 'cli' => ['*'], ], 'exclude' => [ 'http' => [], 'cli' => [], ], 'user_id_resolver' => function ($request): ?string { $user = $request->getAttribute('user'); if (is_object($user) && method_exists($user, 'getId')) { return (string) $user->getId(); } return null; }, ];
Config Reference
| Key | Type | Default | Notes |
|---|---|---|---|
enabled |
bool |
false |
Must be true and paired with a non-empty api_key to profile |
debug |
bool |
false |
Rethrows internal profiling errors instead of failing open |
log_errors |
bool |
true |
Logs profiling errors with error_log() when not in debug mode |
api_key |
string |
'' |
Required when profiling is enabled |
api_url |
string |
https://ingress.perfbase.cloud |
Receiver base URL |
sample_rate |
float |
0.1 |
Between 0.0 and 1.0 |
timeout |
int |
10 |
Request timeout in seconds |
proxy |
`string | null` | null |
flags |
int |
FeatureFlags::DefaultFlags |
SDK feature flags passed to the extension |
environment |
string |
production |
Added to each trace |
app_version |
string |
'' |
Added to each trace |
include.http |
string[] |
['*'] |
HTTP allowlist patterns |
exclude.http |
string[] |
[] |
HTTP denylist patterns |
include.cli |
string[] |
['*'] |
CLI allowlist patterns |
exclude.cli |
string[] |
[] |
CLI denylist patterns |
user_id_resolver |
`callable | null` | null |
Validation rules:
api_urlmust be a valid URLsample_ratemust be between0.0and1.0timeoutmust be at least1flagsmust be a non-negative integeruser_id_resolvermust be callable ornull
HTTP Profiling
Both middleware implementations share the same lifecycle behavior:
- profiling starts before the downstream handler runs
- response status is captured on success
- exception messages are captured on failure
- cleanup and trace submission happen in
finally
Recorded HTTP attributes include:
source=httpactionenvironmentapp_versionhostnamephp_versionhttp_methodhttp_urlhttp_status_codeuser_ipuser_agentuser_idwhenuser_id_resolverreturns one
Span Naming
HTTP span naming is intentionally low-cardinality:
- preferred:
METHOD /route/{pattern} - fallback:
METHOD /raw/path
Examples:
http.GET./articles/{id}http.POST./sessionshttp.GET./health
The action attribute follows the same rule without the http. prefix:
GET /articles/{id}POST /sessions
URL Handling
http_url keeps the scheme, authority, and path, but strips the query string.
Example:
- request URL:
https://example.com/articles/42?token=secret - recorded
http_url:https://example.com/articles/42
This is intentional so tokens and other sensitive query parameters are not emitted in traces.
User Metadata
The middleware resolves:
user_ipfromCF-Connecting-IP, thenX-Forwarded-For, thenREMOTE_ADDRuser_agentfrom the PSR-7 request headers, with server param fallbackuser_idonly when you provideuser_id_resolver
If user_id_resolver returns:
- a scalar value, it is cast to string
- a stringable object, it is cast to string
null, nouser_idattribute is set
Filters
Filters are evaluated separately for http and cli.
Rules:
- profiling only runs when at least one include pattern matches
- any exclude match blocks profiling
- exclude patterns take precedence over include patterns
Supported pattern styles:
- match all:
*or.* - regex:
/^GET \\/admin/ - glob:
GET /admin/*
HTTP Filter Components
HTTP filters are matched against these normalized components:
METHOD /path/path- route pattern, when available
METHOD /route-pattern, when available- route name, when available
Examples:
'include' => [ 'http' => [ '*', 'GET /health', 'GET /articles/{id}', 'articles.show', '/^POST \\/admin\\//', ], ], 'exclude' => [ 'http' => [ 'GET /internal/*', ], ],
CLI Filter Components
CLI filters are matched against:
- the raw command name
- the normalized action form
cli.{command}
Examples:
'include' => [ 'cli' => [ 'cache:*', '/^queue:(work|listen)$/', ], ], 'exclude' => [ 'cli' => [ 'queue:listen', ], ],
Middleware Order
Route-pattern naming depends on route metadata already being attached to the request when Perfbase runs.
If route metadata is available, the middleware uses the route pattern and route name for naming and filtering. If it is not available yet, the middleware falls back to the raw request path.
Operationally, that means:
- if you want route-pattern naming, register Perfbase in an order where routing has already populated request attributes
- if you cannot guarantee that, profiling still works, but naming falls back to the path
Slim 4 Setup Example
use Perfbase\Slim\Slim4\PerfbaseMiddleware; use Slim\Factory\AppFactory; $app = AppFactory::create(); $config = [ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', 'sample_rate' => 0.2, ]; $app->add(new PerfbaseMiddleware($config)); $app->get('/health', function ($request, $response) { $response->getBody()->write('ok'); return $response; });
Slim 3 Setup Example
use Perfbase\Slim\Slim3\PerfbaseMiddleware; use Slim\App; $app = new App(); $config = [ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', 'sample_rate' => 0.2, ]; $app->add(new PerfbaseMiddleware($config)); $app->get('/health', function ($request, $response) { return $response->write('ok'); });
CLI Usage
CliTraceRunner is intended for application-owned scripts and commands. It does not integrate with a specific console framework in v1.
Example with extra attributes:
use Perfbase\Slim\Cli\CliTraceRunner; $runner = new CliTraceRunner([ 'enabled' => true, 'api_key' => getenv('PERFBASE_API_KEY'), 'environment' => 'production', 'app_version' => '1.0.0', ]); $exitCode = $runner->profile( 'cache:warm', function (): int { return 0; }, [ 'cache_store' => 'redis', 'trigger' => 'deploy', ] );
CLI behavior:
source=cliaction=cli.{command}- integer callback returns are recorded as
exit_code - thrown exceptions are recorded as
exceptionand rethrown - cleanup still happens in
finally
Runtime Behavior
The package is designed to fail open in production.
When debug=false:
- SDK initialization errors are swallowed
- profiling submission failures do not break the request
- middleware and CLI callbacks continue to run normally
When debug=true:
- internal profiling errors are rethrown so integration issues are obvious during development
Production Notes
- Keep
sample_ratebelow1.0unless you explicitly want full capture. - Use route-pattern filters instead of raw-path filters where possible to keep rules stable.
- Do not rely on query strings for naming or filtering; they are intentionally excluded.
- Provide
user_id_resolveronly if your application already has a stable notion of user identity. - If you use reverse proxies or CDNs, ensure client IP headers are trustworthy in your environment before relying on
user_ip.
Troubleshooting
No traces being sent:
- confirm
enabledistrue - confirm
api_keyis present and non-empty - confirm the native Perfbase extension is installed and loaded
- confirm your include and exclude filters allow the current request or command
- confirm
sample_rateis not0
Unexpected path-based names instead of route patterns:
- adjust middleware order so route metadata is available before Perfbase executes
Unexpected missing user_id:
- confirm
user_id_resolverreturns a scalar or stringable object - confirm it does not throw
Development
composer install
composer run test
composer run phpstan
composer run lint
Documentation
Full documentation is available at perfbase.com/docs.
- Docs: perfbase.com/docs
- Issues: github.com/perfbaseorg/slim/issues
- Support: support@perfbase.com
License
Apache-2.0. See LICENSE.txt.