dev-master
9999999-devA statsd client for Symfony 2.
MIT
The Requires
- php >=5.3
- symfony/framework-bundle >2.3
The Development Requires
A statsd client for Symfony 2.
A statsd client for Symfony 2., (*1)
Add it to your composer.json
file:, (*2)
"require": { "guerriat/metricsbundle": "dev-master" }
, (*3)
Update your vendors using composer:, (*4)
$ php composer.phar update
, (*5)
Register it in app/AppKernel.php
by adding the following line to the $bundles
array:, (*6)
new Guerriat\MetricsBundle\GuerriatMetricsBundle(),
, (*7)
Configure it at will, following the syntax detailed in "Configuration" and "Usage" sections., (*8)
This bundle's configuration has two main sections: servers & clients., (*9)
guerriat_metrics: servers: clients:
You can setup multiple statsd
servers and give them a name. For each one, you can specify the host (defaults to 127.0.0.1
), the port (defaults to 8125
) and the maximum size of UDP payload in bytes (defaults to 512
). Metrics are sent together (as much as possible by datagram) at the end of the page generation., (*10)
Here's an sample configuration file for two servers:, (*11)
guerriat_metrics: servers: default: host: 127.0.0.1 port: 8125 funky: host: funky.guerriat.be port: 54321 udp_max_size: 1024
A client is named and can be assigned to all servers or a subset of them (and that's the whole point of clients). This is done by specifying an array of servers name for the servers
property. If you want to use all servers, you can set the array ['all']
or simply omit the servers
property., (*12)
When using multiple servers, this bundle makes sure that a given key will always be sent to the same server, avoiding aggregation trouble at the statsd level., (*13)
A client can also have other sections such as events
, collectors
and monolog
, as explained in Usage., (*14)
Here's a sample configuration file featuring three servers and two clients:, (*15)
guerriat_metrics: servers: srv1: host: 127.0.0.1 srv2: host: statsd1.guerriat.be srv3: host: statsd2.guerriat.be clients: default: servers: ['all'] no_srv2: servers: ['srv1', 'srv3']
You can set a key prefix for a given client:, (*16)
client_name: prefix: app_name.env_name
It will be used for all metrics sent by the client (including metrics sent via events, collectors and monolog)., (*17)
By default, collectors
will ignore routes that begin with an underscore (such as _wdt
or _assetic_*
), but you can override that behaviour by adding ignore_underscore_route: false
to the client's config as shown:, (*18)
client_name: ignore_underscore_route: false
Every metric is identified by a key. It can only contains alphanumerical characters, hyphens, underscores and dots., (*19)
A counter that you can increment and decrement. You can also sample it, in order not to overload the network. By example, if the sampling rate is 0.1, the message will be sent only once every ten calls. The data is automatically corrected in order for graphite to give correct values. Thus, you don't need to worry about data consistency when changing the sampling rate., (*20)
(note that decrementing is not supported by the current version of Etsy's implementation of statsd, due to a bug), (*21)
A timer is a time in millisecond. Derived values (such as mean, percentile…) are automatically calculated for analytics purposes., (*22)
A gauge contains a arbitrary value., (*23)
A set is a count of unique numbers among the different numbers sent. By example, you can send the user id in order to count the number of active user., (*24)
There is 4 ways to send metrics :, (*25)
Metrics are automatically sent with the onKernelTerminate
event, but they can be sent at any time by using the flushMetrics()
method on a client as shown below from a controller:, (*26)
$this->get('guerriat_metrics')->flushMetrics();
In the controller, you can send metrics using the default
client thanks to the guerriat_metrics
service. For other clients, the service is named guerriat_metrics.client_name
., (*27)
// Counting $this->get('guerriat_metrics')->increment('key'); $this->get('guerriat_metrics')->decrement('key'); // … with a sampling rate $this->get('guerriat_metrics')->increment('key', 0.5); // … with a custom value $this->get('guerriat_metrics')->counter('key', 4); // … with both $this->get('guerriat_metrics')->counter('key', 4, 0.5); // Timing $start = microtime(true); slow_function(); $this->get('guerriat_metrics')->timer('key', (microtime(true) - $start) * 1000); // … or give a callable $this->get('guerriat_metrics')->timing('key', 'slow_function'); // Gauge $this->get('guerriat_metrics')->gauge('key', 42); // Set $this->get('guerriat_metrics')->set('key', 6);
You can setup events to be listened directly in the config file. For each clients, there is an events
section, specifying which metrics should be sent. All types are available: counter
(with increment
and decrement
shortcuts), timer
, gauge
and set
., (*28)
The configuration is done like this:, (*29)
event_name: type: app.key
Or like this, if you want to specify which method is called to get the metric value (except for increment
and decrement
):, (*30)
event_name: type: key: app.key method: getValue
By default, timer
will call getDuration()
while counter
, gauge
and set
will call getValue()
., (*31)
Here's an excerpt of a sample configuration file:, (*32)
client_name: events: guerriat.app.visit: increment: guerriat.guest guerriat.app.long_event: timer: guerriat.long_event.timer counter: guerriat.long_event.processed_items gauge: key: guerriat.long_event.result method: getResult guerriat.app.login: decrement: guerriat.guest increment: guerriat.known_user timer: key: guerriat.password_hash.timer method: getHashDuration set: key: guerriat.connected_users method: getUserId
$event = new \Symfony\Component\EventDispatcher\Event(); $this->get('event_dispatcher')->dispatch('event_name', $event);
MetricCollector
A MetricCollector
is a class extending MetricCollector
, having at least a method which is called on kernel.response and whose signature is:, (*33)
public function collect($client, $key, $request, $response, $exception, $master, $ignore_underscore_route);
$client
is a reference to the Client
service and you can use it as you would from the controller$key
is the key specified in the config file$request
is the Request
object$response
is the Response
object$exception
is the Exception
object$master
is a boolean indicating whether it is the master request$ignore_underscore_route
is a boolean indicating whether it should ignore route starting with _
You have to activate a MetricCollector
for a specific client via the config file, specifying the service name of the collector and the key you want to use, as you can see in this excerpt of a sample configuration file:, (*34)
client_name: collectors: sample_bundle.collector.url: guerriat.request.url guerriat_metrics.collector.time: guerriat.request.time
A few MetricCollector
s are included in this bundle:, (*35)
guerriat_metrics.collector.time
collects the request time (with route name, in a timer)guerriat_metrics.collector.exception
collects the exception (with code, in a counter)guerriat_metrics.collector.memory
collects PHP memory usage (in KB, in a gauge)guerriat_metrics.collector.hit
collects hits (with route name, in a counter)guerriat_metrics.collector.response
collects responses status code (with request route name, in a counter)This bundle have a Monolog handler which can send a increment on every log above a set level. As for the events and collectors, this is configured by client, as you can see in this self-explanatory excerpt:, (*36)
client_name: monolog: enable: true prefix: 'log' ## key prefix level: 'warning' ## minimum level formatter: context_logging: true ## if you want additional packets for context, default is false. extra_logging: true ## if you want additional packets for extra, default is false. words: 3 ## the number of the word in the stats key, default is 2.
However, you also must tell Monolog about our handler by adding this to your config file:, (*37)
monolog: handlers: guerriat_metrics: type: service id: guerriat_metrics.monolog.handler
Note that the prefix will be added to the client's prefix. The resulting key will have the format client_prefix.monolog_prefix.channel.level.first_words
., (*38)
$logger = $this->get('logger'); $logger->error('An error occurred'); $logger->warning('Something strange took place'); $logger->info('Something happened');
If you need to format a string to a valid key, you can use this simple helper:, (*39)
use Guerriat\MetricsBundle\Metric\KeyFormatter; KeyFormatter::format("L'éclair au chocolat"); // returns "Leclair-au-chocolat"
You also can specify a maximum number of words:, (*40)
KeyFormatter::format("L'éclair au chocolat", 2); // returns "Leclair-au"
Or a maximum number of characters:, (*41)
KeyFormatter::format("L'éclair au chocolat", false, 5); // returns "Lecla"
You also can customize the separator:, (*42)
KeyFormatter::format("L'éclair au chocolat", false, false, '.'); // returns "Leclair.au.chocolat"
Or do all this at once:, (*43)
KeyFormatter::format("L'éclair au chocolat", 3, 15, '.'); // returns "Leclair.au.choc"
guerriat_metrics: servers: srv1: host: 127.0.0.1 ## default is 127.0.0.1 port: 8125 ## default is 8125 srv2: host: statsd.guerriat.be beta: host: statsd.guerriat.be port: 8127 udp_max_size: 1024 ## default is 512 clients: default: prefix: guerriat.%kernel.environment% servers: ['srv1', 'srv2'] ## default is ['all'] events: guerriat.app.visit: increment: visit.guest guerriat.app.long_event: timer: long_event.timer counter: long_event.processed_items gauge: key: long_event.result method: getResult guerriat.app.login: decrement: visit.guest increment: visit.known_user timer: key: password_hash.timer method: getHashDuration set: key: connected_users method: getUserId collectors: sample_bundle.collector.url: request.url guerriat_metrics.collector.time: request.time guerriat_metrics.collector.exception: request guerriat_metrics.collector.memory: request.memory guerriat_metrics.collector.hit: request.hit guerriat_metrics.collector.response: response monolog: enable: true prefix: 'log' ## key prefix level: 'warning' ## minimum level test: prefix: guerriat ignore_underscore_route: false ## default is true servers: ['test'] monolog: enable: true prefix: 'log' level: 'debug' formatter: context_logging: true ## if you want additional packets for context, default is false. extra_logging: true ## if you want additional packets for extra, default is false. words: 3 ## the number of the word in the stats key, default is 2. monolog: handlers: guerriat_metrics: type: service id: guerriat_metrics.monolog.handler
$ php composer.phar install $ phpunit --coverage-html Tests/coverage
Written by Olivier Guerriat and greatly inspired by those two bundles:, (*45)
A statsd client for Symfony 2.
MIT