sitetheory/profiler-storage-bundle
Sitetheory's Profiler Storage Bundle provides configurable storage backends for persisting profiler data in PHP applications. It lets you capture and retrieve profiling traces outside of memory, making it easier to inspect request performance across environments and storage drivers.
This bundle is a drop-in replacement/extension for Symfony's profiler storage layer, letting you send profiler data (_profiler tokens, timelines, request traces) to a backend other than the default filesystem cache directory. The day-to-day value shows up when the request you want to inspect was served by a different PHP process than the one rendering _profiler — e.g. multiple app containers, a load balancer, or a php-fpm pool with a shared cache.
Minimal steps:
Install with a version constraint pinned to your Symfony major, since the last tagged release is from 2019:
composer require sitetheory/profiler-storage-bundle
Check composer why-not sitetheory/profiler-storage-bundle if resolution fails — most likely a symfony/framework-bundle constraint conflict.
Register the bundle using the convention for your Symfony version:
new Sitetheory\ProfilerStorageBundle\ProfilerStorageBundle() to AppKernel::registerBundles().config/bundles.php.Inspect the bundle's DI extension first. Look at DependencyInjection/ and Resources/config/ in vendor/sitetheory/profiler-storage-bundle to find the exact config key (usually something like sitetheory_profiler_storage:) and the DSN format it accepts. Do this before writing config — the README is thin and the extension is the source of truth.
Wire it into the profiler. In config/packages/dev/framework.yaml (or config_dev.yml):
framework:
profiler:
dsn: 'redis://redis:6379/2' # or whatever DSN the bundle documents
First use case to validate: open two browser tabs, hit the app, then load /_profiler from a second request. If tokens survive across requests (and ideally across containers), the storage is working. If you see "Token not found", the profiler is still writing to the filesystem — verify with debug:container profiler.storage.
Shared Redis storage across containers. The canonical workflow: run several app containers behind a proxy, point every container's framework.profiler.dsn at the same Redis instance, and browse /_profiler from any container. This is the pattern that justifies the dependency — the default FileProfilerStorage writes to var/cache/dev/profiler, which is per-container.
Environment-scoped config. Never enable this in production. Put the DSN and any bundle config under config/packages/dev/ and config/packages/test/, not the base config. A misconfigured profiler storage in prod silently accumulates request data (and potentially request payloads) in Redis.
Custom storage via ProfilerStorageInterface. If the bundle's built-in backends don't fit, implement Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface (read, write, purge, find) and alias it to profiler.storage in a compiler pass or service definition. This bundle's config is a convenience wrapper; the underlying contract is stable across Symfony versions and is the extension point to rely on.
Decorator for observability. Wrap the storage service with a decorator that logs write failures and latency:
services:
App\Profiler\LoggingStorage:
decorates: profiler.storage
arguments: ['@App\Profiler\LoggingStorage.inner', '@logger']
This gives you visibility when the backend is slow without touching bundle internals — useful because profiler writes happen on the response path and a slow Redis will add latency to every dev request.
CI / local triage workflow. In integration test runs, enable the profiler and dump tokens to Redis, then inspect from the host with redis-cli or by loading /_profiler against a running dev container. This lets you debug a failing pipeline step without re-running it.
Pair with framework.profiler.collect: false when you only need the storage path (e.g. to seed data) — collecting and storing are independent knobs.
framework.profiler.dsn (which supports HTTP/Redis/etc. in modern versions) and treat this bundle as a stopgap for 2.8–4.x.framework.profiler is disabled unless kernel.debug is true (or you force it). If _profiler returns 404 in your container, the problem is usually APP_DEBUG=0, not the storage bundle.bin/console debug:container profiler.storage --show-arguments.profiler:clear-style command purges by pattern, but if nothing runs it, Redis fills up. Set maxmemory-policy on the Redis database (use a dedicated DB index, not 0) and schedule purges.profiler service reads profiler.storage. If your bundle config doesn't take effect, a later compiler pass or framework.profiler.dsn wins — check debug:container --show-arguments profiler.storage and debug:config framework profiler to see the final DSN.ProfilerStorageInterface, not this bundle's config tree. If you outgrow the bundle, swap in your own storage service without changing application code.bin/console cache:clear in the target environment; stale container definitions are a common cause of "my config change did nothing."How can I help you explore Laravel packages today?