appneta/traceview-bundle
AppNeta TraceView Bundle integrates TraceView (Tracy) application performance monitoring into Symfony apps, adding instrumentation and configuration to trace requests, database queries, and external calls for faster debugging and optimization.
The single most important thing to internalize: this package is not the monitoring product, and it is not a Laravel package. It is ~30–60 lines of Symfony2 event-subscriber glue that decorates transactions opened by the native traceview PHP agent (the Oboe-based PECL extension). All real instrumentation lives in the extension; the bundle only adds framework-aware naming so transactions show up as App\Http\Controllers\OrderController::show instead of index.php.
For a Laravel developer, "getting started" means extracting the pattern, not installing the artifact:
php -m | grep traceview. If there is no supported build, stop — no amount of middleware will help.kernel.request, open/name the transaction from the route/controller, subscribe to kernel.response, close it. Port that mental model to middleware.composer require appneta/traceview-bundle. It is a Symfony Bundle registered in AppKernel, requires symfony/framework-bundle 2.x, and will not boot or even resolve inside a Laravel app.$request->route()?->getName() (falling back to the URI pattern, not the raw URI), and closes it in a finally.Service provider + singleton. Bind a thin tracer wrapper in a service provider, but make the binding conditional on extension_loaded('traceview') so the app boots cleanly on machines without the agent. Guard every extension call behind that check, or use a null-object tracer. This keeps local/dev/CI functional and avoids fatals.
Global middleware, try/finally. The core pattern mirrors the bundle's subscriber:
public function handle($request, Closure $next)
{
$this->tracer->start($request);
try {
return $next($request);
} finally {
$this->tracer->setStatus($response->getStatusCode() ?? 500);
$this->tracer->finish();
}
}
The finally matters — the Symfony subscriber gets the same behavior from kernel.exception, but in Laravel a thrown exception skips the response path entirely, so without finally a failed request leaves an open transaction and a broken trace.
Register after session/auth. Place the middleware after StartSession and any authentication middleware so you can tag user_id and tenant from the resolved user, which is the whole point of route-aware naming. Placing it first gives you latency numbers but no attribution.
Exception reporting. Hook bootstrap/app.php's withExceptions (Laravel 11) or Exceptions\Handler::report() to mark the active transaction errored and attach the exception class. This is the Laravel equivalent of the bundle's kernel.exception listener.
Job and command listeners. This is where the bundle gives you nothing — it only hooks the HTTP kernel. Queue workloads need separate JobProcessing/JobProcessed/JobFailed listeners (and a console hook for artisan commands), each opening and closing its own transaction. If you skip this, your async traffic is invisible and your traces are half-true.
Noise and cost control. Exclude /health, /horizon, /telescope, and artisan bootstrapping from tracing, and lean on agent-side sampling. These are your primary levers for both cost (TraceView prices per host/agent) and dashboard signal-to-noise. The bundle offers neither; you build it explicitly.
traceview_set_transaction_name() (via the extension) with the route name or controller action, never the raw URI — otherwise every /orders/12345 becomes a distinct transaction and your aggregates are useless.symfony/* constraints fails at resolve time. Treat the repository as documentation, not a dependency.start/tag/finish interface) so swapping to OpenTelemetry's PHP SDK later is a config change, not a re-instrumentation project. If TraceView is not already a mandated, contracted vendor, invest this same day of work in OpenTelemetry instead and keep the observability decision reversible.How can I help you explore Laravel packages today?