troopers/metrics-bundle
A PHP metrics bundle for collecting, aggregating, and exposing application metrics. Plug it into your app to track performance and business indicators, then serve them to dashboards or monitoring tools through a simple, configurable setup.
This bundle is a thin, under-documented Symfony integration for recording and reading application metrics. With 10 stars, no dependents, and a last release in January 2017, there are no tutorials or Stack Overflow answers to lean on — the bundle source is the specification. Start there, not with the README.
Confirm compatibility before installing. The 2017 release targets Symfony 2.7/3.x and PHP 5.6–7.1. On a modern stack you will almost certainly need to fork it or vendor it in. Pin to a commit SHA rather than a branch:
composer require troopers/metrics-bundle:dev-master#<sha>
If constraints collide with your Symfony version, fork the repo and relax the composer.json constraints yourself.
Register the bundle. Legacy: new Troopers\MetricsBundle\TroopersMetricsBundle() in AppKernel. Symfony 4+: add it to config/bundles.php.
Read these three files first, in order:
DependencyInjection/Configuration.php — the complete, authoritative list of config keys (storage driver, entity class, collection toggles, etc.).Resources/config/services.yml (and any services/*.yml it imports) — the real service IDs. Old bundles rarely expose clean aliases, so find the manager service with bin/console debug:container | grep -i metric.Tests/ directory — the only working usage examples that exist.Your first use case: instrument one thing. Inject the metrics manager into a single service or controller and record a counter or timing around an operation:
$metrics = $this->get('troopers_metrics.manager'); // verify exact ID first
$metrics->increment('user.signup');
Then confirm the value actually lands where you expect (DB table, log, or backend) before instrumenting anything else.
Verify your configuration resolves. Run bin/console debug:config troopers_metrics (if the bundle exposes it) — this is faster than guessing which storage backend the defaults selected.
Wrap it behind your own interface immediately. Because the package is unmaintained, the single most valuable pattern is a one-method-deep abstraction:
final class AppMetrics
{
public function __construct(private MetricsManager $inner) {}
public function increment(string $key, int $by = 1): void
{
$this->inner->increment($key, $by);
}
public function timing(string $key, callable $fn): mixed
{
$start = microtime(true);
try {
return $fn();
} finally {
$this->inner->timing($key, microtime(true) - $start);
}
}
}
Swapping to StatsD, Prometheus, or a home-grown implementation later becomes a one-file change.
Instrument at boundaries, not mid-logic. The natural collection points are:
kernel.request/kernel.terminate listener for request duration and status-code counters.postFlush/postPersist subscriber for query and write counts.ConsoleEvents::COMMAND/TERMINATE listener for job duration.Tag-driven collection. If the bundle offers collector tags, prefer declaring a service with the collector tag over hard-wiring every call site — it lets you add instrumentation without touching business code.
Batch writes when backed by Doctrine. If metrics persist to an entity, do not flush per metric. Accumulate in the request and flush once on kernel.terminate, or you will multiply your write load by your metric count.
Environment-specific config. Disable collection in test and reduce sampling in dev; keep prod the only fully-instrumented environment. This also keeps test suites fast and deterministic.
Decorator for sampling. Add a decorator around the manager that records only N% of events when cardinality or write volume becomes a concern, rather than scattering if (rand()) checks through call sites.
get()-style service access, and container patterns removed in Symfony 4+. Budget for a fork, not a composer require.$this->get() may work while constructor autowiring of the manager fails; bind the exact service ID in services.yaml explicitly.debug:config before writing production instrumentation.kernel.terminate, or an explicit finalizer.bin/console debug:container | grep -i metric to find real service IDs, debug:config to confirm resolved settings, then a one-line throwaway command or test that calls the manager directly. With no external documentation, a 10-line functional test is the fastest ground truth.How can I help you explore Laravel packages today?