From 69cf0607404f943845318c8f4b43c01f369ec725 Mon Sep 17 00:00:00 2001 From: Sergey Protko Date: Mon, 18 Sep 2017 17:43:47 +0300 Subject: [PATCH 1/3] Add Predis support --- composer.json | 6 +- examples/flush_adapter.php | 5 + examples/metrics.php | 4 + examples/pushgateway.php | 4 + examples/some_counter.php | 4 + examples/some_gauge.php | 4 + examples/some_histogram.php | 4 + src/Prometheus/PushGateway.php | 4 +- src/Prometheus/Storage/Predis.php | 335 ++++++++++++++++++ tests/Test/BlackBoxPushGatewayTest.php | 2 +- .../Predis/CollectorRegistryTest.php | 16 + tests/Test/Prometheus/Predis/CounterTest.php | 20 ++ tests/Test/Prometheus/Predis/GaugeTest.php | 20 ++ .../Test/Prometheus/Predis/HistogramTest.php | 20 ++ 14 files changed, 443 insertions(+), 5 deletions(-) create mode 100644 src/Prometheus/Storage/Predis.php create mode 100644 tests/Test/Prometheus/Predis/CollectorRegistryTest.php create mode 100644 tests/Test/Prometheus/Predis/CounterTest.php create mode 100644 tests/Test/Prometheus/Predis/GaugeTest.php create mode 100644 tests/Test/Prometheus/Predis/HistogramTest.php diff --git a/composer.json b/composer.json index 3d97c12..1126c79 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,13 @@ "guzzlehttp/guzzle": "^6.2" }, "require-dev": { - "phpunit/phpunit": "4.1.0" + "phpunit/phpunit": "4.1.0", + "predis/predis": "^1.1" }, "suggest": { "ext-redis": "Required if using Redis.", - "ext-apc": "Required if using APCu." + "predis/predis": "Required if using Predis", + "ext-apcu": "Required if using APCu." }, "autoload": { "psr-0": { diff --git a/examples/flush_adapter.php b/examples/flush_adapter.php index 0c3862d..a2f98c0 100644 --- a/examples/flush_adapter.php +++ b/examples/flush_adapter.php @@ -8,6 +8,11 @@ $redisAdapter = new Prometheus\Storage\Redis(array('host' => REDIS_HOST)); $redisAdapter->flushRedis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); + $adapter->flushRedis(); } elseif ($adapter === 'apc') { $apcAdapter = new Prometheus\Storage\APC(); $apcAdapter->flushAPC(); diff --git a/examples/metrics.php b/examples/metrics.php index fa89247..76c834a 100644 --- a/examples/metrics.php +++ b/examples/metrics.php @@ -11,6 +11,10 @@ if ($adapter === 'redis') { Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/pushgateway.php b/examples/pushgateway.php index 984035d..6c4d789 100644 --- a/examples/pushgateway.php +++ b/examples/pushgateway.php @@ -9,6 +9,10 @@ if ($adapter === 'redis') { Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_counter.php b/examples/some_counter.php index 823bfac..58fc6ff 100644 --- a/examples/some_counter.php +++ b/examples/some_counter.php @@ -10,6 +10,10 @@ if ($adapter === 'redis') { Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_gauge.php b/examples/some_gauge.php index b3e2382..b847131 100644 --- a/examples/some_gauge.php +++ b/examples/some_gauge.php @@ -13,6 +13,10 @@ if ($adapter === 'redis') { Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_histogram.php b/examples/some_histogram.php index 6b34809..a618cbe 100644 --- a/examples/some_histogram.php +++ b/examples/some_histogram.php @@ -12,6 +12,10 @@ if ($adapter === 'redis') { Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); +} elseif ($adapter === 'predis') { + $adapter = new Prometheus\Storage\Predis([ + 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' + ]); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/src/Prometheus/PushGateway.php b/src/Prometheus/PushGateway.php index a4a3fd2..8cbbac7 100644 --- a/src/Prometheus/PushGateway.php +++ b/src/Prometheus/PushGateway.php @@ -49,9 +49,9 @@ public function pushAdd(CollectorRegistry $collectorRegistry, $job, $groupingKey * @param $job * @param $groupingKey */ - public function delete($job, $groupingKey = null) + public function delete(CollectorRegistry $collectorRegistry, $job, $groupingKey = null) { - $this->doRequest(null, $job, $groupingKey, 'delete'); + $this->doRequest($collectorRegistry, $job, $groupingKey, 'delete'); } /** diff --git a/src/Prometheus/Storage/Predis.php b/src/Prometheus/Storage/Predis.php new file mode 100644 index 0000000..d4a3258 --- /dev/null +++ b/src/Prometheus/Storage/Predis.php @@ -0,0 +1,335 @@ + '127.0.0.1', + 'port' => 6379, + 'timeout' => 0.1, + 'read_timeout' => 10, + 'persistent_connections' => false, + ]; + + private static $prefix = 'PROMETHEUS_'; + + private $options; + /** + * @var Client + */ + private $predis; + + public function __construct(array $options = array()) + { + $this->options = array_merge(self::$defaultOptions, $options); + } + + /** + * @param array $options + */ + public static function setDefaultOptions(array $options) + { + self::$defaultOptions = array_merge(self::$defaultOptions, $options); + } + + public static function setPrefix($prefix) + { + self::$prefix = $prefix; + } + + public function flushRedis() + { + $this->openConnection(); + $this->predis->flushall(); + } + + /** + * @return MetricFamilySamples[] + * @throws StorageException + */ + public function collect() + { + $this->openConnection(); + $metrics = $this->collectHistograms(); + $metrics = array_merge($metrics, $this->collectGauges()); + $metrics = array_merge($metrics, $this->collectCounters()); + return array_map( + function (array $metric) { + return new MetricFamilySamples($metric); + }, + $metrics + ); + } + + /** + * @throws StorageException + */ + private function openConnection() + { + try { + + $this->predis = new Client([ + 'scheme' => 'tcp', + 'host' => $this->options['host'], + 'port' => $this->options['port'], + 'timeout' => $this->options['timeout'], + 'read_write_timeout' => $this->options['read_timeout'], + 'persistent' => $this->options['persistent_connections'], + ]); + + } catch (\RedisException $e) { + throw new StorageException("Can't connect to Redis server", 0, $e); + } + } + + public function updateHistogram(array $data) + { + $this->openConnection(); + $bucketToIncrease = '+Inf'; + foreach ($data['buckets'] as $bucket) { + if ($data['value'] <= $bucket) { + $bucketToIncrease = $bucket; + break; + } + } + $metaData = $data; + unset($metaData['value']); + unset($metaData['labelValues']); + $this->predis->eval(<<toMetricKey($data), + json_encode(array('b' => 'sum', 'labelValues' => $data['labelValues'])), + json_encode(array('b' => $bucketToIncrease, 'labelValues' => $data['labelValues'])), + self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + $data['value'], + json_encode($metaData) + ); + } + + public function updateGauge(array $data) + { + $this->openConnection(); + $metaData = $data; + unset($metaData['value']); + unset($metaData['labelValues']); + unset($metaData['command']); + $this->predis->eval(<<toMetricKey($data), + $this->getRedisCommand($data['command']), + self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + json_encode($data['labelValues']), + $data['value'], + json_encode($metaData) + ); + } + + public function updateCounter(array $data) + { + $this->openConnection(); + $metaData = $data; + unset($metaData['value']); + unset($metaData['labelValues']); + unset($metaData['command']); + $result = $this->predis->eval(<<toMetricKey($data), + $this->getRedisCommand($data['command']), + self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + json_encode($data['labelValues']), + $data['value'], + json_encode($metaData) + ); + return $result; + } + + private function collectHistograms() + { + $keys = $this->predis->smembers(self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + sort($keys); + $histograms = array(); + foreach ($keys as $key) { + $raw = $this->predis->hgetall($key); + $histogram = json_decode($raw['__meta'], true); + unset($raw['__meta']); + $histogram['samples'] = array(); + + // Add the Inf bucket so we can compute it later on + $histogram['buckets'][] = '+Inf'; + + $allLabelValues = array(); + foreach (array_keys($raw) as $k) { + $d = json_decode($k, true); + if ($d['b'] == 'sum') { + continue; + } + $allLabelValues[] = $d['labelValues']; + } + + // We need set semantics. + // This is the equivalent of array_unique but for arrays of arrays. + $allLabelValues = array_map("unserialize", array_unique(array_map("serialize", $allLabelValues))); + sort($allLabelValues); + + foreach ($allLabelValues as $labelValues) { + // Fill up all buckets. + // If the bucket doesn't exist fill in values from + // the previous one. + $acc = 0; + foreach ($histogram['buckets'] as $bucket) { + $bucketKey = json_encode(array('b' => $bucket, 'labelValues' => $labelValues)); + if (!isset($raw[$bucketKey])) { + $histogram['samples'][] = array( + 'name' => $histogram['name'] . '_bucket', + 'labelNames' => array('le'), + 'labelValues' => array_merge($labelValues, array($bucket)), + 'value' => $acc + ); + } else { + $acc += $raw[$bucketKey]; + $histogram['samples'][] = array( + 'name' => $histogram['name'] . '_bucket', + 'labelNames' => array('le'), + 'labelValues' => array_merge($labelValues, array($bucket)), + 'value' => $acc + ); + } + } + + // Add the count + $histogram['samples'][] = array( + 'name' => $histogram['name'] . '_count', + 'labelNames' => array(), + 'labelValues' => $labelValues, + 'value' => $acc + ); + + // Add the sum + $histogram['samples'][] = array( + 'name' => $histogram['name'] . '_sum', + 'labelNames' => array(), + 'labelValues' => $labelValues, + 'value' => $raw[json_encode(array('b' => 'sum', 'labelValues' => $labelValues))] + ); + } + $histograms[] = $histogram; + } + return $histograms; + } + + private function collectGauges() + { + $keys = $this->predis->smembers(self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + sort($keys); + $gauges = array(); + foreach ($keys as $key) { + $raw = $this->predis->hgetall($key); + $gauge = json_decode($raw['__meta'], true); + unset($raw['__meta']); + $gauge['samples'] = array(); + foreach ($raw as $k => $value) { + $gauge['samples'][] = array( + 'name' => $gauge['name'], + 'labelNames' => array(), + 'labelValues' => json_decode($k, true), + 'value' => $value + ); + } + usort($gauge['samples'], function($a, $b){ + return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); + }); + $gauges[] = $gauge; + } + return $gauges; + } + + private function collectCounters() + { + $keys = $this->predis->smembers(self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + sort($keys); + $counters = array(); + foreach ($keys as $key) { + $raw = $this->predis->hgetall($key); + $counter = json_decode($raw['__meta'], true); + unset($raw['__meta']); + $counter['samples'] = array(); + foreach ($raw as $k => $value) { + $counter['samples'][] = array( + 'name' => $counter['name'], + 'labelNames' => array(), + 'labelValues' => json_decode($k, true), + 'value' => $value + ); + } + usort($counter['samples'], function($a, $b){ + return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); + }); + $counters[] = $counter; + } + return $counters; + } + + private function getRedisCommand($cmd) + { + switch ($cmd) { + case Adapter::COMMAND_INCREMENT_INTEGER: + return 'hIncrBy'; + case Adapter::COMMAND_INCREMENT_FLOAT: + return 'hIncrByFloat'; + case Adapter::COMMAND_SET: + return 'hSet'; + default: + throw new \InvalidArgumentException("Unknown command"); + } + } + + /** + * @param array $data + * @return string + */ + private function toMetricKey(array $data) + { + return implode(':', array(self::$prefix, $data['type'], $data['name'])); + } +} diff --git a/tests/Test/BlackBoxPushGatewayTest.php b/tests/Test/BlackBoxPushGatewayTest.php index 26490c6..8fb793c 100644 --- a/tests/Test/BlackBoxPushGatewayTest.php +++ b/tests/Test/BlackBoxPushGatewayTest.php @@ -33,7 +33,7 @@ public function pushGatewayShouldWork() $metrics ); - $pushGateway->delete('my_job', array('instance' => 'foo')); + $pushGateway->delete($registry,'my_job', array('instance' => 'foo')); $httpClient = new Client(); $metrics = $httpClient->get("http://pushgateway:9091/metrics")->getBody()->getContents(); diff --git a/tests/Test/Prometheus/Predis/CollectorRegistryTest.php b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php new file mode 100644 index 0000000..1c1c038 --- /dev/null +++ b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php @@ -0,0 +1,16 @@ +adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Predis/CounterTest.php b/tests/Test/Prometheus/Predis/CounterTest.php new file mode 100644 index 0000000..eed8bbd --- /dev/null +++ b/tests/Test/Prometheus/Predis/CounterTest.php @@ -0,0 +1,20 @@ +adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Predis/GaugeTest.php b/tests/Test/Prometheus/Predis/GaugeTest.php new file mode 100644 index 0000000..064676b --- /dev/null +++ b/tests/Test/Prometheus/Predis/GaugeTest.php @@ -0,0 +1,20 @@ +adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Predis/HistogramTest.php b/tests/Test/Prometheus/Predis/HistogramTest.php new file mode 100644 index 0000000..474c203 --- /dev/null +++ b/tests/Test/Prometheus/Predis/HistogramTest.php @@ -0,0 +1,20 @@ +adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter->flushRedis(); + } +} From 5f5113a3b0e6332fd5f56b7ad712b62b5c87e3be Mon Sep 17 00:00:00 2001 From: Sergey Protko Date: Wed, 27 Sep 2017 17:01:50 +0300 Subject: [PATCH 2/3] Remove handling of connection from predis adapter --- examples/flush_adapter.php | 6 +- examples/metrics.php | 6 +- examples/pushgateway.php | 6 +- examples/some_counter.php | 6 +- examples/some_gauge.php | 6 +- examples/some_histogram.php | 6 +- src/Prometheus/Storage/Predis.php | 70 +++---------------- .../Predis/CollectorRegistryTest.php | 2 +- tests/Test/Prometheus/Predis/CounterTest.php | 2 +- tests/Test/Prometheus/Predis/GaugeTest.php | 2 +- .../Test/Prometheus/Predis/HistogramTest.php | 2 +- 11 files changed, 33 insertions(+), 81 deletions(-) diff --git a/examples/flush_adapter.php b/examples/flush_adapter.php index a2f98c0..9433765 100644 --- a/examples/flush_adapter.php +++ b/examples/flush_adapter.php @@ -9,9 +9,9 @@ $redisAdapter = new Prometheus\Storage\Redis(array('host' => REDIS_HOST)); $redisAdapter->flushRedis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); $adapter->flushRedis(); } elseif ($adapter === 'apc') { $apcAdapter = new Prometheus\Storage\APC(); diff --git a/examples/metrics.php b/examples/metrics.php index 76c834a..f816bd8 100644 --- a/examples/metrics.php +++ b/examples/metrics.php @@ -12,9 +12,9 @@ Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/pushgateway.php b/examples/pushgateway.php index 6c4d789..51438f6 100644 --- a/examples/pushgateway.php +++ b/examples/pushgateway.php @@ -10,9 +10,9 @@ Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_counter.php b/examples/some_counter.php index 58fc6ff..0c52cd1 100644 --- a/examples/some_counter.php +++ b/examples/some_counter.php @@ -11,9 +11,9 @@ Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_gauge.php b/examples/some_gauge.php index b847131..7573761 100644 --- a/examples/some_gauge.php +++ b/examples/some_gauge.php @@ -14,9 +14,9 @@ Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/examples/some_histogram.php b/examples/some_histogram.php index a618cbe..9a75a46 100644 --- a/examples/some_histogram.php +++ b/examples/some_histogram.php @@ -13,9 +13,9 @@ Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis([ - 'host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1' - ]); + $adapter = new Prometheus\Storage\Predis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); } elseif ($adapter === 'in-memory') { diff --git a/src/Prometheus/Storage/Predis.php b/src/Prometheus/Storage/Predis.php index d4a3258..bff5208 100644 --- a/src/Prometheus/Storage/Predis.php +++ b/src/Prometheus/Storage/Predis.php @@ -13,33 +13,16 @@ class Predis implements Adapter { const PROMETHEUS_METRIC_KEYS_SUFFIX = '_METRIC_KEYS'; - private static $defaultOptions = [ - 'host' => '127.0.0.1', - 'port' => 6379, - 'timeout' => 0.1, - 'read_timeout' => 10, - 'persistent_connections' => false, - ]; - private static $prefix = 'PROMETHEUS_'; - private $options; /** * @var Client */ private $predis; - public function __construct(array $options = array()) + public function __construct(Client $predis) { - $this->options = array_merge(self::$defaultOptions, $options); - } - - /** - * @param array $options - */ - public static function setDefaultOptions(array $options) - { - self::$defaultOptions = array_merge(self::$defaultOptions, $options); + $this->predis = $predis; } public static function setPrefix($prefix) @@ -49,7 +32,6 @@ public static function setPrefix($prefix) public function flushRedis() { - $this->openConnection(); $this->predis->flushall(); } @@ -59,7 +41,6 @@ public function flushRedis() */ public function collect() { - $this->openConnection(); $metrics = $this->collectHistograms(); $metrics = array_merge($metrics, $this->collectGauges()); $metrics = array_merge($metrics, $this->collectCounters()); @@ -71,30 +52,8 @@ function (array $metric) { ); } - /** - * @throws StorageException - */ - private function openConnection() - { - try { - - $this->predis = new Client([ - 'scheme' => 'tcp', - 'host' => $this->options['host'], - 'port' => $this->options['port'], - 'timeout' => $this->options['timeout'], - 'read_write_timeout' => $this->options['read_timeout'], - 'persistent' => $this->options['persistent_connections'], - ]); - - } catch (\RedisException $e) { - throw new StorageException("Can't connect to Redis server", 0, $e); - } - } - public function updateHistogram(array $data) { - $this->openConnection(); $bucketToIncrease = '+Inf'; foreach ($data['buckets'] as $bucket) { if ($data['value'] <= $bucket) { @@ -105,6 +64,7 @@ public function updateHistogram(array $data) $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); + $this->predis->eval(<<openConnection(); $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); @@ -159,7 +118,6 @@ public function updateGauge(array $data) public function updateCounter(array $data) { - $this->openConnection(); $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); @@ -219,22 +177,16 @@ private function collectHistograms() $acc = 0; foreach ($histogram['buckets'] as $bucket) { $bucketKey = json_encode(array('b' => $bucket, 'labelValues' => $labelValues)); - if (!isset($raw[$bucketKey])) { - $histogram['samples'][] = array( - 'name' => $histogram['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($labelValues, array($bucket)), - 'value' => $acc - ); - } else { + if (isset($raw[$bucketKey])) { $acc += $raw[$bucketKey]; - $histogram['samples'][] = array( - 'name' => $histogram['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($labelValues, array($bucket)), - 'value' => $acc - ); } + + $histogram['samples'][] = array( + 'name' => $histogram['name'] . '_bucket', + 'labelNames' => array('le'), + 'labelValues' => array_merge($labelValues, array($bucket)), + 'value' => $acc + ); } // Add the count diff --git a/tests/Test/Prometheus/Predis/CollectorRegistryTest.php b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php index 1c1c038..9bb836b 100644 --- a/tests/Test/Prometheus/Predis/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php @@ -10,7 +10,7 @@ class CollectorRegistryTest extends AbstractCollectorRegistryTest { public function configureAdapter() { - $this->adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Predis/CounterTest.php b/tests/Test/Prometheus/Predis/CounterTest.php index eed8bbd..7568ff6 100644 --- a/tests/Test/Prometheus/Predis/CounterTest.php +++ b/tests/Test/Prometheus/Predis/CounterTest.php @@ -14,7 +14,7 @@ class CounterTest extends AbstractCounterTest public function configureAdapter() { - $this->adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Predis/GaugeTest.php b/tests/Test/Prometheus/Predis/GaugeTest.php index 064676b..fe14939 100644 --- a/tests/Test/Prometheus/Predis/GaugeTest.php +++ b/tests/Test/Prometheus/Predis/GaugeTest.php @@ -14,7 +14,7 @@ class GaugeTest extends AbstractGaugeTest public function configureAdapter() { - $this->adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Predis/HistogramTest.php b/tests/Test/Prometheus/Predis/HistogramTest.php index 474c203..caa7397 100644 --- a/tests/Test/Prometheus/Predis/HistogramTest.php +++ b/tests/Test/Prometheus/Predis/HistogramTest.php @@ -14,7 +14,7 @@ class HistogramTest extends AbstractHistogramTest public function configureAdapter() { - $this->adapter = new Predis(array('host' => REDIS_HOST)); + $this->adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); $this->adapter->flushRedis(); } } From e2d1074c978fbcbf759b0372631397250153576f Mon Sep 17 00:00:00 2001 From: Sergey Protko Date: Mon, 26 Feb 2018 23:31:27 +0300 Subject: [PATCH 3/3] Introduce redis client adapter - Encapsulate differences between predis and redis behind single abstraction. - Reduce duplication in tests --- examples/flush_adapter.php | 22 +- examples/initialize.php | 21 ++ examples/metrics.php | 14 +- examples/pushgateway.php | 15 +- examples/some_counter.php | 15 +- examples/some_gauge.php | 15 +- examples/some_histogram.php | 15 +- src/Prometheus/Storage/Predis.php | 287 ------------------ src/Prometheus/Storage/Redis.php | 98 ++---- src/Prometheus/Storage/RedisAdapter.php | 119 ++++++++ .../Predis/CollectorRegistryTest.php | 8 +- tests/Test/Prometheus/Predis/CounterTest.php | 9 +- tests/Test/Prometheus/Predis/GaugeTest.php | 9 +- .../Test/Prometheus/Predis/HistogramTest.php | 9 +- .../Prometheus/Predis/InitializationTrait.php | 17 ++ .../Redis/CollectorRegistryTest.php | 8 +- tests/Test/Prometheus/Redis/CounterTest.php | 9 +- tests/Test/Prometheus/Redis/GaugeTest.php | 9 +- tests/Test/Prometheus/Redis/HistogramTest.php | 9 +- .../Prometheus/Redis/InitializationTrait.php | 17 ++ .../{RedisTest.php => RedisAdapterTest.php} | 6 +- 21 files changed, 226 insertions(+), 505 deletions(-) create mode 100644 examples/initialize.php delete mode 100644 src/Prometheus/Storage/Predis.php create mode 100644 src/Prometheus/Storage/RedisAdapter.php create mode 100644 tests/Test/Prometheus/Predis/InitializationTrait.php create mode 100644 tests/Test/Prometheus/Redis/InitializationTrait.php rename tests/Test/Prometheus/Storage/{RedisTest.php => RedisAdapterTest.php} (61%) diff --git a/examples/flush_adapter.php b/examples/flush_adapter.php index 9433765..4c7eecf 100644 --- a/examples/flush_adapter.php +++ b/examples/flush_adapter.php @@ -1,22 +1,12 @@ REDIS_HOST)); - $redisAdapter->flushRedis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); +if ($adapter instanceof \Prometheus\Storage\Redis) { $adapter->flushRedis(); -} elseif ($adapter === 'apc') { - $apcAdapter = new Prometheus\Storage\APC(); - $apcAdapter->flushAPC(); -} elseif ($adapter === 'in-memory') { - $inMemoryAdapter = new Prometheus\Storage\InMemory(); - $inMemoryAdapter->flushMemory(); +} elseif ($adapter instanceof \Prometheus\Storage\APC) { + $adapter->flushAPC(); +} elseif ($adapter instanceof \Prometheus\Storage\InMemory) { + $adapter->flushMemory(); } \ No newline at end of file diff --git a/examples/initialize.php b/examples/initialize.php new file mode 100644 index 0000000..406119d --- /dev/null +++ b/examples/initialize.php @@ -0,0 +1,21 @@ + isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1') + ); + case "predis": + return Prometheus\Storage\Redis::usingPredis( + new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) + ); + case "apc": + return new Prometheus\Storage\APC(); + case "in-memory": + return new Prometheus\Storage\InMemory(); + default: + throw new \RuntimeException(sprintf('Adapter "" is not supported', $adapterName)); +} diff --git a/examples/metrics.php b/examples/metrics.php index f816bd8..6742112 100644 --- a/examples/metrics.php +++ b/examples/metrics.php @@ -6,20 +6,8 @@ use Prometheus\RenderTextFormat; use Prometheus\Storage\Redis; -$adapter = $_GET['adapter']; +$adapter = require __DIR__ . '/initialize.php'; -if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); - $adapter = new Prometheus\Storage\Redis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); -} elseif ($adapter === 'apc') { - $adapter = new Prometheus\Storage\APC(); -} elseif ($adapter === 'in-memory') { - $adapter = new Prometheus\Storage\InMemory(); -} $registry = new CollectorRegistry($adapter); $renderer = new RenderTextFormat(); $result = $renderer->render($registry->getMetricFamilySamples()); diff --git a/examples/pushgateway.php b/examples/pushgateway.php index 51438f6..b69e9af 100644 --- a/examples/pushgateway.php +++ b/examples/pushgateway.php @@ -4,20 +4,7 @@ use Prometheus\Storage\Redis; use Prometheus\CollectorRegistry; -$adapter = $_GET['adapter']; - -if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); - $adapter = new Prometheus\Storage\Redis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); -} elseif ($adapter === 'apc') { - $adapter = new Prometheus\Storage\APC(); -} elseif ($adapter === 'in-memory') { - $adapter = new Prometheus\Storage\InMemory(); -} +$adapter = require __DIR__ . '/initialize.php'; $registry = new CollectorRegistry($adapter); diff --git a/examples/some_counter.php b/examples/some_counter.php index 0c52cd1..3851e7c 100644 --- a/examples/some_counter.php +++ b/examples/some_counter.php @@ -5,20 +5,7 @@ use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; -$adapter = $_GET['adapter']; - -if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); - $adapter = new Prometheus\Storage\Redis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); -} elseif ($adapter === 'apc') { - $adapter = new Prometheus\Storage\APC(); -} elseif ($adapter === 'in-memory') { - $adapter = new Prometheus\Storage\InMemory(); -} +$adapter = require __DIR__ . '/initialize.php'; $registry = new CollectorRegistry($adapter); $counter = $registry->registerCounter('test', 'some_counter', 'it increases', ['type']); diff --git a/examples/some_gauge.php b/examples/some_gauge.php index 7573761..a128cb2 100644 --- a/examples/some_gauge.php +++ b/examples/some_gauge.php @@ -8,20 +8,7 @@ error_log('c='. $_GET['c']); -$adapter = $_GET['adapter']; - -if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); - $adapter = new Prometheus\Storage\Redis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); -} elseif ($adapter === 'apc') { - $adapter = new Prometheus\Storage\APC(); -} elseif ($adapter === 'in-memory') { - $adapter = new Prometheus\Storage\InMemory(); -} +$adapter = require __DIR__ . '/initialize.php'; $registry = new CollectorRegistry($adapter); $gauge = $registry->registerGauge('test', 'some_gauge', 'it sets', ['type']); diff --git a/examples/some_histogram.php b/examples/some_histogram.php index 9a75a46..0157c7c 100644 --- a/examples/some_histogram.php +++ b/examples/some_histogram.php @@ -7,20 +7,7 @@ error_log('c='. $_GET['c']); -$adapter = $_GET['adapter']; - -if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); - $adapter = new Prometheus\Storage\Redis(); -} elseif ($adapter === 'predis') { - $adapter = new Prometheus\Storage\Predis( - new \Predis\Client(['host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1']) - ); -} elseif ($adapter === 'apc') { - $adapter = new Prometheus\Storage\APC(); -} elseif ($adapter === 'in-memory') { - $adapter = new Prometheus\Storage\InMemory(); -} +$adapter = require __DIR__ . '/initialize.php'; $registry = new CollectorRegistry($adapter); $histogram = $registry->registerHistogram('test', 'some_histogram', 'it observes', ['type'], [0.1, 1, 2, 3.5, 4, 5, 6, 7, 8, 9]); diff --git a/src/Prometheus/Storage/Predis.php b/src/Prometheus/Storage/Predis.php deleted file mode 100644 index bff5208..0000000 --- a/src/Prometheus/Storage/Predis.php +++ /dev/null @@ -1,287 +0,0 @@ -predis = $predis; - } - - public static function setPrefix($prefix) - { - self::$prefix = $prefix; - } - - public function flushRedis() - { - $this->predis->flushall(); - } - - /** - * @return MetricFamilySamples[] - * @throws StorageException - */ - public function collect() - { - $metrics = $this->collectHistograms(); - $metrics = array_merge($metrics, $this->collectGauges()); - $metrics = array_merge($metrics, $this->collectCounters()); - return array_map( - function (array $metric) { - return new MetricFamilySamples($metric); - }, - $metrics - ); - } - - public function updateHistogram(array $data) - { - $bucketToIncrease = '+Inf'; - foreach ($data['buckets'] as $bucket) { - if ($data['value'] <= $bucket) { - $bucketToIncrease = $bucket; - break; - } - } - $metaData = $data; - unset($metaData['value']); - unset($metaData['labelValues']); - - $this->predis->eval(<<toMetricKey($data), - json_encode(array('b' => 'sum', 'labelValues' => $data['labelValues'])), - json_encode(array('b' => $bucketToIncrease, 'labelValues' => $data['labelValues'])), - self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, - $data['value'], - json_encode($metaData) - ); - } - - public function updateGauge(array $data) - { - $metaData = $data; - unset($metaData['value']); - unset($metaData['labelValues']); - unset($metaData['command']); - $this->predis->eval(<<toMetricKey($data), - $this->getRedisCommand($data['command']), - self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, - json_encode($data['labelValues']), - $data['value'], - json_encode($metaData) - ); - } - - public function updateCounter(array $data) - { - $metaData = $data; - unset($metaData['value']); - unset($metaData['labelValues']); - unset($metaData['command']); - $result = $this->predis->eval(<<toMetricKey($data), - $this->getRedisCommand($data['command']), - self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, - json_encode($data['labelValues']), - $data['value'], - json_encode($metaData) - ); - return $result; - } - - private function collectHistograms() - { - $keys = $this->predis->smembers(self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); - sort($keys); - $histograms = array(); - foreach ($keys as $key) { - $raw = $this->predis->hgetall($key); - $histogram = json_decode($raw['__meta'], true); - unset($raw['__meta']); - $histogram['samples'] = array(); - - // Add the Inf bucket so we can compute it later on - $histogram['buckets'][] = '+Inf'; - - $allLabelValues = array(); - foreach (array_keys($raw) as $k) { - $d = json_decode($k, true); - if ($d['b'] == 'sum') { - continue; - } - $allLabelValues[] = $d['labelValues']; - } - - // We need set semantics. - // This is the equivalent of array_unique but for arrays of arrays. - $allLabelValues = array_map("unserialize", array_unique(array_map("serialize", $allLabelValues))); - sort($allLabelValues); - - foreach ($allLabelValues as $labelValues) { - // Fill up all buckets. - // If the bucket doesn't exist fill in values from - // the previous one. - $acc = 0; - foreach ($histogram['buckets'] as $bucket) { - $bucketKey = json_encode(array('b' => $bucket, 'labelValues' => $labelValues)); - if (isset($raw[$bucketKey])) { - $acc += $raw[$bucketKey]; - } - - $histogram['samples'][] = array( - 'name' => $histogram['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($labelValues, array($bucket)), - 'value' => $acc - ); - } - - // Add the count - $histogram['samples'][] = array( - 'name' => $histogram['name'] . '_count', - 'labelNames' => array(), - 'labelValues' => $labelValues, - 'value' => $acc - ); - - // Add the sum - $histogram['samples'][] = array( - 'name' => $histogram['name'] . '_sum', - 'labelNames' => array(), - 'labelValues' => $labelValues, - 'value' => $raw[json_encode(array('b' => 'sum', 'labelValues' => $labelValues))] - ); - } - $histograms[] = $histogram; - } - return $histograms; - } - - private function collectGauges() - { - $keys = $this->predis->smembers(self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); - sort($keys); - $gauges = array(); - foreach ($keys as $key) { - $raw = $this->predis->hgetall($key); - $gauge = json_decode($raw['__meta'], true); - unset($raw['__meta']); - $gauge['samples'] = array(); - foreach ($raw as $k => $value) { - $gauge['samples'][] = array( - 'name' => $gauge['name'], - 'labelNames' => array(), - 'labelValues' => json_decode($k, true), - 'value' => $value - ); - } - usort($gauge['samples'], function($a, $b){ - return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); - }); - $gauges[] = $gauge; - } - return $gauges; - } - - private function collectCounters() - { - $keys = $this->predis->smembers(self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); - sort($keys); - $counters = array(); - foreach ($keys as $key) { - $raw = $this->predis->hgetall($key); - $counter = json_decode($raw['__meta'], true); - unset($raw['__meta']); - $counter['samples'] = array(); - foreach ($raw as $k => $value) { - $counter['samples'][] = array( - 'name' => $counter['name'], - 'labelNames' => array(), - 'labelValues' => json_decode($k, true), - 'value' => $value - ); - } - usort($counter['samples'], function($a, $b){ - return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); - }); - $counters[] = $counter; - } - return $counters; - } - - private function getRedisCommand($cmd) - { - switch ($cmd) { - case Adapter::COMMAND_INCREMENT_INTEGER: - return 'hIncrBy'; - case Adapter::COMMAND_INCREMENT_FLOAT: - return 'hIncrByFloat'; - case Adapter::COMMAND_SET: - return 'hSet'; - default: - throw new \InvalidArgumentException("Unknown command"); - } - } - - /** - * @param array $data - * @return string - */ - private function toMetricKey(array $data) - { - return implode(':', array(self::$prefix, $data['type'], $data['name'])); - } -} diff --git a/src/Prometheus/Storage/Redis.php b/src/Prometheus/Storage/Redis.php index f38391b..d433266 100644 --- a/src/Prometheus/Storage/Redis.php +++ b/src/Prometheus/Storage/Redis.php @@ -3,6 +3,7 @@ namespace Prometheus\Storage; +use Predis\Client; use Prometheus\Counter; use Prometheus\Exception\StorageException; use Prometheus\Gauge; @@ -13,55 +14,40 @@ class Redis implements Adapter { const PROMETHEUS_METRIC_KEYS_SUFFIX = '_METRIC_KEYS'; - private static $defaultOptions = array(); - private static $prefix = 'PROMETHEUS_'; + private $prefix = 'PROMETHEUS_'; - private $options; private $redis; - public function __construct(array $options = array()) + /** + * Redis constructor. + * @param RedisAdapter $redis + * @param string $prefix + */ + public function __construct(RedisAdapter $redis, $prefix = 'PROMETHEUS_') { - // with php 5.3 we cannot initialize the options directly on the field definition - // so we initialize them here for now - if (!isset(self::$defaultOptions['host'])) { - self::$defaultOptions['host'] = '127.0.0.1'; - } - if (!isset(self::$defaultOptions['port'])) { - self::$defaultOptions['port'] = 6379; - } - if (!isset(self::$defaultOptions['timeout'])) { - self::$defaultOptions['timeout'] = 0.1; // in seconds - } - if (!isset(self::$defaultOptions['read_timeout'])) { - self::$defaultOptions['read_timeout'] = 10; // in seconds - } - if (!isset(self::$defaultOptions['persistent_connections'])) { - self::$defaultOptions['persistent_connections'] = false; - } - if (!isset(self::$defaultOptions['password'])) { - self::$defaultOptions['password'] = null; - } - - $this->options = array_merge(self::$defaultOptions, $options); - $this->redis = new \Redis(); + $this->redis = $redis; } /** - * @param array $options + * @param string $prefix */ - public static function setDefaultOptions(array $options) + public function setPrefix($prefix) + { + $this->prefix = $prefix; + } + + public static function usingRedis(\Redis $redis, array $options) { - self::$defaultOptions = array_merge(self::$defaultOptions, $options); + return new self(RedisAdapter::forRedis($redis, $options)); } - public static function setPrefix($prefix) + public static function usingPredis(Client $redis) { - self::$prefix = $prefix; + return new self(RedisAdapter::forPredis($redis)); } public function flushRedis() { - $this->openConnection(); $this->redis->flushAll(); } @@ -71,7 +57,6 @@ public function flushRedis() */ public function collect() { - $this->openConnection(); $metrics = $this->collectHistograms(); $metrics = array_merge($metrics, $this->collectGauges()); $metrics = array_merge($metrics, $this->collectCounters()); @@ -83,29 +68,8 @@ function (array $metric) { ); } - /** - * @throws StorageException - */ - private function openConnection() - { - try { - if ($this->options['persistent_connections']) { - @$this->redis->pconnect($this->options['host'], $this->options['port'], $this->options['timeout']); - } else { - @$this->redis->connect($this->options['host'], $this->options['port'], $this->options['timeout']); - } - if ($this->options['password']) { - $this->redis->auth($this->options['password']); - } - $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->options['read_timeout']); - } catch (\RedisException $e) { - throw new StorageException("Can't connect to Redis server", 0, $e); - } - } - public function updateHistogram(array $data) { - $this->openConnection(); $bucketToIncrease = '+Inf'; foreach ($data['buckets'] as $bucket) { if ($data['value'] <= $bucket) { @@ -116,7 +80,7 @@ public function updateHistogram(array $data) $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); - $this->redis->eval(<<redis->evaluate(<<toMetricKey($data), json_encode(array('b' => 'sum', 'labelValues' => $data['labelValues'])), json_encode(array('b' => $bucketToIncrease, 'labelValues' => $data['labelValues'])), - self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + $this->prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, $data['value'], json_encode($metaData), ), @@ -139,12 +103,12 @@ public function updateHistogram(array $data) public function updateGauge(array $data) { - $this->openConnection(); + $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); unset($metaData['command']); - $this->redis->eval(<<redis->evaluate(<<toMetricKey($data), $this->getRedisCommand($data['command']), - self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + $this->prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, json_encode($data['labelValues']), $data['value'], json_encode($metaData), @@ -174,12 +138,11 @@ public function updateGauge(array $data) public function updateCounter(array $data) { - $this->openConnection(); $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); unset($metaData['command']); - $result = $this->redis->eval(<<redis->evaluate(<<toMetricKey($data), $this->getRedisCommand($data['command']), - self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + $this->prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, json_encode($data['labelValues']), $data['value'], json_encode($metaData), @@ -203,7 +166,7 @@ public function updateCounter(array $data) private function collectHistograms() { - $keys = $this->redis->sMembers(self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + $keys = $this->redis->sMembers($this->prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); $histograms = array(); foreach ($keys as $key) { @@ -277,7 +240,7 @@ private function collectHistograms() private function collectGauges() { - $keys = $this->redis->sMembers(self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + $keys = $this->redis->sMembers($this->prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); $gauges = array(); foreach ($keys as $key) { @@ -303,7 +266,7 @@ private function collectGauges() private function collectCounters() { - $keys = $this->redis->sMembers(self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); + $keys = $this->redis->sMembers($this->prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); $counters = array(); foreach ($keys as $key) { @@ -347,7 +310,6 @@ private function getRedisCommand($cmd) */ private function toMetricKey(array $data) { - return implode(':', array(self::$prefix, $data['type'], $data['name'])); + return implode(':', array($this->prefix, $data['type'], $data['name'])); } - } diff --git a/src/Prometheus/Storage/RedisAdapter.php b/src/Prometheus/Storage/RedisAdapter.php new file mode 100644 index 0000000..c7d16ad --- /dev/null +++ b/src/Prometheus/Storage/RedisAdapter.php @@ -0,0 +1,119 @@ +options = array_replace([ + 'host' => '127.0.0.1', + 'port' => 6379, + 'timeout' => 0.1, + 'read_timeout' => 10, + 'persistent_connections' => false, + 'password' => null, + ], $options); + + return $adapter; + } + + /** + * @param Client $client + * @return RedisAdapter + */ + public static function forPredis(Client $client) + { + return new self($client); + } + + /** + * @param \Redis|Client $redisInstance + */ + private function __construct($redisInstance) + { + $this->redis = $redisInstance; + } + + /** + * @param string $script + * @param array $args + * @param int $numKeys + */ + public function evaluate($script, $args = array(), $numKeys = 0) + { + if ($this->redis instanceof Client) { + $this->redis->eval($script, $numKeys, ...$args); + return; + } + + $this->openConnection(); + $this->redis->eval($script, $args, $numKeys); + } + + /** + * @param string $key + * @return array + */ + public function sMembers($key) + { + $this->openConnection(); + return $this->redis->smembers($key); + } + + /** + * @param string $key + * @return array + */ + public function hGetAll($key) + { + $this->openConnection(); + return $this->redis->hgetall($key); + } + + public function flushAll() + { + $this->openConnection(); + $this->redis->flushall(); + } + + /** + * @throws StorageException + */ + private function openConnection() + { + if ($this->redis instanceof Client) { + return; + } + + try { + if ($this->options['persistent_connections']) { + @$this->redis->pconnect($this->options['host'], $this->options['port'], $this->options['timeout']); + } else { + @$this->redis->connect($this->options['host'], $this->options['port'], $this->options['timeout']); + } + if ($this->options['password']) { + $this->redis->auth($this->options['password']); + } + $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->options['read_timeout']); + } catch (\RedisException $e) { + throw new StorageException("Can't connect to Redis server", 0, $e); + } + } +} \ No newline at end of file diff --git a/tests/Test/Prometheus/Predis/CollectorRegistryTest.php b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php index 9bb836b..a6acda5 100644 --- a/tests/Test/Prometheus/Predis/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/Predis/CollectorRegistryTest.php @@ -1,16 +1,10 @@ adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Predis/CounterTest.php b/tests/Test/Prometheus/Predis/CounterTest.php index 7568ff6..3d2eb8c 100644 --- a/tests/Test/Prometheus/Predis/CounterTest.php +++ b/tests/Test/Prometheus/Predis/CounterTest.php @@ -1,9 +1,7 @@ adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Predis/GaugeTest.php b/tests/Test/Prometheus/Predis/GaugeTest.php index fe14939..bb40755 100644 --- a/tests/Test/Prometheus/Predis/GaugeTest.php +++ b/tests/Test/Prometheus/Predis/GaugeTest.php @@ -1,9 +1,7 @@ adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Predis/HistogramTest.php b/tests/Test/Prometheus/Predis/HistogramTest.php index caa7397..a8a0fe8 100644 --- a/tests/Test/Prometheus/Predis/HistogramTest.php +++ b/tests/Test/Prometheus/Predis/HistogramTest.php @@ -1,9 +1,7 @@ adapter = new Predis(new \Predis\Client(['host' => REDIS_HOST])); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Predis/InitializationTrait.php b/tests/Test/Prometheus/Predis/InitializationTrait.php new file mode 100644 index 0000000..b642984 --- /dev/null +++ b/tests/Test/Prometheus/Predis/InitializationTrait.php @@ -0,0 +1,17 @@ +adapter = Redis::usingPredis( + new Client(['host' => REDIS_HOST]) + ); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Redis/CollectorRegistryTest.php b/tests/Test/Prometheus/Redis/CollectorRegistryTest.php index ed2ad2b..7261005 100644 --- a/tests/Test/Prometheus/Redis/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/Redis/CollectorRegistryTest.php @@ -1,16 +1,10 @@ adapter = new Redis(array('host' => REDIS_HOST)); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Redis/CounterTest.php b/tests/Test/Prometheus/Redis/CounterTest.php index 0d78272..4e9bc15 100644 --- a/tests/Test/Prometheus/Redis/CounterTest.php +++ b/tests/Test/Prometheus/Redis/CounterTest.php @@ -1,9 +1,7 @@ adapter = new Redis(array('host' => REDIS_HOST)); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Redis/GaugeTest.php b/tests/Test/Prometheus/Redis/GaugeTest.php index 17d0c44..952a259 100644 --- a/tests/Test/Prometheus/Redis/GaugeTest.php +++ b/tests/Test/Prometheus/Redis/GaugeTest.php @@ -1,9 +1,7 @@ adapter = new Redis(array('host' => REDIS_HOST)); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Redis/HistogramTest.php b/tests/Test/Prometheus/Redis/HistogramTest.php index 57f73f6..e95b0b0 100644 --- a/tests/Test/Prometheus/Redis/HistogramTest.php +++ b/tests/Test/Prometheus/Redis/HistogramTest.php @@ -1,9 +1,7 @@ adapter = new Redis(array('host' => REDIS_HOST)); - $this->adapter->flushRedis(); - } + use InitializationTrait; } diff --git a/tests/Test/Prometheus/Redis/InitializationTrait.php b/tests/Test/Prometheus/Redis/InitializationTrait.php new file mode 100644 index 0000000..ffa5997 --- /dev/null +++ b/tests/Test/Prometheus/Redis/InitializationTrait.php @@ -0,0 +1,17 @@ +adapter = Redis::usingRedis( + new \Redis(), + array('host' => REDIS_HOST) + ); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Storage/RedisTest.php b/tests/Test/Prometheus/Storage/RedisAdapterTest.php similarity index 61% rename from tests/Test/Prometheus/Storage/RedisTest.php rename to tests/Test/Prometheus/Storage/RedisAdapterTest.php index 8eb1654..0db173c 100644 --- a/tests/Test/Prometheus/Storage/RedisTest.php +++ b/tests/Test/Prometheus/Storage/RedisAdapterTest.php @@ -4,7 +4,7 @@ namespace Prometheus\Storage; -class RedisTest extends \PHPUnit_Framework_TestCase +class RedisAdapterTest extends \PHPUnit_Framework_TestCase { /** * @test @@ -13,8 +13,8 @@ class RedisTest extends \PHPUnit_Framework_TestCase */ public function itShouldThrowAnExceptionOnConnectionFailure() { - $redis = new Redis(array('host' => 'doesntexist.test')); - $redis->flushRedis(); + $redis = RedisAdapter::forRedis(new \Redis, ['host' => 'doesntexist.test']); + $redis->hGetAll('test'); } }