Installation
composer require domnikl/statsd-bundle
Add to config/bundles.php:
return [
// ...
Domnikl\StatsdBundle\DomniklStatsdBundle::class => ['all' => true],
];
Configuration
Define statsd in config/packages/domnikl_statsd.yaml:
statsd:
host: 'localhost'
port: 8125
prefix: 'myapp'
sampling_rate: 1.0
First Use Case
Inject Statsd\Statsd into a service/controller:
use Statsd\Statsd;
class MyController extends AbstractController
{
public function __construct(private Statsd $statsd) {}
public function index()
{
$this->statsd->increment('page.views');
$this->statsd->timing('page.load', 150); // 150ms
}
}
Metrics Collection
$this->statsd->timing('db.query', $executionTimeMs);
$this->statsd->increment('user.signups');
$this->statsd->decrement('failed.jobs');
$this->statsd->gauge('queue.size', count($queue));
Contextual Metrics
Use tags (via statsd client methods) for segmentation:
$this->statsd->increment('api.calls', [], ['endpoint' => 'users', 'status' => '200']);
Dependency Injection
Statsd (as shown above).public function __construct(private Statsd $statsd) {}
onKernelEvent:
public function __construct(private Statsd $statsd) {}
public function onKernelEvent(GetResponseEvent $event) {
$this->statsd->increment('kernel.events');
}
Middleware Integration Track HTTP metrics in middleware:
public function handle(Request $request, Closure $next): Response
{
$start = microtime(true);
$response = $next($request);
$this->statsd->timing('http.response', (microtime(true) - $start) * 1000);
return $response;
}
Database Layer Wrap Doctrine queries with timing:
$this->statsd->timing('db.query', function() use ($entityManager) {
return $entityManager->createQuery('SELECT u FROM User u')->getResult();
});
Sampling Rate
sampling_rate: 1.0 means 100% of metrics are sent. Adjust (e.g., 0.1 for 10%) to reduce load:
sampling_rate: 0.1 # Send 10% of metrics
1.0 for /checkout).Prefix Collisions
prefix in config is unique (e.g., myapp.prod vs. myapp.dev).prefix: '%env(STATSD_PREFIX)%'
Connection Issues
try {
$this->statsd->increment('critical.metric');
} catch (\Exception $e) {
// Log locally or use a backup (e.g., file-based)
file_put_contents('/tmp/statsd_fallback.log', "Metric dropped: critical.metric\n", FILE_APPEND);
}
Tag Limits
// Bad: Exceeds limit
$this->statsd->increment('user.profile.view', [], ['user_id' => '1234567890abcdef1234567890abcdef']);
// Good: Shorten IDs or truncate
$this->statsd->increment('user.profile.view', [], ['user_id' => '123456...']);
Timing Granularity
$this->statsd->timing('process.time', $timeInSeconds * 1000);
Verify Metrics
Use statsd CLI tools (e.g., graphite-statsd) or statsd-no-dogs to inspect metrics:
statsd-no-dogs -p 8125 -l 0.0.0.0:8126
Then visit http://localhost:8126 to see real-time metrics.
Logging
Enable debug mode in config/packages/domnikl_statsd.yaml:
debug: true
Logs will appear in Symfony’s dev.log.
Network Issues Check if the StatsD server is running:
telnet localhost 8125
Or test with nc:
echo "myapp.test:1|c" | nc localhost 8125
Custom Metric Handlers
Extend the bundle by creating a custom Statsd client:
use Statsd\StatsdInterface;
class CustomStatsd implements StatsdInterface
{
private $statsd;
public function __construct(Statsd $statsd) {
$this->statsd = $statsd;
}
public function customMetric(string $name, array $tags = [], array $data = []) {
// Add custom logic (e.g., validation, transformation)
$this->statsd->increment($name, $tags, $data);
}
}
Register as a service:
services:
App\Service\CustomStatsd:
arguments:
$statsd: '@statsd'
Async Metrics For high-throughput apps, use a queue (e.g., Symfony Messenger) to batch metrics:
$this->messageBus->dispatch(new MetricMessage('api.calls', 1));
Configure a handler to flush batches to StatsD.
Dynamic Prefixes Override the prefix per environment or feature flag:
$prefix = $this->featureFlagEnabled('new_metrics') ? 'myapp.v2' : 'myapp.v1';
$this->statsd->setPrefix($prefix);
How can I help you explore Laravel packages today?