Skip to main content
Integrations

Symfony Integration

The Perfbase Symfony bundle provides automatic profiling for HTTP requests and console commands via kernel event subscribers. Supports Symfony 5.4, 6.x, and 7.x.

Installation

Install the Perfbase PHP extension first. This is what does the actual profiling:

bash -c "$(curl -fsSL https://cdn.perfbase.com/install.sh)"

Then install the Symfony bundle:

composer require perfbase/symfony

If using Symfony Flex, the bundle is registered automatically and a default config file is created at config/packages/perfbase.yaml.

Without Flex, register the bundle manually:

// config/bundles.php
return [
    // ...
    Perfbase\Symfony\PerfbaseBundle::class => ['all' => true],
];

Configuration

The Flex recipe creates a starter config. Update it with your API key and enable profiling:

# config/packages/perfbase.yaml
perfbase:
    enabled: true
    api_key: '%env(PERFBASE_API_KEY)%'
    sample_rate: 0.1

All options

KeyTypeDefaultDescription
enabledboolfalseMaster on/off switch. When true, api_key is required.
api_keystring''Your project API key. Required when enabled.
api_urlstringhttps://ingress.perfbase.cloudIngestion endpoint. Must be a valid URL.
sample_ratefloat0.1Fraction of requests to profile (0.0–1.0). 0.1 = 10%.
timeoutint10HTTP timeout in seconds for trace submission.
proxystring|nullnullOptional proxy URL (http, https, socks5, socks5h).
flagsintDefaultFlagsSDK feature flags bitmask. See Feature flags.
app_versionstring''Your application version, recorded on every trace.
debugboolfalseWhen true, profiling errors are thrown instead of silently logged.
log_errorsbooltrueLog profiling errors via error_log().

Include and exclude filters

Control which routes and commands are profiled:

perfbase:
    include:
        http: ['*']               # All routes (default)
        console: ['*']            # All commands (default)
    exclude:
        http: ['/health', '/_profiler/*']
        console: ['cache:clear']

Pattern types

  • Glob patterns: api/*, /admin/users/* (matched via fnmatch())
  • Regex patterns: /^GET \/api\// (delimited by forward slashes)
  • Catch-all: * or .* matches everything

What’s matched against HTTP filters

Patterns are tested against multiple representations of the request, so you can filter by any of:

  • Request path: /api/users/42
  • Method + path: GET /api/users/42
  • Route template: /api/users/{id}
  • Method + route template: GET /api/users/{id}
  • Route name: app_user_show
  • Controller: App\Controller\UserController::show

HTTP profiling

HTTP requests are profiled automatically via a kernel event subscriber, with no middleware to register. The subscriber hooks into four kernel events:

  1. kernel.request: creates a profiling lifecycle and starts the trace span.
  2. kernel.response: records the HTTP status code.
  3. kernel.exception: records the exception message, and the status code for HTTP exceptions.
  4. kernel.terminate: stops the span and submits the trace. Runs after the response is sent, so submission never delays the response.

Sub-requests are automatically skipped. Only the main request is profiled.

Each request gets a span named http.{METHOD}.{path} using the route template when available (e.g., http.GET./api/users/{id} rather than http.GET./api/users/42).

Automatic attributes

AttributeSource
hostnamegethostname()
environmentkernel.environment
app_versionConfig value
php_versionPHP version
sourcehttp
actione.g., GET /api/users/{id}
http_methodRequest method
http_urlScheme + host + path (no query string)
http_status_codeResponse status code
user_ipClient IP address
user_agentUser agent string
user_idFrom Security token storage, if available

Console command profiling

Artisan commands are profiled automatically via console event listeners. The subscriber handles ConsoleEvents::COMMAND, ConsoleEvents::ERROR, and ConsoleEvents::TERMINATE.

Each command gets a span named console.{command} (e.g., console.app:import-data). The exit code and any exceptions are recorded as attributes.

Use the exclude filter to skip noisy or long-running commands:

perfbase:
    exclude:
        console: ['messenger:consume', 'cache:*', 'server:*']

Messenger profiling

Symfony Messenger worker profiling is not yet supported. Individual messages dispatched during an HTTP request or console command are captured as part of that request’s trace.

Sample rate

The sample rate controls what fraction of requests are profiled:

perfbase:
    sample_rate: 1.0    # Profile everything (development)
    sample_rate: 0.1    # 10% of requests (production)
    sample_rate: 0.01   # 1% of requests (high-traffic)

When a request isn’t sampled, no profiling overhead is incurred.

Error handling

Profiling never crashes your application. The bundle uses a fail-open error handling strategy:

  • debug: true: profiling errors are thrown as exceptions. Use this during development to catch configuration issues.
  • debug: false (default): errors are caught silently. If log_errors: true (default), they are logged via error_log().

Every event handler is wrapped in try/catch, so a profiling bug can never disrupt your application.

Using the SDK directly

For manual profiling beyond what the automatic subscribers capture, inject the SDK client:

use Perfbase\SDK\Perfbase;

class ImportService
{
    public function __construct(private Perfbase $perfbase) {}

    public function run(): void
    {
        $this->perfbase->startTraceSpan('import-products');
        // ... do work ...
        $this->perfbase->stopTraceSpan('import-products');
        $this->perfbase->submitTrace();
    }
}

The bundle registers Perfbase\SDK\Perfbase as a singleton service, so it can be autowired in any service. See the PHP SDK docs for the full API reference.