Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

StatsDHandler and StatsDFormatter #176

Closed
wants to merge 2 commits into from

5 participants

@liuggio

This PR contains Handler and Formatter,
the handler uses a dependency to statsd-php-client.

Technically could be possible (with few fixes) to avoid the dependency with proper using
of StreamHandler and BufferHandler, but this needs some logic from statsd-php-client, so I preferred to leave the dep.

composer.json
@@ -19,14 +19,16 @@
"require-dev": {
"mlehner/gelf-php": "1.0.*",
"raven/raven": "0.3.*",
- "doctrine/couchdb": "dev-master"
+ "doctrine/couchdb": "dev-master",
+ "liuggio/statsd-php-client": "1.0.6"
@stof
stof added a note

Please don't use an exact version but a range. It does not make sense to forbid using 1.0.7 once available

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Formatter/StatsDFormatter.php
((12 lines not shown))
+namespace Monolog\Formatter;
+
+/**
+ * Formats incoming records in order to be a perfect StatsD key.
+ *
+ * This is especially useful for logging to files
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Giulio De Donato <liuggio@gmail.com>
+ */
+class StatsDFormatter extends LineFormatter
+{
+ const SIMPLE_FORMAT = "%channel%.%level_name%.%short_message%";
+
+ protected $format;
@stof
stof added a note

isn't it already defined in the parent class ?

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Formatter/StatsDFormatter.php
((81 lines not shown))
+ if ($this->logContext && isset($vars['context'])) {
+ foreach ($vars['context'] as $key => $parameter) {
+ $output .= PHP_EOL . sprintf("%s.context.%s.%s", $firstRow, $key, $parameter);
+ }
+ }
+ // creating more rows for extra content
+ if ($this->logExtra && isset($vars['extra'])) {
+ foreach ($vars['extra'] as $key => $parameter) {
+ $output .= PHP_EOL . sprintf("%s.extra.%s.%s", $firstRow, $key, $parameter);
+ }
+ }
+
+ return $output;
+ }
+
+ public function formatBatch(array $records)
@stof
stof added a note

isn't this already handled by the parent class ?

@liuggio
liuggio added a note

yes, but it has different behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Handler/StatsDHandler.php
((70 lines not shown))
+ */
+ public function close()
+ {
+ $this->statsDService->send($this->buffer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $records = explode(PHP_EOL, $record['formatted']);
+
+ foreach ($records as $record) {
+ if (!empty($record)) {
+ $this->buffer[] = $this->statsDFactory->increment(sprintf('%s.%s', $this->getPrefix(), $record));
@stof
stof added a note

why is the goal of this buffer ?

@stof
stof added a note

ah sorry, missed the close

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Handler/StatsDHandler.php
((66 lines not shown))
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->statsDService->send($this->buffer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $records = explode(PHP_EOL, $record['formatted']);
@stof
stof added a note

I would not call it $records as it is not a list of records.

And instead of exploding a previously formatted message, you should return an array in the formatter

@liuggio
liuggio added a note

I wanted to leave the type compatibility with other formats, but I agree with :+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Handler/StatsDHandler.php
((43 lines not shown))
+
+ /**
+ * @var statsDFactory
+ */
+ protected $statsDFactory;
+
+
+ /**
+ * @param StatsdClientInterface $statsDService The Service sends the packet
+ * @param StatsdDataFactoryInterface $statsDFactory The Factory creates the StatsDPacket
+ * @param string $prefix statsd prefix
+ * @param string $connectionString Socket connection string
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(StatsdClientInterface $statsDService = null, StatsdDataFactoryInterface $statsDFactory = null, $prefix, $level = Logger::DEBUG, $bubble = true)
@stof
stof added a note

= null ? The client and the factory don't look like they can be omitted

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Handler/StatsDHandler.php
((39 lines not shown))
+ /**
+ * @var statsDService
+ */
+ protected $statsDService;
+
+ /**
+ * @var statsDFactory
+ */
+ protected $statsDFactory;
+
+
+ /**
+ * @param StatsdClientInterface $statsDService The Service sends the packet
+ * @param StatsdDataFactoryInterface $statsDFactory The Factory creates the StatsDPacket
+ * @param string $prefix statsd prefix
+ * @param string $connectionString Socket connection string
@stof
stof added a note

wrong param

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on the diff
src/Monolog/Handler/StatsDHandler.php
((74 lines not shown))
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $records = explode(PHP_EOL, $record['formatted']);
+
+ foreach ($records as $record) {
+ if (!empty($record)) {
+ $this->buffer[] = $this->statsDFactory->increment(sprintf('%s.%s', $this->getPrefix(), $record));
+ }
+ }
+ }
+
@stof
stof added a note

you should overwrite getDefaultFormatter

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/Monolog/Handler/StatsDHandlerTest.php
((24 lines not shown))
+ if (!class_exists('Liuggio\StatsdClient\StatsdClient')) {
+ $this->markTestSkipped('The "liuggio/statsd-php-client" package is not installed');
+ }
+ }
+
+ public function testHandle()
+ {
+ $client = $this->getMockBuilder('Liuggio\StatsdClient\StatsdClientInterface')
+ ->setMethods(array('send'))
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $factory = $this->getMockBuilder('Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface')
+ ->setMethods(array())
+ ->disableOriginalConstructor()
+ ->getMock();
@stof
stof added a note

As it is an interface, $this->getMock('Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface'); is enough. there is no constructor in interfaces (so no need to disable it) and it will mock all methods of the interface

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/Monolog/Handler/StatsDHandlerTest.php
((9 lines not shown))
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+use Liuggio\StatsdClient\Entity\StatsdData;
+
+
+class StatsDHandlerTest extends TestCase
+{
+ protected function setup()
+ {
+ if (!class_exists('Liuggio\StatsdClient\StatsdClient')) {
@stof
stof added a note

as what you actually use in the test is only the interface, wouldn't it be better to check the interface ?

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Seldaek
Owner

Before diving in the code, I'd like to discuss whether this makes sense at all. statsd is used for statistics/metrics and not really logging. As such I'm wondering if it really makes sense to use monolog to send data to it.

@liuggio

Hi,
Monolog: Sends your logs to files, sockets, inboxes, databases and various web services, for me the monolog goal should be save the log, it did not have to worry about where they go, and how they should be interpreted, StatsD uses Graphite as database.

We use logstash that has statsd output, because the logs are very useful to understand what is happening to your system, eg. when you need to know the state of the application in a specified time (maybe after a certain event), are Warning incremented after a deployment? How many time a customer use the file upload?

I totally understand your doubt but for me statsd as output doesn't smell at all.

@Seldaek
Owner
@liuggio

mmm not really you described monolog as statsd client, that is not the goal of the PR.

The objective is have a visual understanding of the application behavior,
if you have an application, with widespread use of logging, filtering only the channels you need (example the order because is your core domain), you'll obtain a lot of information of what is happening (also having retroactive graphs when you set up a new feature).

README.mdown
@@ -175,6 +177,7 @@ Formatters
- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
- _GelfFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/).
+- _StatsDFormatter_: Used to format log records into a worth StatsD key.
@Seldaek Owner
Seldaek added a note

Typo of worthy? Otherwise I didn't get what you meant with worth there :)

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
README.mdown
@@ -127,6 +127,8 @@ Handlers
- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using
[raven](https://packagist.org/packages/raven/raven).
- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
+- _StatsDHandler_: Logs records to a [StatsD Server](https://github.com/etsy/statsd/), please use StatsDFormatter
+ in order to have clean statistic keys.
@Seldaek Owner
Seldaek added a note

The , please use... part can be removed now that you have getDefaultFormatter returning it already.

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/Monolog/Handler/StatsDHandler.php
((37 lines not shown))
+ */
+ protected $prefix;
+
+ /**
+ * @var statsDService
+ */
+ protected $statsDService;
+
+ /**
+ * @var statsDFactory
+ */
+ protected $statsDFactory;
+
+
+ /**
+ * @param StatsdClientInterface $statsDService The Service sends the packet

only one space is needed in the last column

@liuggio
liuggio added a note

thanks Yep I'm going to review the code in order to clean up CS.

@liuggio
liuggio added a note

ps: you have a talent, how do you spot it? ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@liuggio

Ok this is not a fix, I used to create relative link on Readme, useful with more branches. Let me know, revert on demand :)

@liuggio liuggio commented on the diff
README.mdown
@@ -119,7 +119,7 @@ Handlers
### Log specific servers and networked logging
- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this
- for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md).
@liuggio
liuggio added a note

Ok this is not a fix, I used to create relative link on Readme, useful with more branches. Let me know, revert on demand :)

@Seldaek Owner
Seldaek added a note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@timmow

@liuggio One thing you can look at in the meantime is http://www.logstash.net/docs/1.1.9/, for which there is a formatter available for monolog. Logstash is a centralised log store, and it can send the logs onto statsd / graphite.

@liuggio

Better idea, I moved the monolog handler/formatter into the library itself "liuggio/statsd-php-client"

The things that smelled to me is not having a StatsdHandler here in monolog (I still don't get your doubts) but a dependency to a unofficial lib.

particular thanks to @stof for the good code suggestions.

@liuggio liuggio closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 27, 2013
  1. @liuggio
  2. @liuggio

    little monolog fixes

    liuggio authored
This page is out of date. Refresh to see the latest.
View
4 README.mdown
@@ -119,7 +119,7 @@ Handlers
### Log specific servers and networked logging
- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this
- for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md).
@liuggio
liuggio added a note

Ok this is not a fix, I used to create relative link on Readme, useful with more branches. Let me know, revert on demand :)

@Seldaek Owner
Seldaek added a note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ for UNIX and TCP sockets. See an [example](doc/sockets.md).
- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible
server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+).
- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server.
@@ -127,6 +127,7 @@ Handlers
- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using
[raven](https://packagist.org/packages/raven/raven).
- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
+- _StatsDHandler_: Logs records to a [StatsD Server](https://github.com/etsy/statsd/).
### Logging in development
@@ -175,6 +176,7 @@ Formatters
- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
- _GelfFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/).
+- _StatsDFormatter_: Used to format log records into StatsD keys, only useful for the StatsDHandler.
Processors
----------
View
6 composer.json
@@ -19,14 +19,16 @@
"require-dev": {
"mlehner/gelf-php": "1.0.*",
"raven/raven": "0.3.*",
- "doctrine/couchdb": "dev-master"
+ "doctrine/couchdb": "dev-master",
+ "liuggio/statsd-php-client": "1.0.*"
},
"suggest": {
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
"raven/raven": "Allow sending log messages to a Sentry server",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
- "ext-mongo": "Allow sending log messages to a MongoDB server"
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "statsd-php-client": "Allow sending log messages to StatsD server"
},
"autoload": {
"psr-0": {"Monolog": "src/"}
View
5 src/Monolog/Formatter/LineFormatter.php
@@ -55,7 +55,10 @@ public function format(array $record)
return $output;
}
-
+
+ /**
+ * {@inheritdoc}
+ */
public function formatBatch(array $records)
{
$message = '';
View
108 src/Monolog/Formatter/StatsDFormatter.php
@@ -0,0 +1,108 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Formats incoming records in order to be a perfect StatsD key.
+ *
+ * This is especially useful for logging to files
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Giulio De Donato <liuggio@gmail.com>
+ */
+class StatsDFormatter extends LineFormatter
+{
+ const SIMPLE_FORMAT = "%channel%.%level_name%.%short_message%";
+
+ protected $numberOfWords;
+ protected $logContext;
+ protected $logExtra;
+
+ /**
+ * @param string $format The format of the message
+ * @param Boolean $logContext If true add multiple rows containing Context information
+ * @param Boolean $logExtra If true add multiple rows containing Extra information
+ * @param integer $numberOfWords The number of words to show.
+ */
+ public function __construct($format = null, $logContext = true, $logExtra = true, $numberOfWords = 2)
+ {
+ $this->format = $format ? : static::SIMPLE_FORMAT;
+ $this->numberOfWords = $numberOfWords;
+ $this->logContext = $logContext;
+ $this->logExtra = $logExtra;
+ parent::__construct();
+ }
+
+ /**
+ * This function converts a long message into a string with the first N-words.
+ * eg. from: "Notified event "kernel.request" to listener "Symfony\Component\HttpKernel\EventListener"
+ * to: "Notified event"
+ *
+ * @param string $message The message to shortify.
+ *
+ * @return string
+ */
+ public function getFirstWords($message)
+ {
+ $glue = '-';
+ $pieces = explode(' ', $message);
+ array_splice($pieces, $this->numberOfWords);
+ $shortMessage = preg_replace("/[^A-Za-z0-9?![:space:]]/", "-", implode($glue, $pieces));
+
+ return $shortMessage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $vars = $this->normalize($record);
+
+ $firstRow = $this->format;
+ $output = array();
+
+ $vars['short_message'] = $this->getFirstWords($vars['message']);
+ foreach ($vars as $var => $val) {
+ $firstRow = str_replace('%' . $var . '%', $this->convertToString($val), $firstRow);
+ }
+ $output[] = $firstRow;
+ // creating more rows for context content
+ if ($this->logContext && isset($vars['context'])) {
+ foreach ($vars['context'] as $key => $parameter) {
+ $output[] = sprintf("%s.context.%s.%s", $firstRow, $key, $parameter);
+ }
+ }
+ // creating more rows for extra content
+ if ($this->logExtra && isset($vars['extra'])) {
+ foreach ($vars['extra'] as $key => $parameter) {
+ $output[] = sprintf("%s.extra.%s.%s", $firstRow, $key, $parameter);
+ }
+ }
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ $output = array();
+ foreach ($records as $record) {
+ $output = array_merge($output, $this->format($record));
+ }
+
+ return $output;
+ }
+}
View
129 src/Monolog/Handler/StatsDHandler.php
@@ -0,0 +1,129 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Handler\AbstractProcessingHandler;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\StatsDFormatter;
+use Monolog\Logger;
+
+use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
+use Liuggio\StatsdClient\Factory\StatsdDataFactory;
+use Liuggio\StatsdClient\StatsdClientInterface;
+
+/**
+ * A processing handler for StatsD.
+ *
+ * @author Giulio De Donato <liuggio@gmail.com>
+ */
+class StatsDHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var array
+ */
+ protected $buffer = array();
+
+ /**
+ * @var string
+ */
+ protected $prefix;
+
+ /**
+ * @var statsDService
+ */
+ protected $statsDService;
+
+ /**
+ * @var statsDFactory
+ */
+ protected $statsDFactory;
+
+ /**
+ * @param StatsdClientInterface $statsDService The Service sends the packet
+ * @param StatsdDataFactoryInterface $statsDFactory The Factory creates the StatsDPacket
+ * @param string $prefix Statsd key prefix
+ * @param integer $level The minimum logging level at which this handler will be triggered
+ * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(StatsdClientInterface $statsDService, StatsdDataFactoryInterface $statsDFactory = null, $prefix, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->statsDService = $statsDService;
+ $this->statsDFactory = $statsDFactory ? $statsDFactory : new StatsdDataFactory();
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->statsDService->send($this->buffer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $records = is_array($record['formatted']) ? $record['formatted'] : array($record['formatted']);
+
+ foreach ($records as $record) {
+ if (!empty($record)) {
+ $this->buffer[] = $this->statsDFactory->increment(sprintf('%s.%s', $this->getPrefix(), $record));
+ }
+ }
+ }
+
@stof
stof added a note

you should overwrite getDefaultFormatter

@liuggio
liuggio added a note

:+1:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ /**
+ * Gets the default formatter.
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultFormatter()
+ {
+ return new StatsDFormatter();
+ }
+
+ /**
+ * @param string $prefix
+ */
+ public function setPrefix($prefix)
+ {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @param StatsdClientInterface $statsDService
+ */
+ public function setStatsDService(StatsdClientInterface $statsDService)
+ {
+ $this->statsDService = $statsDService;
+ }
+
+ /**
+ * @param StatsdDataFactoryInterface $statsDFactory
+ */
+ public function setStatsDFactory(StatsdDataFactoryInterface $statsDFactory)
+ {
+ $this->statsDFactory = $statsDFactory;
+ }
+}
View
176 tests/Monolog/Formatter/StatsDFormatterTest.php
@@ -0,0 +1,176 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * @covers Monolog\Formatter\StatsDFormatter
+ */
+class StatsDFormatterTest extends \PHPUnit_Framework_TestCase
+{
+ public function testBatchFormat()
+ {
+ $formatter = new StatsDFormatter(null, 2);
+ $message = $formatter->formatBatch(array(
+ array(
+ 'level_name' => 'CRITICAL',
+ 'channel' => 'test',
+ 'message' => 'bar',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'message' => 'foo',
+ 'context' => array(),
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ),
+ ));
+
+ $this->assertEquals(array('test.CRITICAL.bar', 'log.WARNING.foo'), $message);
+ }
+
+ public function testDefFormatWithString()
+ {
+ $formatter = new StatsDFormatter(StatsDFormatter::SIMPLE_FORMAT);
+ $message = $formatter->format(array(
+ 'level_name' => 'WARNING',
+ 'channel' => 'log',
+ 'context' => array(),
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ));
+ $this->assertEquals(array('log.WARNING.foo'), $message);
+ }
+
+ public function testDefFormatWithArrayContext()
+ {
+ $formatter = new StatsDFormatter();
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ )
+ ));
+
+ $assert = array('meh.ERROR.foo',
+ 'meh.ERROR.foo.context.foo.bar',
+ 'meh.ERROR.foo.context.baz.qux');
+
+ $this->assertEquals($assert, $message);
+ }
+
+ public function testDefFormatWithArrayContextAndExtra()
+ {
+ $formatter = new StatsDFormatter();
+ $message = $formatter->format(array(
+ 'level_name' => 'ERROR',
+ 'channel' => 'meh',
+ 'message' => 'foo',
+ 'datetime' => new \DateTime,
+ 'extra' => array('extra'=>'woow'),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ )
+ ));
+
+ $assert = array('meh.ERROR.foo',
+ 'meh.ERROR.foo.context.foo.bar',
+ 'meh.ERROR.foo.context.baz.qux',
+ 'meh.ERROR.foo.extra.extra.woow');
+
+ $this->assertEquals($assert, $message);
+
+ }
+
+ public function testDefLongFormat()
+ {
+ $formatter = new StatsDFormatter();
+ $message = $formatter->format(array(
+ 'level_name' => 'DEBUG',
+ 'channel' => 'doctrine',
+ 'message' => 'INSERT INTO viaggio_calendar (enable, viaggio_id, calendar_id) VALUES (?, ?, ?)',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ )
+ ));
+ $this->assertEquals(array("doctrine.DEBUG.INSERT-INTO",
+ "doctrine.DEBUG.INSERT-INTO.context.foo.bar",
+ "doctrine.DEBUG.INSERT-INTO.context.baz.qux"), $message);
+ }
+
+ public function testDefLongFormatWith3WordsNoContextAndNoExtra()
+ {
+ $formatter = new StatsDFormatter(null, false, false, 3);
+ $message = $formatter->format(array(
+ 'level_name' => 'DEBUG',
+ 'channel' => 'doctrine',
+ 'message' => 'INSERT INTO viaggio_calendar (enable, viaggio_id, calendar_id) VALUES (?, ?, ?)',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ )
+ ));
+ $this->assertEquals(array("doctrine.DEBUG.INSERT-INTO-viaggio-calendar"), $message);
+ }
+ public function testDefRouteException()
+ {
+ $formatter = new StatsDFormatter();
+ $message = $formatter->format(array(
+ 'level_name' => 'DEBUG',
+ 'channel' => 'doctrine',
+ 'message' => 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException: No route found for "GET /ddd" (uncaught exception) at /xxxx/classes.php line 5062',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ ));
+ $this->assertEquals(array('doctrine.DEBUG.Symfony-Component-HttpKernel-Exception-NotFoundHttpException--No'), $message);
+ }
+
+ public function testDefKernelException()
+ {
+ $formatter = new StatsDFormatter();
+ $message = $formatter->format(array(
+ 'level_name' => 'DEBUG',
+ 'channel' => 'doctrine',
+ 'message' => 'Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelException"',
+ 'datetime' => new \DateTime,
+ 'extra' => array(),
+ 'context' => array(
+ 'foo' => 'bar',
+ 'baz' => 'qux',
+ )
+ ));
+
+ $assert = array('doctrine.DEBUG.Notified-event',
+ 'doctrine.DEBUG.Notified-event.context.foo.bar',
+ 'doctrine.DEBUG.Notified-event.context.baz.qux');
+
+ $this->assertEquals($assert, $message);
+
+
+ }
+}
+
View
56 tests/Monolog/Handler/StatsDHandlerTest.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\TestCase;
+use Monolog\Logger;
+
+use Liuggio\StatsdClient\Entity\StatsdData;
+
+
+class StatsDHandlerTest extends TestCase
+{
+ protected function setup()
+ {
+ if (!interface_exists('Liuggio\StatsdClient\StatsdClientInterface')) {
+ $this->markTestSkipped('The "liuggio/statsd-php-client" package is not installed');
+ }
+ }
+
+ public function testHandle()
+ {
+ $client = $this->getMock('Liuggio\StatsdClient\StatsdClientInterface');
+ $factory = $this->getMock('Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface');
+
+ $factory->expects($this->any())
+ ->method('increment')
+ ->will($this->returnCallback(function ($input){
+ return sprintf('%s|c|1', $input);
+ }));
+
+ $prefixToAssert = 'prefix';
+ $messageToAssert = 'test-msg';
+
+ $record = $this->getRecord(Logger::WARNING, $messageToAssert, array('data' => new \stdClass, 'foo' => 34));
+
+ $assert = array(sprintf('%s.test.WARNING.%s|c|1',$prefixToAssert, $messageToAssert),
+ sprintf('%s.test.WARNING.%s.context.data.[object] (stdClass: {})|c|1',$prefixToAssert, $messageToAssert),
+ sprintf('%s.test.WARNING.%s.context.foo.34|c|1',$prefixToAssert, $messageToAssert));
+
+ $client->expects($this->once())
+ ->method('send')
+ ->with($assert);
+
+ $handler = new StatsDHandler($client, $factory, $prefixToAssert);
+ $handler->handle($record);
+ }
+}
Something went wrong with that request. Please try again.