diff --git a/doc/usage.md b/doc/usage.md index 029f6c2..90d1eb5 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -5,7 +5,8 @@ array( 'serv1' => array('address' => 'udp://200.22.143.12'), 'serv2' => array('port' => 8125, 'address' => 'udp://200.22.143.12') - ) + ), + new \M6Web\Component\Statsd\MessageFormatter\InfluxDBStatsDMessageFormatter() ); $client->increment('a.graphite.node'); diff --git a/src/M6Web/Component/Statsd/Client.php b/src/M6Web/Component/Statsd/Client.php index 7ff3d6b..e8bbe3d 100644 --- a/src/M6Web/Component/Statsd/Client.php +++ b/src/M6Web/Component/Statsd/Client.php @@ -5,6 +5,9 @@ namespace M6Web\Component\Statsd; +use M6Web\Component\Statsd\MessageFormatter\InfluxDBStatsDMessageFormatter; +use M6Web\Component\Statsd\MessageFormatter\MessageFormatterInterface; + /** * client Statsd */ @@ -38,15 +41,19 @@ class Client */ private $serverKeys = []; + /** @var MessageFormatterInterface */ + private $messageFormatter; + /** * contructeur * * @param array $servers les serveurs */ - public function __construct(array $servers) + public function __construct(array $servers, MessageFormatterInterface $messageFormatter = null) { $this->init($servers); $this->initQueue(); + $this->messageFormatter = $messageFormatter ?: new InfluxDBStatsDMessageFormatter(); } /** @@ -170,7 +177,9 @@ protected function buildSampledData() foreach ($this->getToSend() as $metric) { $server = $metric['server']; - $sampledData[$server][] = $metric['message']->getStatsdMessage(); + /** @var MessageEntity $message */ + $message = $metric['message']; + $sampledData[$server][] = $this->messageFormatter->format($message); } return $sampledData; diff --git a/src/M6Web/Component/Statsd/MessageEntity.php b/src/M6Web/Component/Statsd/MessageEntity.php index 084a654..2418c11 100644 --- a/src/M6Web/Component/Statsd/MessageEntity.php +++ b/src/M6Web/Component/Statsd/MessageEntity.php @@ -76,7 +76,7 @@ protected function checkConstructor() * * @return bool */ - protected function useSampleRate() + public function useSampleRate() { if (($this->getSampleRate() < 1) && (mt_rand() / mt_getrandmax()) <= $this->getSampleRate()) { return true; @@ -117,6 +117,14 @@ public function getUnit() return $this->unit; } + /** + * @return array + */ + public function getTags() + { + return $this->tags; + } + /** * @return string Tags formatted for sending * ex: "server=5,country=fr" @@ -147,9 +155,22 @@ private function getFullNode() * format a statsd message * * @return string + * + * @deprecated */ public function getStatsdMessage() { + trigger_error( + sprintf( + '%s is deprecated and will be removed in the next major version. '. + 'Update your code to use %s::%s.', + __METHOD__, + 'M6Web\Component\Statsd\MessageFormatter\MessageFormatterInterface', + 'format' + ), + E_USER_DEPRECATED + ); + $message = sprintf('%s:%s|%s', $this->getFullNode(), $this->getValue(), $this->getUnit()); if ($this->useSampleRate()) { $message .= sprintf('|@%s', $this->getSampleRate()); diff --git a/src/M6Web/Component/Statsd/MessageFormatter/DogStatsDMessageFormatter.php b/src/M6Web/Component/Statsd/MessageFormatter/DogStatsDMessageFormatter.php new file mode 100644 index 0000000..efa344d --- /dev/null +++ b/src/M6Web/Component/Statsd/MessageFormatter/DogStatsDMessageFormatter.php @@ -0,0 +1,42 @@ +getNode(), $message->getValue(), $message->getUnit()); + + if ($message->useSampleRate()) { + $formatted .= sprintf('|@%s', $message->getSampleRate()); + } + + if ($message->getTags()) { + $formatted .= '|#'.$this->getTagsAsString($message); + } + + return $formatted."\n"; + } + + /** + * @return string + */ + private function getTagsAsString(MessageEntity $message) + { + $tags = array_map(static function ($k, $v) { + return $k.':'.$v; + }, array_keys($message->getTags()), $message->getTags()); + + return implode(',', $tags); + } +} diff --git a/src/M6Web/Component/Statsd/MessageFormatter/InfluxDBStatsDMessageFormatter.php b/src/M6Web/Component/Statsd/MessageFormatter/InfluxDBStatsDMessageFormatter.php new file mode 100644 index 0000000..107da8a --- /dev/null +++ b/src/M6Web/Component/Statsd/MessageFormatter/InfluxDBStatsDMessageFormatter.php @@ -0,0 +1,44 @@ +getNode(); + + if ($message->getTags()) { + $node .= ','.$this->getTagsAsString($message); + } + + $formatted = sprintf('%s:%s|%s', $node, $message->getValue(), $message->getUnit()); + + if ($message->useSampleRate()) { + $formatted .= sprintf('|@%s', $message->getSampleRate()); + } + + return $formatted; + } + + /** + * @return string + */ + private function getTagsAsString(MessageEntity $message) + { + $tags = array_map(static function ($k, $v) { + return $k.'='.$v; + }, array_keys($message->getTags()), $message->getTags()); + + return implode(',', $tags); + } +} diff --git a/src/M6Web/Component/Statsd/MessageFormatter/MessageFormatterInterface.php b/src/M6Web/Component/Statsd/MessageFormatter/MessageFormatterInterface.php new file mode 100644 index 0000000..96f3b5b --- /dev/null +++ b/src/M6Web/Component/Statsd/MessageFormatter/MessageFormatterInterface.php @@ -0,0 +1,16 @@ +boolean($client->send()) ->isEqualTo(true) ->mock($client) - ->call('writeDatas')->exactly(1); + ->call('writeDatas') + ->withArguments('serv2', ['service.foo:1|c'])->once() + ->withAnyArguments()->exactly(1); $client = new \mock\M6Web\Component\Statsd\Client($this->getConf()); $client->getMockController()->writeDatas = function ($server, $datas) { return true; @@ -315,7 +317,9 @@ public function testSend() ->then() ->boolean($client->send()) ->mock($client) - ->call('writeDatas')->exactly(1); // but one call + ->call('writeDatas') + ->withArguments('serv2', ['service.foo:1|c', 'service.foo:1|c'])->once() + ->withAnyArguments()->exactly(1); // but one call $client = new \mock\M6Web\Component\Statsd\Client($this->getConf()); $client->getMockController()->writeDatas = function ($server, $datas) { return true; @@ -324,12 +328,19 @@ public function testSend() ->then() ->boolean($client->send()) ->mock($client) - ->call('writeDatas')->exactly(2); + ->call('writeDatas') + ->withArguments('serv1', ['foo2:1|c'])->once() + ->withArguments('serv2', ['foo:1|c'])->once() + ->withAnyArguments()->exactly(2); $this->if($client->count('foocount', 5)) ->then() ->boolean($client->send()) ->mock($client) - ->call('writeDatas')->exactly(3); + ->call('writeDatas') + ->withArguments('serv1', ['foo2:1|c'])->once() + ->withArguments('serv2', ['foo:1|c'])->once() + ->withArguments('serv2', ['foocount:5|c'])->once() + ->withAnyArguments()->exactly(3); } } diff --git a/src/M6Web/Component/Tests/Units/MessageEntity.php b/src/M6Web/Component/Tests/Units/MessageEntity.php index bb08dc1..3262a33 100644 --- a/src/M6Web/Component/Tests/Units/MessageEntity.php +++ b/src/M6Web/Component/Tests/Units/MessageEntity.php @@ -37,32 +37,55 @@ public function testGet() */ public function testgetStatsdMessage() { + $expectedDeprecation = + 'M6Web\Component\Statsd\MessageEntity::getStatsdMessage is deprecated and will be '. + 'removed in the next major version. Update your code to use '. + 'M6Web\Component\Statsd\MessageFormatter\MessageFormatterInterface::format.'; + // not sampled message - $this->if($messageEntity = new Statsd\MessageEntity( - 'raoul.node', 1, 'c')) - ->then() - ->string($messageEntity->getStatsdMessage()) - ->isEqualTo('raoul.node:1|c') - ; + $this + ->when(function () { + $this->if($messageEntity = new Statsd\MessageEntity( + 'raoul.node', 1, 'c')) + ->then() + ->string($messageEntity->getStatsdMessage()) + ->isEqualTo('raoul.node:1|c') + ; + }) + ->error() + ->withMessage($expectedDeprecation) + ->exists(); // sampled message $this->function->mt_rand = function () { return 1; }; $this->function->mt_getrandmax = function () { return 10; }; - $this->if($messageEntity = new Statsd\MessageEntity( - 'raoul.node', 1, 'c', 0.2)) - ->then() - ->string($messageEntity->getStatsdMessage()) - ->isEqualTo('raoul.node:1|c|@0.2') - ; + $this + ->when(function () { + $this->if($messageEntity = new Statsd\MessageEntity( + 'raoul.node', 1, 'c', 0.2)) + ->then() + ->string($messageEntity->getStatsdMessage()) + ->isEqualTo('raoul.node:1|c|@0.2') + ; + }) + ->error() + ->withMessage($expectedDeprecation) + ->exists(); // with tags - $this->if($messageEntity = new Statsd\MessageEntity( - 'raoul.node', 1, 'c', 0.2, ['foo' => 'bar'])) - ->then() - ->string($messageEntity->getStatsdMessage()) - ->isEqualTo('raoul.node,foo=bar:1|c|@0.2') - ; + $this + ->when(function () { + $this->if($messageEntity = new Statsd\MessageEntity( + 'raoul.node', 1, 'c', 0.2, ['foo' => 'bar'])) + ->then() + ->string($messageEntity->getStatsdMessage()) + ->isEqualTo('raoul.node,foo=bar:1|c|@0.2') + ; + }) + ->error() + ->withMessage($expectedDeprecation) + ->exists(); } public function testErrorConstructorStatsdMessage() diff --git a/src/M6Web/Component/Tests/Units/MessageFormatter/DogStatsDMessageFormatter.php b/src/M6Web/Component/Tests/Units/MessageFormatter/DogStatsDMessageFormatter.php new file mode 100644 index 0000000..4fbe237 --- /dev/null +++ b/src/M6Web/Component/Tests/Units/MessageFormatter/DogStatsDMessageFormatter.php @@ -0,0 +1,38 @@ +if($formatter = new Statsd\MessageFormatter\DogStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo("raoul.node:1|c\n"); + + // sampled message + $message = new \mock\M6Web\Component\Statsd\MessageEntity('raoul.node', 1, 'c', 0.2); + $this->calling($message)->useSampleRate = true; + $this + ->given($formatter = new Statsd\MessageFormatter\DogStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo("raoul.node:1|c|@0.2\n"); + + // with tags + $message = new \mock\M6Web\Component\Statsd\MessageEntity('raoul.node', 1, 'c', 0.2, ['foo' => 'bar']); + $this->calling($message)->useSampleRate = true; + $this + ->if($formatter = new Statsd\MessageFormatter\DogStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo("raoul.node:1|c|@0.2|#foo:bar\n"); + } +} diff --git a/src/M6Web/Component/Tests/Units/MessageFormatter/InfluxDBStatsDMessageFormatter.php b/src/M6Web/Component/Tests/Units/MessageFormatter/InfluxDBStatsDMessageFormatter.php new file mode 100644 index 0000000..fd83ed4 --- /dev/null +++ b/src/M6Web/Component/Tests/Units/MessageFormatter/InfluxDBStatsDMessageFormatter.php @@ -0,0 +1,38 @@ +if($formatter = new Statsd\MessageFormatter\InfluxDBStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo('raoul.node:1|c'); + + // sampled message + $message = new \mock\M6Web\Component\Statsd\MessageEntity('raoul.node', 1, 'c', 0.2); + $this->calling($message)->useSampleRate = true; + $this + ->given($formatter = new Statsd\MessageFormatter\InfluxDBStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo('raoul.node:1|c|@0.2'); + + // with tags + $message = new \mock\M6Web\Component\Statsd\MessageEntity('raoul.node', 1, 'c', 0.2, ['foo' => 'bar']); + $this->calling($message)->useSampleRate = true; + $this + ->if($formatter = new Statsd\MessageFormatter\InfluxDBStatsDMessageFormatter()) + ->then() + ->string($formatter->format($message)) + ->isEqualTo('raoul.node,foo=bar:1|c|@0.2'); + } +}