diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..2d1525e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,103 @@ +unit-config: &unit-config + environment: + COMPOSER_PREFER_LOWEST: 0 + steps: + - checkout + + - run: + name: Install latest composer + command: | + php -r "copy('https://raw.githubusercontent.com/composer/getcomposer.org/master/web/installer', 'composer-setup.php');" + php composer-setup.php + php -r "unlink('composer-setup.php');" + mv composer.phar /usr/local/bin/composer + + - run: + name: Write COMPOSER_PREFER_LOWEST to file + command: echo "$COMPOSER_PREFER_LOWEST" > ~/COMPOSER_PREFER_LOWEST.txt + + # Download and cache dependencies + - restore_cache: + keys: + - v1-composer-cache-{{ checksum "~/COMPOSER_PREFER_LOWEST.txt" }}-{{ checksum "composer.json" }} + # Fall back to using the latest cache if no exact match is found. + - v1-composer-cache-{{ checksum "~/COMPOSER_PREFER_LOWEST.txt" }} + + - run: + name: Validate composer files + command: composer validate --strict + + - run: + name: Install PHP extensions + command: | + printf '\n' | sudo pecl install redis + sudo docker-php-ext-enable redis + + - run: + name: Install composer packages + command: | + if [ $COMPOSER_PREFER_LOWEST -eq "1" ]; then + composer update --no-ansi --no-progress --optimize-autoloader --no-interaction --no-plugins --no-scripts --prefer-dist --prefer-stable --prefer-lowest + else + composer update --no-ansi --no-progress --optimize-autoloader --no-interaction --no-plugins --no-scripts --prefer-dist --prefer-stable + fi + + - save_cache: + key: v1-composer-cache-{{ checksum "~/COMPOSER_PREFER_LOWEST.txt" }}-{{ checksum "composer.json" }} + paths: + - ./vendor + + - run: + name: Wait for backing services to start + command: dockerize -wait tcp://127.0.0.1:6379 -timeout 30s + + - run: + name: Run PHP Code Sniffer + command: ./vendor/bin/phpcs + + - run: + name: Run tests + command: ./vendor/bin/phpunit + +version: 2.1 +jobs: + php74: + <<: *unit-config + docker: + - image: circleci/php:7.4-cli-node + - image: circleci/redis:5-alpine + environment: + COMPOSER_PREFER_LOWEST: 0 + + php74-lowest: + <<: *unit-config + docker: + - image: circleci/php:7.4-cli-node + - image: circleci/redis:5-alpine + environment: + COMPOSER_PREFER_LOWEST: 1 + + php73: + <<: *unit-config + docker: + - image: circleci/php:7.3-cli-node + - image: circleci/redis:5-alpine + environment: + COMPOSER_PREFER_LOWEST: 0 + + php73-lowest: + <<: *unit-config + docker: + - image: circleci/php:7.3-cli-node + - image: circleci/redis:5-alpine + environment: + COMPOSER_PREFER_LOWEST: 1 + +workflows: + version: 2 + units: + jobs: + - php74 + - php74-lowest + - php73 + - php73-lowest diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1044039 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +* text=auto +/.circleci/ export-ignore +/.github/ export-ignore +/examples/ export-ignore +/nginx/ export-ignore +/php-fpm/ export-ignore +/tests/ export-ignore +.gitattributes export-ignore +.gitignore export-ignore +docker-compose.yml export-ignore +phpcs.xml.dist export-ignore +phpunit.xml.dist export-ignore diff --git a/.gitignore b/.gitignore index 44ab7a5..fc951dd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.iml /.idea/ composer.lock -composer.phar \ No newline at end of file +composer.phar +.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 720eacf..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: php -php: - - 5.6 - - 7.0 - - 7.1 - -services: - - redis-server - -before_script: - - echo "apc.enabled = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - echo "apc.enable_cli = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - echo "extension = apcu.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - composer self-update - - composer install --no-interaction --prefer-source --dev - - phpenv rehash - -script: - - vendor/bin/phpunit --verbose --colors diff --git a/README.md b/README.md index 2c62cd7..35e4f1f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # A prometheus client library written in PHP -[![Build Status](https://travis-ci.org/Jimdo/prometheus_client_php.svg?branch=master)](https://travis-ci.org/Jimdo/prometheus_client_php) +[![CircleCI](https://circleci.com/gh/endclothing/prometheus_client_php/tree/master.svg?style=shield)](https://circleci.com/gh/endclothing/prometheus_client_php/tree/master) This library uses Redis or APCu to do the client side aggregation. If using Redis, we recommend to run a local Redis instance next to your PHP workers. @@ -12,6 +12,14 @@ You can pick from three adapters. Redis, APC or an in memory adapter. While the first needs a separate binary running, the second just needs the [APC](https://pecl.php.net/package/APCU) extension to be installed. If you don't need persistent metrics between requests (e.g. a long running cron job or script) the in memory adapter might be suitable to use. +## Installation + +Add as [Composer](https://getcomposer.org/) dependency: + +```sh +composer require endclothing/prometheus_client_php +``` + ## Usage A simple counter: @@ -83,13 +91,27 @@ $renderer = new RenderTextFormat(); $result = $renderer->render($registry->getMetricFamilySamples()); ``` +### Advanced Usage + +#### Advanced Histogram Usage +On passing an empty array for the bucket parameter on instantiation, a set of default buckets will be used instead. +Whilst this is a good base for a typical web application, there is named constructor to assist in the generation of +exponential / geometric buckets. + +Eg: +``` +Histogram::exponentialBuckets(0.05, 1.5, 10); +``` + +This will start your buckets with a value of 1.5, grow them by a factor of 1.5 per bucket across a set of 10 buckets. + Also look at the [examples](examples). ## Development ### Dependencies -* PHP 5.6 +* PHP ^7.3 * PHP Redis extension * PHP APCu extension * [Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) diff --git a/composer.json b/composer.json index b941542..e98dcf4 100644 --- a/composer.json +++ b/composer.json @@ -1,30 +1,34 @@ { - "name": "jimdo/prometheus_client_php", + "name": "endclothing/prometheus_client_php", + "description": "Prometheus instrumentation library for PHP applications.", + "type": "library", + "license": "Apache-2.0", "authors": [ { - "name": "Joscha", - "email": "joscha@schnipseljagd.org" - }, - { - "name": "Jan Brauer", - "email": "jan.brauer@jimdo.com" + "name": "Daniel Noel-Davies", + "email": "Daniel.Noel-Davies@endclothing.com" } ], + "replace": { + "jimdo/prometheus_client_php": "*" + }, "require": { - "php": ">=5.6.3", - "guzzlehttp/guzzle": "^6.2", + "php": "^7.3", + "ext-json": "*", + "guzzlehttp/guzzle": "^6.3", "symfony/polyfill-apcu": "^1.6" }, "require-dev": { - "phpunit/phpunit": "4.1.0" + "phpunit/phpunit": "^8.4", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-redis": "Required if using Redis.", "ext-apc": "Required if using APCu." }, "autoload": { - "psr-0": { - "Prometheus\\": "src/" + "psr-4": { + "Prometheus\\": "src/Prometheus/" } }, "autoload-dev": { @@ -32,5 +36,13 @@ "Test\\Prometheus\\": "tests/" } }, - "license": "Apache-2.0" + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "config": { + "sort-packages": true + }, + "prefer-stable": true } diff --git a/examples/flush_adapter.php b/examples/flush_adapter.php index 0c3862d..8e2ca88 100644 --- a/examples/flush_adapter.php +++ b/examples/flush_adapter.php @@ -4,9 +4,9 @@ $adapter = $_GET['adapter']; if ($adapter === 'redis') { - define('REDIS_HOST', isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1'); + define('REDIS_HOST', $_SERVER['REDIS_HOST'] ?? '127.0.0.1'); - $redisAdapter = new Prometheus\Storage\Redis(array('host' => REDIS_HOST)); + $redisAdapter = new Prometheus\Storage\Redis(['host' => REDIS_HOST]); $redisAdapter->flushRedis(); } elseif ($adapter === 'apc') { $apcAdapter = new Prometheus\Storage\APC(); @@ -14,4 +14,4 @@ } elseif ($adapter === 'in-memory') { $inMemoryAdapter = new Prometheus\Storage\InMemory(); $inMemoryAdapter->flushMemory(); -} \ No newline at end of file +} diff --git a/examples/metrics.php b/examples/metrics.php index fa89247..e523f79 100644 --- a/examples/metrics.php +++ b/examples/metrics.php @@ -9,7 +9,7 @@ $adapter = $_GET['adapter']; if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); + Redis::setDefaultOptions(['host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1']); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); diff --git a/examples/pushgateway.php b/examples/pushgateway.php index 984035d..c337fea 100644 --- a/examples/pushgateway.php +++ b/examples/pushgateway.php @@ -1,13 +1,14 @@ isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); + Redis::setDefaultOptions(['host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1']); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); @@ -20,5 +21,5 @@ $counter = $registry->registerCounter('test', 'some_counter', 'it increases', ['type']); $counter->incBy(6, ['blue']); -$pushGateway = new \Prometheus\PushGateway('192.168.59.100:9091'); -$pushGateway->push($registry, 'my_job', array('instance'=>'foo')); +$pushGateway = new PushGateway('192.168.59.100:9091'); +$pushGateway->push($registry, 'my_job', ['instance' => 'foo']); diff --git a/examples/some_counter.php b/examples/some_counter.php index 823bfac..857e7e8 100644 --- a/examples/some_counter.php +++ b/examples/some_counter.php @@ -8,7 +8,7 @@ $adapter = $_GET['adapter']; if ($adapter === 'redis') { - Redis::setDefaultOptions(array('host' => isset($_SERVER['REDIS_HOST']) ? $_SERVER['REDIS_HOST'] : '127.0.0.1')); + Redis::setDefaultOptions(['host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1']); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); diff --git a/examples/some_gauge.php b/examples/some_gauge.php index b3e2382..f8202d2 100644 --- a/examples/some_gauge.php +++ b/examples/some_gauge.php @@ -6,12 +6,12 @@ use Prometheus\Storage\Redis; -error_log('c='. $_GET['c']); +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')); + Redis::setDefaultOptions(['host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1']); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); diff --git a/examples/some_histogram.php b/examples/some_histogram.php index 6b34809..aeb5c1d 100644 --- a/examples/some_histogram.php +++ b/examples/some_histogram.php @@ -5,12 +5,12 @@ use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; -error_log('c='. $_GET['c']); +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')); + Redis::setDefaultOptions(['host' => $_SERVER['REDIS_HOST'] ?? '127.0.0.1']); $adapter = new Prometheus\Storage\Redis(); } elseif ($adapter === 'apc') { $adapter = new Prometheus\Storage\APC(); diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..78ea685 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,12 @@ + + + src/ + tests/ + examples/ + + vendor/* + + + + + diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index c09d661..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - ./tests/Test/Prometheus - - - diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..9fc8a72 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,24 @@ + + + + + + ./tests/Test/Prometheus + + + + + + ./src/Prometheus + + + diff --git a/src/Prometheus/Collector.php b/src/Prometheus/Collector.php index edc5e80..5f0a440 100644 --- a/src/Prometheus/Collector.php +++ b/src/Prometheus/Collector.php @@ -1,17 +1,34 @@ storageAdapter = $storageAdapter; $metricName = ($namespace ? $namespace . '_' : '') . $name; if (!preg_match(self::RE_METRIC_LABEL_NAME, $metricName)) { - throw new \InvalidArgumentException("Invalid metric name: '" . $metricName . "'"); + throw new InvalidArgumentException("Invalid metric name: '" . $metricName . "'"); } $this->name = $metricName; $this->help = $help; foreach ($labels as $label) { if (!preg_match(self::RE_METRIC_LABEL_NAME, $label)) { - throw new \InvalidArgumentException("Invalid label name: '" . $label . "'"); + throw new InvalidArgumentException("Invalid label name: '" . $label . "'"); } } $this->labels = $labels; @@ -41,24 +58,36 @@ public function __construct(Adapter $storageAdapter, $namespace, $name, $help, $ /** * @return string */ - public abstract function getType(); + abstract public function getType(); - public function getName() + /** + * @return string + */ + public function getName(): string { return $this->name; } - public function getLabelNames() + /** + * @return array + */ + public function getLabelNames(): array { return $this->labels; } - public function getHelp() + /** + * @return string + */ + public function getHelp(): string { return $this->help; } - public function getKey() + /** + * @return string + */ + public function getKey(): string { return sha1($this->getName() . serialize($this->getLabelNames())); } @@ -66,10 +95,10 @@ public function getKey() /** * @param $labels */ - protected function assertLabelsAreDefinedCorrectly($labels) + protected function assertLabelsAreDefinedCorrectly($labels): void { if (count($labels) != count($this->labels)) { - throw new \InvalidArgumentException(sprintf('Labels are not defined correctly: ', print_r($labels, true))); + throw new InvalidArgumentException(sprintf('Labels are not defined correctly: ', print_r($labels, true))); } } } diff --git a/src/Prometheus/CollectorRegistry.php b/src/Prometheus/CollectorRegistry.php index 9ff18e3..541e1d8 100644 --- a/src/Prometheus/CollectorRegistry.php +++ b/src/Prometheus/CollectorRegistry.php @@ -1,9 +1,9 @@ storageAdapter = $redisAdapter; @@ -41,7 +48,7 @@ public function __construct(Adapter $redisAdapter) /** * @return CollectorRegistry */ - public static function getDefault() + public static function getDefault(): CollectorRegistry { if (!self::$defaultRegistry) { return self::$defaultRegistry = new static(new Redis()); @@ -52,7 +59,7 @@ public static function getDefault() /** * @return MetricFamilySamples[] */ - public function getMetricFamilySamples() + public function getMetricFamilySamples(): array { return $this->storageAdapter->collect(); } @@ -65,7 +72,7 @@ public function getMetricFamilySamples() * @return Gauge * @throws MetricsRegistrationException */ - public function registerGauge($namespace, $name, $help, $labels = array()) + public function registerGauge($namespace, $name, $help, $labels = []): Gauge { $metricIdentifier = self::metricIdentifier($namespace, $name); if (isset($this->gauges[$metricIdentifier])) { @@ -87,7 +94,7 @@ public function registerGauge($namespace, $name, $help, $labels = array()) * @return Gauge * @throws MetricNotFoundException */ - public function getGauge($namespace, $name) + public function getGauge($namespace, $name): Gauge { $metricIdentifier = self::metricIdentifier($namespace, $name); if (!isset($this->gauges[$metricIdentifier])) { @@ -102,8 +109,9 @@ public function getGauge($namespace, $name) * @param string $help e.g. The duration something took in seconds. * @param array $labels e.g. ['controller', 'action'] * @return Gauge + * @throws MetricsRegistrationException */ - public function getOrRegisterGauge($namespace, $name, $help, $labels = array()) + public function getOrRegisterGauge($namespace, $name, $help, $labels = []): Gauge { try { $gauge = $this->getGauge($namespace, $name); @@ -121,7 +129,7 @@ public function getOrRegisterGauge($namespace, $name, $help, $labels = array()) * @return Counter * @throws MetricsRegistrationException */ - public function registerCounter($namespace, $name, $help, $labels = array()) + public function registerCounter($namespace, $name, $help, $labels = []): Counter { $metricIdentifier = self::metricIdentifier($namespace, $name); if (isset($this->counters[$metricIdentifier])) { @@ -143,7 +151,7 @@ public function registerCounter($namespace, $name, $help, $labels = array()) * @return Counter * @throws MetricNotFoundException */ - public function getCounter($namespace, $name) + public function getCounter($namespace, $name): Counter { $metricIdentifier = self::metricIdentifier($namespace, $name); if (!isset($this->counters[$metricIdentifier])) { @@ -158,8 +166,9 @@ public function getCounter($namespace, $name) * @param string $help e.g. The number of requests made. * @param array $labels e.g. ['controller', 'action'] * @return Counter + * @throws MetricsRegistrationException */ - public function getOrRegisterCounter($namespace, $name, $help, $labels = array()) + public function getOrRegisterCounter($namespace, $name, $help, $labels = []): Counter { try { $counter = $this->getCounter($namespace, $name); @@ -178,7 +187,7 @@ public function getOrRegisterCounter($namespace, $name, $help, $labels = array() * @return Histogram * @throws MetricsRegistrationException */ - public function registerHistogram($namespace, $name, $help, $labels = array(), $buckets = null) + public function registerHistogram($namespace, $name, $help, $labels = [], $buckets = null): Histogram { $metricIdentifier = self::metricIdentifier($namespace, $name); if (isset($this->histograms[$metricIdentifier])) { @@ -201,7 +210,7 @@ public function registerHistogram($namespace, $name, $help, $labels = array(), $ * @return Histogram * @throws MetricNotFoundException */ - public function getHistogram($namespace, $name) + public function getHistogram($namespace, $name): Histogram { $metricIdentifier = self::metricIdentifier($namespace, $name); if (!isset($this->histograms[$metricIdentifier])) { @@ -217,8 +226,9 @@ public function getHistogram($namespace, $name) * @param array $labels e.g. ['controller', 'action'] * @param array $buckets e.g. [100, 200, 300] * @return Histogram + * @throws MetricsRegistrationException */ - public function getOrRegisterHistogram($namespace, $name, $help, $labels = array(), $buckets = null) + public function getOrRegisterHistogram($namespace, $name, $help, $labels = [], $buckets = null): Histogram { try { $histogram = $this->getHistogram($namespace, $name); @@ -228,7 +238,12 @@ public function getOrRegisterHistogram($namespace, $name, $help, $labels = array return $histogram; } - private static function metricIdentifier($namespace, $name) + /** + * @param $namespace + * @param $name + * @return string + */ + private static function metricIdentifier($namespace, $name): string { return $namespace . ":" . $name; } diff --git a/src/Prometheus/Counter.php b/src/Prometheus/Counter.php index 3624c9c..1b095e5 100644 --- a/src/Prometheus/Counter.php +++ b/src/Prometheus/Counter.php @@ -1,7 +1,8 @@ incBy(1, $labels); } @@ -29,20 +30,20 @@ public function inc(array $labels = array()) * @param int $count e.g. 2 * @param array $labels e.g. ['status', 'opcode'] */ - public function incBy($count, array $labels = array()) + public function incBy($count, array $labels = []): void { $this->assertLabelsAreDefinedCorrectly($labels); $this->storageAdapter->updateCounter( - array( + [ 'name' => $this->getName(), 'help' => $this->getHelp(), 'type' => $this->getType(), 'labelNames' => $this->getLabelNames(), 'labelValues' => $labels, 'value' => $count, - 'command' => Adapter::COMMAND_INCREMENT_INTEGER - ) + 'command' => Adapter::COMMAND_INCREMENT_INTEGER, + ] ); } } diff --git a/src/Prometheus/Exception/MetricNotFoundException.php b/src/Prometheus/Exception/MetricNotFoundException.php index ff67175..bb3d51c 100644 --- a/src/Prometheus/Exception/MetricNotFoundException.php +++ b/src/Prometheus/Exception/MetricNotFoundException.php @@ -1,13 +1,13 @@ assertLabelsAreDefinedCorrectly($labels); $this->storageAdapter->updateGauge( - array( + [ 'name' => $this->getName(), 'help' => $this->getHelp(), 'type' => $this->getType(), 'labelNames' => $this->getLabelNames(), 'labelValues' => $labels, 'value' => $value, - 'command' => Adapter::COMMAND_SET - ) + 'command' => Adapter::COMMAND_SET, + ] ); } /** * @return string */ - public function getType() + public function getType(): string { return self::TYPE; } - public function inc($labels = array()) + /** + * @param array $labels + */ + public function inc($labels = []): void { $this->incBy(1, $labels); } - public function incBy($value, $labels = array()) + /** + * @param $value + * @param array $labels + */ + public function incBy($value, array $labels = []): void { $this->assertLabelsAreDefinedCorrectly($labels); $this->storageAdapter->updateGauge( - array( + [ 'name' => $this->getName(), 'help' => $this->getHelp(), 'type' => $this->getType(), 'labelNames' => $this->getLabelNames(), 'labelValues' => $labels, 'value' => $value, - 'command' => Adapter::COMMAND_INCREMENT_FLOAT - ) + 'command' => Adapter::COMMAND_INCREMENT_FLOAT, + ] ); } - public function dec($labels = array()) + /** + * @param array $labels + */ + public function dec($labels = []): void { $this->decBy(1, $labels); } - public function decBy($value, $labels = array()) + /** + * @param $value + * @param array $labels + */ + public function decBy($value, $labels = []): void { $this->incBy(-$value, $labels); } diff --git a/src/Prometheus/Histogram.php b/src/Prometheus/Histogram.php index 9dbfda4..b67c89f 100644 --- a/src/Prometheus/Histogram.php +++ b/src/Prometheus/Histogram.php @@ -1,14 +1,19 @@ = $buckets[$i + 1]) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( "Histogram buckets must be in increasing order: " . $buckets[$i] . " >= " . $buckets[$i + 1] ); @@ -41,7 +46,7 @@ public function __construct(Adapter $adapter, $namespace, $name, $help, $labels } foreach ($labels as $label) { if ($label === 'le') { - throw new \InvalidArgumentException("Histogram cannot have a label named 'le'."); + throw new InvalidArgumentException("Histogram cannot have a label named 'le'."); } } $this->buckets = $buckets; @@ -51,23 +56,53 @@ public function __construct(Adapter $adapter, $namespace, $name, $help, $labels * List of default buckets suitable for typical web application latency metrics * @return array */ - public static function getDefaultBuckets() + public static function getDefaultBuckets(): array { - return array( - 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0 - ); + return [ + 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0, + ]; + } + + /** + * @param float $start + * @param float $growthFactor + * @param int $numberOfBuckets + * @return array + */ + public static function exponentialBuckets(float $start, float $growthFactor, int $numberOfBuckets): array + { + if ($numberOfBuckets < 1) { + throw new InvalidArgumentException('Number of buckets must be a positive integer'); + } + + if ($start <= 0) { + throw new InvalidArgumentException('The starting position of a set of buckets must be a positive integer'); + } + + if ($growthFactor <= 1) { + throw new InvalidArgumentException('The growth factor must greater than 1'); + } + + $buckets = []; + + for ($i = 0; $i < $numberOfBuckets; $i++) { + $buckets[$i] = $start; + $start *= $growthFactor; + } + + return $buckets; } /** * @param double $value e.g. 123 * @param array $labels e.g. ['status', 'opcode'] */ - public function observe($value, $labels = array()) + public function observe(float $value, array $labels = []): void { $this->assertLabelsAreDefinedCorrectly($labels); $this->storageAdapter->updateHistogram( - array( + [ 'value' => $value, 'name' => $this->getName(), 'help' => $this->getHelp(), @@ -75,14 +110,14 @@ public function observe($value, $labels = array()) 'labelNames' => $this->getLabelNames(), 'labelValues' => $labels, 'buckets' => $this->buckets, - ) + ] ); } /** * @return string */ - public function getType() + public function getType(): string { return self::TYPE; } diff --git a/src/Prometheus/MetricFamilySamples.php b/src/Prometheus/MetricFamilySamples.php index e88e9aa..5e4ae18 100644 --- a/src/Prometheus/MetricFamilySamples.php +++ b/src/Prometheus/MetricFamilySamples.php @@ -1,14 +1,35 @@ name; } @@ -35,7 +56,7 @@ public function getName() /** * @return string */ - public function getType() + public function getType(): string { return $this->type; } @@ -43,7 +64,7 @@ public function getType() /** * @return string */ - public function getHelp() + public function getHelp(): string { return $this->help; } @@ -51,7 +72,7 @@ public function getHelp() /** * @return Sample[] */ - public function getSamples() + public function getSamples(): array { return $this->samples; } @@ -59,7 +80,7 @@ public function getSamples() /** * @return array */ - public function getLabelNames() + public function getLabelNames(): array { return $this->labelNames; } @@ -67,7 +88,7 @@ public function getLabelNames() /** * @return bool */ - public function hasLabelNames() + public function hasLabelNames(): bool { return !empty($this->labelNames); } diff --git a/src/Prometheus/PushGateway.php b/src/Prometheus/PushGateway.php index a4a3fd2..8b99982 100644 --- a/src/Prometheus/PushGateway.php +++ b/src/Prometheus/PushGateway.php @@ -1,32 +1,46 @@ address = $address; + $this->client = $client ?? new Client(); } /** * Pushes all metrics in a Collector, replacing all those with the same job. * Uses HTTP PUT. * @param CollectorRegistry $collectorRegistry - * @param $job - * @param $groupingKey + * @param string $job + * @param array $groupingKey + * @throws GuzzleException */ - public function push(CollectorRegistry $collectorRegistry, $job, $groupingKey = null) + public function push(CollectorRegistry $collectorRegistry, string $job, array $groupingKey = []): void { $this->doRequest($collectorRegistry, $job, $groupingKey, 'put'); } @@ -37,30 +51,33 @@ public function push(CollectorRegistry $collectorRegistry, $job, $groupingKey = * @param CollectorRegistry $collectorRegistry * @param $job * @param $groupingKey + * @throws GuzzleException */ - public function pushAdd(CollectorRegistry $collectorRegistry, $job, $groupingKey = null) + public function pushAdd(CollectorRegistry $collectorRegistry, string $job, array $groupingKey = []): void { $this->doRequest($collectorRegistry, $job, $groupingKey, 'post'); } /** - * Deletes metrics from the Pushgateway. + * Deletes metrics from the Push Gateway. * Uses HTTP POST. - * @param $job - * @param $groupingKey + * @param string $job + * @param array $groupingKey + * @throws GuzzleException */ - public function delete($job, $groupingKey = null) + public function delete(string $job, array $groupingKey = []): void { $this->doRequest(null, $job, $groupingKey, 'delete'); } /** * @param CollectorRegistry $collectorRegistry - * @param $job - * @param $groupingKey - * @param $method + * @param string $job + * @param array $groupingKey + * @param string $method + * @throws GuzzleException */ - private function doRequest(CollectorRegistry $collectorRegistry, $job, $groupingKey, $method) + private function doRequest(CollectorRegistry $collectorRegistry, string $job, array $groupingKey, $method): void { $url = "http://" . $this->address . "/metrics/job/" . $job; if (!empty($groupingKey)) { @@ -68,24 +85,27 @@ private function doRequest(CollectorRegistry $collectorRegistry, $job, $grouping $url .= "/" . $label . "/" . $value; } } - $client = new Client(); - $requestOptions = array( - 'headers' => array( - 'Content-Type' => RenderTextFormat::MIME_TYPE - ), + + $requestOptions = [ + 'headers' => [ + 'Content-Type' => RenderTextFormat::MIME_TYPE, + ], 'connect_timeout' => 10, 'timeout' => 20, - ); + ]; + if ($method != 'delete') { $renderer = new RenderTextFormat(); $requestOptions['body'] = $renderer->render($collectorRegistry->getMetricFamilySamples()); } - $response = $client->request($method, $url, $requestOptions); + $response = $this->client->request($method, $url, $requestOptions); $statusCode = $response->getStatusCode(); - if ($statusCode != 202) { - $msg = "Unexpected status code " . $statusCode . " received from pushgateway " . $this->address . ": " . $response->getBody(); - throw new \RuntimeException($msg); + if (!in_array($statusCode, [200, 202])) { + $msg = "Unexpected status code " + . $statusCode + . " received from push gateway " + . $this->address . ": " . $response->getBody(); + throw new RuntimeException($msg); } } - } diff --git a/src/Prometheus/RenderTextFormat.php b/src/Prometheus/RenderTextFormat.php index 95fe2b5..a5b78dc 100644 --- a/src/Prometheus/RenderTextFormat.php +++ b/src/Prometheus/RenderTextFormat.php @@ -1,7 +1,8 @@ getName(), $b->getName()); }); - $lines = array(); + $lines = []; foreach ($metrics as $metric) { $lines[] = "# HELP " . $metric->getName() . " {$metric->getHelp()}"; @@ -30,9 +30,14 @@ public function render(array $metrics) return implode("\n", $lines) . "\n"; } - private function renderSample(MetricFamilySamples $metric, Sample $sample) + /** + * @param MetricFamilySamples $metric + * @param Sample $sample + * @return string + */ + private function renderSample(MetricFamilySamples $metric, Sample $sample): string { - $escapedLabels = array(); + $escapedLabels = []; $labelNames = $metric->getLabelNames(); if ($metric->hasLabelNames() || $sample->hasLabelNames()) { @@ -45,7 +50,11 @@ private function renderSample(MetricFamilySamples $metric, Sample $sample) return $sample->getName() . ' ' . $sample->getValue(); } - private function escapeLabelValue($v) + /** + * @param string $v + * @return string + */ + private function escapeLabelValue($v): string { $v = str_replace("\\", "\\\\", $v); $v = str_replace("\n", "\\n", $v); diff --git a/src/Prometheus/Sample.php b/src/Prometheus/Sample.php index 9d9d1b3..c8774e8 100644 --- a/src/Prometheus/Sample.php +++ b/src/Prometheus/Sample.php @@ -1,15 +1,35 @@ name = $data['name']; @@ -21,7 +41,7 @@ public function __construct(array $data) /** * @return string */ - public function getName() + public function getName(): string { return $this->name; } @@ -29,7 +49,7 @@ public function getName() /** * @return array */ - public function getLabelNames() + public function getLabelNames(): array { return (array)$this->labelNames; } @@ -37,7 +57,7 @@ public function getLabelNames() /** * @return array */ - public function getLabelValues() + public function getLabelValues(): array { return (array)$this->labelValues; } @@ -45,15 +65,15 @@ public function getLabelValues() /** * @return int|double */ - public function getValue() + public function getValue(): string { - return $this->value; + return (string) $this->value; } /** * @return bool */ - public function hasLabelNames() + public function hasLabelNames(): bool { return !empty($this->labelNames); } diff --git a/src/Prometheus/Storage/APC.php b/src/Prometheus/Storage/APC.php index b608e49..2fe659d 100644 --- a/src/Prometheus/Storage/APC.php +++ b/src/Prometheus/Storage/APC.php @@ -1,9 +1,10 @@ collectHistograms(); $metrics = array_merge($metrics, $this->collectGauges()); @@ -22,7 +23,10 @@ public function collect() return $metrics; } - public function updateHistogram(array $data) + /** + * @param array $data + */ + public function updateHistogram(array $data): void { // Initialize the sum $sumKey = $this->histogramBucketValueKey($data, 'sum'); @@ -55,7 +59,10 @@ public function updateHistogram(array $data) apcu_inc($this->histogramBucketValueKey($data, $bucketToIncrease)); } - public function updateGauge(array $data) + /** + * @param array $data + */ + public function updateGauge(array $data): void { $valueKey = $this->valueKey($data); if ($data['command'] == Adapter::COMMAND_SET) { @@ -75,7 +82,10 @@ public function updateGauge(array $data) } } - public function updateCounter(array $data) + /** + * @param array $data + */ + public function updateCounter(array $data): void { $new = apcu_add($this->valueKey($data), 0); if ($new) { @@ -84,56 +94,59 @@ public function updateCounter(array $data) apcu_inc($this->valueKey($data), $data['value']); } - public function flushAPC() + /** + * @return void + */ + public function flushAPC(): void { - apcu_clear_cache(); + apcu_clear_cache(); } /** * @param array $data * @return string */ - private function metaKey(array $data) + private function metaKey(array $data): string { - return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], 'meta')); + return implode(':', [self::PROMETHEUS_PREFIX, $data['type'], $data['name'], 'meta']); } /** * @param array $data * @return string */ - private function valueKey(array $data) + private function valueKey(array $data): string { - return implode(':', array( + return implode(':', [ self::PROMETHEUS_PREFIX, $data['type'], $data['name'], $this->encodeLabelValues($data['labelValues']), - 'value' - )); + 'value', + ]); } /** * @param array $data * @return string */ - private function histogramBucketValueKey(array $data, $bucket) + private function histogramBucketValueKey(array $data, $bucket): string { - return implode(':', array( + return implode(':', [ self::PROMETHEUS_PREFIX, $data['type'], $data['name'], $this->encodeLabelValues($data['labelValues']), $bucket, - 'value' - )); + 'value', + ]); } /** * @param array $data * @return array */ - private function metaData(array $data) + private function metaData(array $data): array { $metricsMetaData = $data; unset($metricsMetaData['value']); @@ -145,26 +158,26 @@ private function metaData(array $data) /** * @return array */ - private function collectCounters() + private function collectCounters(): array { - $counters = array(); - foreach (new \APCUIterator('/^prom:counter:.*:meta/') as $counter) { + $counters = []; + foreach (new APCUIterator('/^prom:counter:.*:meta/') as $counter) { $metaData = json_decode($counter['value'], true); - $data = array( + $data = [ 'name' => $metaData['name'], 'help' => $metaData['help'], 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], - ); - foreach (new \APCUIterator('/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { + ]; + foreach (new APCUIterator('/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'], - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $value['value'] - ); + 'value' => $value['value'], + ]; } $this->sortSamples($data['samples']); $counters[] = new MetricFamilySamples($data); @@ -175,26 +188,26 @@ private function collectCounters() /** * @return array */ - private function collectGauges() + private function collectGauges(): array { - $gauges = array(); - foreach (new \APCUIterator('/^prom:gauge:.*:meta/') as $gauge) { + $gauges = []; + foreach (new APCUIterator('/^prom:gauge:.*:meta/') as $gauge) { $metaData = json_decode($gauge['value'], true); - $data = array( + $data = [ 'name' => $metaData['name'], 'help' => $metaData['help'], 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], - ); - foreach (new \APCUIterator('/^prom:gauge:' . $metaData['name'] . ':.*:value/') as $value) { + ]; + foreach (new APCUIterator('/^prom:gauge:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'], - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $this->fromInteger($value['value']) - ); + 'value' => $this->fromInteger($value['value']), + ]; } $this->sortSamples($data['samples']); @@ -206,24 +219,24 @@ private function collectGauges() /** * @return array */ - private function collectHistograms() + private function collectHistograms(): array { - $histograms = array(); - foreach (new \APCUIterator('/^prom:histogram:.*:meta/') as $histogram) { + $histograms = []; + foreach (new APCUIterator('/^prom:histogram:.*:meta/') as $histogram) { $metaData = json_decode($histogram['value'], true); - $data = array( + $data = [ 'name' => $metaData['name'], 'help' => $metaData['help'], 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], - 'buckets' => $metaData['buckets'] - ); + 'buckets' => $metaData['buckets'], + ]; // Add the Inf bucket so we can compute it later on $data['buckets'][] = '+Inf'; - $histogramBuckets = array(); - foreach (new \APCUIterator('/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { + $histogramBuckets = []; + foreach (new APCUIterator('/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $bucket = $parts[4]; @@ -238,41 +251,40 @@ private function collectHistograms() $acc = 0; $decodedLabelValues = $this->decodeLabelValues($labelValues); foreach ($data['buckets'] as $bucket) { - $bucket = (string) $bucket; + $bucket = (string)$bucket; if (!isset($histogramBuckets[$labelValues][$bucket])) { - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($decodedLabelValues, array($bucket)), - 'value' => $acc - ); + 'labelNames' => ['le'], + 'labelValues' => array_merge($decodedLabelValues, [$bucket]), + 'value' => $acc, + ]; } else { $acc += $histogramBuckets[$labelValues][$bucket]; - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'] . '_' . 'bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($decodedLabelValues, array($bucket)), - 'value' => $acc - ); + 'labelNames' => ['le'], + 'labelValues' => array_merge($decodedLabelValues, [$bucket]), + 'value' => $acc, + ]; } } // Add the count - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'] . '_count', - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $decodedLabelValues, - 'value' => $acc - ); + 'value' => $acc, + ]; // Add the sum - $data['samples'][] = array( + $data['samples'][] = [ 'name' => $metaData['name'] . '_sum', - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $decodedLabelValues, - 'value' => $this->fromInteger($histogramBuckets[$labelValues]['sum']) - ); - + 'value' => $this->fromInteger($histogramBuckets[$labelValues]['sum']), + ]; } $histograms[] = new MetricFamilySamples($data); } @@ -283,23 +295,26 @@ private function collectHistograms() * @param mixed $val * @return int */ - private function toInteger($val) + private function toInteger($val): int { return unpack('Q', pack('d', $val))[1]; } /** * @param mixed $val - * @return int + * @return float */ - private function fromInteger($val) + private function fromInteger($val): float { return unpack('d', pack('Q', $val))[1]; } - private function sortSamples(array &$samples) + /** + * @param array $samples + */ + private function sortSamples(array &$samples): void { - usort($samples, function($a, $b){ + usort($samples, function ($a, $b) { return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); }); } @@ -309,7 +324,7 @@ private function sortSamples(array &$samples) * @return string * @throws RuntimeException */ - private function encodeLabelValues(array $values) + private function encodeLabelValues(array $values): string { $json = json_encode($values); if (false === $json) { @@ -323,7 +338,7 @@ private function encodeLabelValues(array $values) * @return array * @throws RuntimeException */ - private function decodeLabelValues($values) + private function decodeLabelValues($values): array { $json = base64_decode($values, true); if (false === $json) { diff --git a/src/Prometheus/Storage/Adapter.php b/src/Prometheus/Storage/Adapter.php index e280f13..068e1d9 100644 --- a/src/Prometheus/Storage/Adapter.php +++ b/src/Prometheus/Storage/Adapter.php @@ -1,9 +1,10 @@ internalCollect($this->counters); $metrics = array_merge($metrics, $this->internalCollect($this->gauges)); @@ -24,14 +25,17 @@ public function collect() return $metrics; } - public function flushMemory() + public function flushMemory(): void { $this->counters = []; $this->gauges = []; $this->histograms = []; } - private function collectHistograms() + /** + * @return array + */ + private function collectHistograms(): array { $histograms = []; foreach ($this->histograms as $histogram) { @@ -41,7 +45,7 @@ private function collectHistograms() 'help' => $metaData['help'], 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], - 'buckets' => $metaData['buckets'] + 'buckets' => $metaData['buckets'], ]; // Add the Inf bucket so we can compute it later on @@ -69,7 +73,7 @@ private function collectHistograms() 'name' => $metaData['name'] . '_bucket', 'labelNames' => ['le'], 'labelValues' => array_merge($decodedLabelValues, [$bucket]), - 'value' => $acc + 'value' => $acc, ]; } else { $acc += $histogramBuckets[$labelValues][$bucket]; @@ -77,7 +81,7 @@ private function collectHistograms() 'name' => $metaData['name'] . '_' . 'bucket', 'labelNames' => ['le'], 'labelValues' => array_merge($decodedLabelValues, [$bucket]), - 'value' => $acc + 'value' => $acc, ]; } } @@ -87,7 +91,7 @@ private function collectHistograms() 'name' => $metaData['name'] . '_count', 'labelNames' => [], 'labelValues' => $decodedLabelValues, - 'value' => $acc + 'value' => $acc, ]; // Add the sum @@ -95,16 +99,19 @@ private function collectHistograms() 'name' => $metaData['name'] . '_sum', 'labelNames' => [], 'labelValues' => $decodedLabelValues, - 'value' => $histogramBuckets[$labelValues]['sum'] + 'value' => $histogramBuckets[$labelValues]['sum'], ]; - } $histograms[] = new MetricFamilySamples($data); } return $histograms; } - private function internalCollect(array $metrics) + /** + * @param array $metrics + * @return array + */ + private function internalCollect(array $metrics): array { $result = []; foreach ($metrics as $metric) { @@ -122,7 +129,7 @@ private function internalCollect(array $metrics) 'name' => $metaData['name'], 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $value + 'value' => $value, ]; } $this->sortSamples($data['samples']); @@ -131,14 +138,18 @@ private function internalCollect(array $metrics) return $result; } - public function updateHistogram(array $data) + /** + * @param array $data + * @return void + */ + public function updateHistogram(array $data): void { // Initialize the sum $metaKey = $this->metaKey($data); if (array_key_exists($metaKey, $this->histograms) === false) { $this->histograms[$metaKey] = [ 'meta' => $this->metaData($data), - 'samples' => [] + 'samples' => [], ]; } $sumKey = $this->histogramBucketValueKey($data, 'sum'); @@ -164,14 +175,17 @@ public function updateHistogram(array $data) $this->histograms[$metaKey]['samples'][$bucketKey] += 1; } - public function updateGauge(array $data) + /** + * @param array $data + */ + public function updateGauge(array $data): void { $metaKey = $this->metaKey($data); $valueKey = $this->valueKey($data); if (array_key_exists($metaKey, $this->gauges) === false) { $this->gauges[$metaKey] = [ 'meta' => $this->metaData($data), - 'samples' => [] + 'samples' => [], ]; } if (array_key_exists($valueKey, $this->gauges[$metaKey]['samples']) === false) { @@ -184,14 +198,17 @@ public function updateGauge(array $data) } } - public function updateCounter(array $data) + /** + * @param array $data + */ + public function updateCounter(array $data): void { $metaKey = $this->metaKey($data); $valueKey = $this->valueKey($data); if (array_key_exists($metaKey, $this->counters) === false) { $this->counters[$metaKey] = [ 'meta' => $this->metaData($data), - 'samples' => [] + 'samples' => [], ]; } if (array_key_exists($valueKey, $this->counters[$metaKey]['samples']) === false) { @@ -206,18 +223,16 @@ public function updateCounter(array $data) /** * @param array $data - * - * @param $bucket - * + * @param string $bucket * @return string */ - private function histogramBucketValueKey(array $data, $bucket) + private function histogramBucketValueKey(array $data, $bucket): string { return implode(':', [ $data['type'], $data['name'], $this->encodeLabelValues($data['labelValues']), - $bucket + $bucket, ]); } @@ -226,9 +241,13 @@ private function histogramBucketValueKey(array $data, $bucket) * * @return string */ - private function metaKey(array $data) + private function metaKey(array $data): string { - return implode(':', [$data['type'], $data['name'], 'meta']); + return implode(':', [ + $data['type'], + $data['name'], + 'meta' + ]); } /** @@ -236,10 +255,14 @@ private function metaKey(array $data) * * @return string */ - private function valueKey(array $data) + private function valueKey(array $data): string { - return implode(':', - [$data['type'], $data['name'], $this->encodeLabelValues($data['labelValues']), 'value']); + return implode(':', [ + $data['type'], + $data['name'], + $this->encodeLabelValues($data['labelValues']), + 'value' + ]); } /** @@ -247,7 +270,7 @@ private function valueKey(array $data) * * @return array */ - private function metaData(array $data) + private function metaData(array $data): array { $metricsMetaData = $data; unset($metricsMetaData['value']); @@ -256,7 +279,10 @@ private function metaData(array $data) return $metricsMetaData; } - private function sortSamples(array &$samples) + /** + * @param array $samples + */ + private function sortSamples(array &$samples): void { usort($samples, function ($a, $b) { return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); @@ -268,7 +294,7 @@ private function sortSamples(array &$samples) * @return string * @throws RuntimeException */ - private function encodeLabelValues(array $values) + private function encodeLabelValues(array $values): string { $json = json_encode($values); if (false === $json) { @@ -282,7 +308,7 @@ private function encodeLabelValues(array $values) * @return array * @throws RuntimeException */ - private function decodeLabelValues($values) + private function decodeLabelValues($values): array { $json = base64_decode($values, true); if (false === $json) { diff --git a/src/Prometheus/Storage/Redis.php b/src/Prometheus/Storage/Redis.php index 091577c..85e3000 100644 --- a/src/Prometheus/Storage/Redis.php +++ b/src/Prometheus/Storage/Redis.php @@ -1,8 +1,10 @@ '127.0.0.1', + 'port' => 6379, + 'timeout' => 0.1, + 'read_timeout' => 10, + 'persistent_connections' => false, + 'password' => null, + ]; + + /** + * @var string + */ private static $prefix = 'PROMETHEUS_'; - private $options; + /** + * @var array + */ + private $options = []; + + /** + * @var \Redis + */ private $redis; - public function __construct(array $options = array()) - { - // 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; - } + /** + * @var boolean + */ + private $connectionInitialized = false; + /** + * Redis constructor. + * @param array $options + */ + public function __construct(array $options = []) + { $this->options = array_merge(self::$defaultOptions, $options); $this->redis = new \Redis(); } + public static function fromExistingConnection(\Redis $redis): self + { + if ($redis->isConnected() === false) { + throw new StorageException('Connection to Redis server not established'); + } + + $self = new self(); + $self->connectionInitialized = true; + $self->redis = $redis; + + return $self; + } + /** * @param array $options */ - public static function setDefaultOptions(array $options) + public static function setDefaultOptions(array $options): void { self::$defaultOptions = array_merge(self::$defaultOptions, $options); } - public static function setPrefix($prefix) + /** + * @param $prefix + */ + public static function setPrefix($prefix): void { self::$prefix = $prefix; } - public function flushRedis() + /** + * @throws StorageException + */ + public function flushRedis(): void { $this->openConnection(); $this->redis->flushAll(); @@ -69,7 +99,7 @@ public function flushRedis() * @return MetricFamilySamples[] * @throws StorageException */ - public function collect() + public function collect(): array { $this->openConnection(); $metrics = $this->collectHistograms(); @@ -86,29 +116,53 @@ function (array $metric) { /** * @throws StorageException */ - private function openConnection() + private function openConnection(): void + { + if ($this->connectionInitialized === true) { + return; + } + + $connectionStatus = $this->connectToServer(); + if ($connectionStatus === false) { + throw new StorageException("Can't connect to Redis server", 0); + } + + if ($this->options['password']) { + $this->redis->auth($this->options['password']); + } + + if (isset($this->options['database'])) { + $this->redis->select($this->options['database']); + } + + $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->options['read_timeout']); + } + + /** + * @return bool + */ + private function connectToServer(): bool { 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']); - } - if (isset($this->options['database'])) { - $this->redis->select($this->options['database']); + return $this->redis->pconnect( + $this->options['host'], + $this->options['port'], + $this->options['timeout'] + ); } - $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->options['read_timeout']); - + return $this->redis->connect($this->options['host'], $this->options['port'], $this->options['timeout']); } catch (\RedisException $e) { - throw new StorageException("Can't connect to Redis server", 0, $e); + return false; } } - public function updateHistogram(array $data) + /** + * @param array $data + * @throws StorageException + */ + public function updateHistogram(array $data): void { $this->openConnection(); $bucketToIncrease = '+Inf'; @@ -121,106 +175,120 @@ public function updateHistogram(array $data) $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); - $this->redis->eval(<<redis->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, + json_encode(['b' => 'sum', 'labelValues' => $data['labelValues']]), + json_encode(['b' => $bucketToIncrease, 'labelValues' => $data['labelValues']]), $data['value'], json_encode($metaData), - ), - 4 + ], + 2 ); } - public function updateGauge(array $data) + /** + * @param array $data + * @throws StorageException + */ + public function updateGauge(array $data): void { $this->openConnection(); $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); unset($metaData['command']); - $this->redis->eval(<<redis->eval( + <<toMetricKey($data), - $this->getRedisCommand($data['command']), self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, + $this->getRedisCommand($data['command']), json_encode($data['labelValues']), $data['value'], json_encode($metaData), - ), - 4 + ], + 2 ); } - public function updateCounter(array $data) + /** + * @param array $data + * @throws StorageException + */ + public function updateCounter(array $data): void { $this->openConnection(); $metaData = $data; unset($metaData['value']); unset($metaData['labelValues']); unset($metaData['command']); - $result = $this->redis->eval(<<redis->eval( + <<toMetricKey($data), - $this->getRedisCommand($data['command']), self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, - json_encode($data['labelValues']), + $this->getRedisCommand($data['command']), $data['value'], + json_encode($data['labelValues']), json_encode($metaData), - ), - 4 + ], + 2 ); - return $result; } - private function collectHistograms() + /** + * @return array + */ + private function collectHistograms(): array { $keys = $this->redis->sMembers(self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); - $histograms = array(); + $histograms = []; foreach ($keys as $key) { - $raw = $this->redis->hGetAll($key); + $raw = $this->redis->hGetAll(str_replace($this->redis->_prefix(''), '', $key)); $histogram = json_decode($raw['__meta'], true); unset($raw['__meta']); - $histogram['samples'] = array(); + $histogram['samples'] = []; // Add the Inf bucket so we can compute it later on $histogram['buckets'][] = '+Inf'; - $allLabelValues = array(); + $allLabelValues = []; foreach (array_keys($raw) as $k) { $d = json_decode($k, true); if ($d['b'] == 'sum') { @@ -240,65 +308,68 @@ private function collectHistograms() // the previous one. $acc = 0; foreach ($histogram['buckets'] as $bucket) { - $bucketKey = json_encode(array('b' => $bucket, 'labelValues' => $labelValues)); + $bucketKey = json_encode(['b' => $bucket, 'labelValues' => $labelValues]); if (!isset($raw[$bucketKey])) { - $histogram['samples'][] = array( + $histogram['samples'][] = [ 'name' => $histogram['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($labelValues, array($bucket)), - 'value' => $acc - ); + 'labelNames' => ['le'], + 'labelValues' => array_merge($labelValues, [$bucket]), + 'value' => $acc, + ]; } else { $acc += $raw[$bucketKey]; - $histogram['samples'][] = array( + $histogram['samples'][] = [ 'name' => $histogram['name'] . '_bucket', - 'labelNames' => array('le'), - 'labelValues' => array_merge($labelValues, array($bucket)), - 'value' => $acc - ); + 'labelNames' => ['le'], + 'labelValues' => array_merge($labelValues, [$bucket]), + 'value' => $acc, + ]; } } // Add the count - $histogram['samples'][] = array( + $histogram['samples'][] = [ 'name' => $histogram['name'] . '_count', - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $labelValues, - 'value' => $acc - ); + 'value' => $acc, + ]; // Add the sum - $histogram['samples'][] = array( + $histogram['samples'][] = [ 'name' => $histogram['name'] . '_sum', - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => $labelValues, - 'value' => $raw[json_encode(array('b' => 'sum', 'labelValues' => $labelValues))] - ); + 'value' => $raw[json_encode(['b' => 'sum', 'labelValues' => $labelValues])], + ]; } $histograms[] = $histogram; } return $histograms; } - private function collectGauges() + /** + * @return array + */ + private function collectGauges(): array { $keys = $this->redis->sMembers(self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); - $gauges = array(); + $gauges = []; foreach ($keys as $key) { - $raw = $this->redis->hGetAll($key); + $raw = $this->redis->hGetAll(str_replace($this->redis->_prefix(''), '', $key)); $gauge = json_decode($raw['__meta'], true); unset($raw['__meta']); - $gauge['samples'] = array(); + $gauge['samples'] = []; foreach ($raw as $k => $value) { - $gauge['samples'][] = array( + $gauge['samples'][] = [ 'name' => $gauge['name'], - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => json_decode($k, true), - 'value' => $value - ); + 'value' => $value, + ]; } - usort($gauge['samples'], function($a, $b){ + usort($gauge['samples'], function ($a, $b) { return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); }); $gauges[] = $gauge; @@ -306,25 +377,28 @@ private function collectGauges() return $gauges; } - private function collectCounters() + /** + * @return array + */ + private function collectCounters(): array { $keys = $this->redis->sMembers(self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX); sort($keys); - $counters = array(); + $counters = []; foreach ($keys as $key) { - $raw = $this->redis->hGetAll($key); + $raw = $this->redis->hGetAll(str_replace($this->redis->_prefix(''), '', $key)); $counter = json_decode($raw['__meta'], true); unset($raw['__meta']); - $counter['samples'] = array(); + $counter['samples'] = []; foreach ($raw as $k => $value) { - $counter['samples'][] = array( + $counter['samples'][] = [ 'name' => $counter['name'], - 'labelNames' => array(), + 'labelNames' => [], 'labelValues' => json_decode($k, true), - 'value' => $value - ); + 'value' => $value, + ]; } - usort($counter['samples'], function($a, $b){ + usort($counter['samples'], function ($a, $b) { return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); }); $counters[] = $counter; @@ -332,7 +406,11 @@ private function collectCounters() return $counters; } - private function getRedisCommand($cmd) + /** + * @param int $cmd + * @return string + */ + private function getRedisCommand(int $cmd): string { switch ($cmd) { case Adapter::COMMAND_INCREMENT_INTEGER: @@ -342,7 +420,7 @@ private function getRedisCommand($cmd) case Adapter::COMMAND_SET: return 'hSet'; default: - throw new \InvalidArgumentException("Unknown command"); + throw new InvalidArgumentException("Unknown command"); } } @@ -350,9 +428,8 @@ private function getRedisCommand($cmd) * @param array $data * @return string */ - private function toMetricKey(array $data) + private function toMetricKey(array $data): string { - return implode(':', array(self::$prefix, $data['type'], $data['name'])); + return implode(':', [self::$prefix, $data['type'], $data['name']]); } - } diff --git a/tests/Test/BlackBoxPushGatewayTest.php b/tests/Test/BlackBoxPushGatewayTest.php index 26490c6..b3ad8ac 100644 --- a/tests/Test/BlackBoxPushGatewayTest.php +++ b/tests/Test/BlackBoxPushGatewayTest.php @@ -1,14 +1,14 @@ incBy(6, ['blue']); $pushGateway = new PushGateway('pushgateway:9091'); - $pushGateway->push($registry, 'my_job', array('instance' => 'foo')); + $pushGateway->push($registry, 'my_job', ['instance' => 'foo']); $httpClient = new Client(); $metrics = $httpClient->get("http://pushgateway:9091/metrics")->getBody()->getContents(); @@ -33,7 +33,7 @@ public function pushGatewayShouldWork() $metrics ); - $pushGateway->delete('my_job', array('instance' => 'foo')); + $pushGateway->delete('my_job', ['instance' => 'foo']); $httpClient = new Client(); $metrics = $httpClient->get("http://pushgateway:9091/metrics")->getBody()->getContents(); diff --git a/tests/Test/BlackBoxTest.php b/tests/Test/BlackBoxTest.php index d57f3a3..b4d8a9e 100644 --- a/tests/Test/BlackBoxTest.php +++ b/tests/Test/BlackBoxTest.php @@ -1,11 +1,12 @@ adapter->flushAPC(); } } - diff --git a/tests/Test/Prometheus/AbstractCollectorRegistryTest.php b/tests/Test/Prometheus/AbstractCollectorRegistryTest.php index 237685c..76f3160 100644 --- a/tests/Test/Prometheus/AbstractCollectorRegistryTest.php +++ b/tests/Test/Prometheus/AbstractCollectorRegistryTest.php @@ -1,18 +1,17 @@ configureAdapter(); $this->renderer = new RenderTextFormat(); @@ -37,17 +36,18 @@ public function itShouldSaveGauges() { $registry = new CollectorRegistry($this->adapter); - $g = $registry->registerGauge('test', 'some_metric', 'this is for testing', array('foo')); - $g->set(35, array('bbb')); - $g->set(35, array('ddd')); - $g->set(35, array('aaa')); - $g->set(35, array('ccc')); + $g = $registry->registerGauge('test', 'some_metric', 'this is for testing', ['foo']); + $g->set(35, ['bbb']); + $g->set(35, ['ddd']); + $g->set(35, ['aaa']); + $g->set(35, ['ccc']); $registry = new CollectorRegistry($this->adapter); $this->assertThat( $this->renderer->render($registry->getMetricFamilySamples()), - $this->equalTo(<<equalTo( + <<adapter); - $metric = $registry->registerCounter('test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $metric->incBy(2, array('lalal', 'lululu')); - $registry->getCounter('test', 'some_metric', array('foo', 'bar'))->inc(array('lalal', 'lululu')); - $registry->getCounter('test', 'some_metric', array('foo', 'bar'))->inc(array('lalal', 'lvlvlv')); + $metric = $registry->registerCounter('test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $metric->incBy(2, ['lalal', 'lululu']); + $registry->getCounter('test', 'some_metric', ['foo', 'bar'])->inc(['lalal', 'lululu']); + $registry->getCounter('test', 'some_metric', ['foo', 'bar'])->inc(['lalal', 'lvlvlv']); $registry = new CollectorRegistry($this->adapter); $this->assertThat( $this->renderer->render($registry->getMetricFamilySamples()), - $this->equalTo(<<equalTo( + <<adapter); - $metric = $registry->registerHistogram('test', 'some_metric', 'this is for testing', array('foo', 'bar'), array(0.1, 1, 5, 10)); - $metric->observe(2, array('lalal', 'lululu')); - $registry->getHistogram('test', 'some_metric', array('foo', 'bar'))->observe(7.1, array('lalal', 'lvlvlv')); - $registry->getHistogram('test', 'some_metric', array('foo', 'bar'))->observe(13, array('lalal', 'lululu')); - $registry->getHistogram('test', 'some_metric', array('foo', 'bar'))->observe(7.1, array('lalal', 'lululu')); - $registry->getHistogram('test', 'some_metric', array('foo', 'bar'))->observe(7.1, array('gnaaha', 'hihihi')); + $metric = $registry->registerHistogram( + 'test', + 'some_metric', + 'this is for testing', + ['foo', 'bar'], + [0.1, 1, 5, 10] + ); + $metric->observe(2, ['lalal', 'lululu']); + $registry->getHistogram('test', 'some_metric', ['foo', 'bar'])->observe(7.1, ['lalal', 'lvlvlv']); + $registry->getHistogram('test', 'some_metric', ['foo', 'bar'])->observe(13, ['lalal', 'lululu']); + $registry->getHistogram('test', 'some_metric', ['foo', 'bar'])->observe(7.1, ['lalal', 'lululu']); + $registry->getHistogram('test', 'some_metric', ['foo', 'bar'])->observe(7.1, ['gnaaha', 'hihihi']); $registry = new CollectorRegistry($this->adapter); $this->assertThat( $this->renderer->render($registry->getMetricFamilySamples()), - $this->equalTo(<<equalTo( + <<adapter); $this->assertThat( $this->renderer->render($registry->getMetricFamilySamples()), - $this->equalTo(<<equalTo( + <<adapter); + $registry = new CollectorRegistry($this->adapter); $registry ->registerCounter('', 'some_quick_counter', 'just a quick measurement') - ->inc(); + ->inc() + ; $this->assertThat( $this->renderer->render($registry->getMetricFamilySamples()), - $this->equalTo(<<equalTo( + <<adapter); + $registry = new CollectorRegistry($this->adapter); $registry->registerCounter('foo', 'metric', 'help'); + + $this->expectException(MetricsRegistrationException::class); $registry->registerCounter('foo', 'metric', 'help'); } /** * @test - * @expectedException \Prometheus\Exception\MetricsRegistrationException */ public function itShouldForbidRegisteringTheSameCounterWithDifferentLabels() { - $registry = new CollectorRegistry( $this->adapter); - $registry->registerCounter('foo', 'metric', 'help', array("foo", "bar")); - $registry->registerCounter('foo', 'metric', 'help', array("spam", "eggs")); + $registry = new CollectorRegistry($this->adapter); + $registry->registerCounter('foo', 'metric', 'help', ["foo", "bar"]); + + $this->expectException(MetricsRegistrationException::class); + $registry->registerCounter('foo', 'metric', 'help', ["spam", "eggs"]); } /** * @test - * @expectedException \Prometheus\Exception\MetricsRegistrationException */ public function itShouldForbidRegisteringTheSameHistogramTwice() { - $registry = new CollectorRegistry( $this->adapter); + $registry = new CollectorRegistry($this->adapter); $registry->registerHistogram('foo', 'metric', 'help'); + + $this->expectException(MetricsRegistrationException::class); $registry->registerHistogram('foo', 'metric', 'help'); } /** * @test - * @expectedException \Prometheus\Exception\MetricsRegistrationException */ public function itShouldForbidRegisteringTheSameHistogramWithDifferentLabels() { - $registry = new CollectorRegistry( $this->adapter); - $registry->registerCounter('foo', 'metric', 'help', array("foo", "bar")); - $registry->registerCounter('foo', 'metric', 'help', array("spam", "eggs")); + $registry = new CollectorRegistry($this->adapter); + $registry->registerCounter('foo', 'metric', 'help', ["foo", "bar"]); + + $this->expectException(MetricsRegistrationException::class); + $registry->registerCounter('foo', 'metric', 'help', ["spam", "eggs"]); } /** * @test - * @expectedException \Prometheus\Exception\MetricsRegistrationException */ public function itShouldForbidRegisteringTheSameGaugeTwice() { - $registry = new CollectorRegistry( $this->adapter); + $registry = new CollectorRegistry($this->adapter); $registry->registerGauge('foo', 'metric', 'help'); + + $this->expectException(MetricsRegistrationException::class); $registry->registerGauge('foo', 'metric', 'help'); } /** * @test - * @expectedException \Prometheus\Exception\MetricsRegistrationException */ public function itShouldForbidRegisteringTheSameGaugeWithDifferentLabels() { - $registry = new CollectorRegistry( $this->adapter); - $registry->registerGauge('foo', 'metric', 'help', array("foo", "bar")); - $registry->registerGauge('foo', 'metric', 'help', array("spam", "eggs")); + $registry = new CollectorRegistry($this->adapter); + $registry->registerGauge('foo', 'metric', 'help', ["foo", "bar"]); + + $this->expectException(MetricsRegistrationException::class); + $registry->registerGauge('foo', 'metric', 'help', ["spam", "eggs"]); } /** * @test - * @expectedException \Prometheus\Exception\MetricNotFoundException */ public function itShouldThrowAnExceptionWhenGettingANonExistentMetric() { - $registry = new CollectorRegistry( $this->adapter); + $registry = new CollectorRegistry($this->adapter); + + $this->expectException(MetricNotFoundException::class); $registry->getGauge("not_here", "go_away"); } @@ -306,5 +324,5 @@ public function itShouldNotRegisterAHistogramTwice() } - public abstract function configureAdapter(); + abstract public function configureAdapter(); } diff --git a/tests/Test/Prometheus/AbstractCounterTest.php b/tests/Test/Prometheus/AbstractCounterTest.php index 188310c..a932939 100644 --- a/tests/Test/Prometheus/AbstractCounterTest.php +++ b/tests/Test/Prometheus/AbstractCounterTest.php @@ -1,9 +1,9 @@ configureAdapter(); } + abstract public function configureAdapter(); + /** * @test */ public function itShouldIncreaseWithLabels() { - $gauge = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->inc(array('lalal', 'lululu')); - $gauge->inc(array('lalal', 'lululu')); - $gauge->inc(array('lalal', 'lululu')); + $counter = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $counter->inc(['lalal', 'lululu']); + $counter->inc(['lalal', 'lululu']); + $counter->inc(['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'type' => Counter::TYPE, 'help' => 'this is for testing', 'name' => 'test_some_metric', - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ + 'labelValues' => ['lalal', 'lululu'], 'value' => 3, 'name' => 'test_some_metric', - 'labelNames' => array() - ), - ) - ) - ) - ) + 'labelNames' => [], + ], + ], + ] + ), + ] ) ); } @@ -63,29 +65,29 @@ public function itShouldIncreaseWithLabels() */ public function itShouldIncreaseWithoutLabelWhenNoLabelsAreDefined() { - $gauge = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing'); - $gauge->inc(); + $counter = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing'); + $counter->inc(); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'type' => Counter::TYPE, 'help' => 'this is for testing', 'name' => 'test_some_metric', - 'labelNames' => array(), - 'samples' => array( - array( - 'labelValues' => array(), + 'labelNames' => [], + 'samples' => [ + [ + 'labelValues' => [], 'value' => 1, 'name' => 'test_some_metric', - 'labelNames' => array() - ), - ) - ) - ) - ) + 'labelNames' => [], + ], + ], + ] + ), + ] ) ); } @@ -95,50 +97,50 @@ public function itShouldIncreaseWithoutLabelWhenNoLabelsAreDefined() */ public function itShouldIncreaseTheCounterByAnArbitraryInteger() { - $gauge = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->inc(array('lalal', 'lululu')); - $gauge->incBy(123, array('lalal', 'lululu')); + $counter = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $counter->inc(['lalal', 'lululu']); + $counter->incBy(123, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'type' => Counter::TYPE, 'help' => 'this is for testing', 'name' => 'test_some_metric', - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ + 'labelValues' => ['lalal', 'lululu'], 'value' => 124, 'name' => 'test_some_metric', - 'labelNames' => array() - ), - ) - ) - ) - ) + 'labelNames' => [], + ], + ], + ] + ), + ] ) ); } /** * @test - * @expectedException \InvalidArgumentException */ public function itShouldRejectInvalidMetricsNames() { + $this->expectException(InvalidArgumentException::class); new Counter($this->adapter, 'test', 'some metric invalid metric', 'help'); } /** * @test - * @expectedException \InvalidArgumentException */ public function itShouldRejectInvalidLabelNames() { - new Counter($this->adapter, 'test', 'some_metric', 'help', array('invalid label')); + $this->expectException(InvalidArgumentException::class); + new Counter($this->adapter, 'test', 'some_metric', 'help', ['invalid label']); } /** @@ -150,30 +152,30 @@ public function itShouldRejectInvalidLabelNames() public function isShouldAcceptAnySequenceOfBasicLatinCharactersForLabelValues($value) { $label = 'foo'; - $histogram = new Counter($this->adapter, 'test', 'some_metric', 'help', array($label)); - $histogram->inc(array($value)); + $histogram = new Counter($this->adapter, 'test', 'some_metric', 'help', [$label]); + $histogram->inc([$value]); $metrics = $this->adapter->collect(); - self::assertInternalType('array', $metrics); - self::assertCount(1, $metrics); - self::assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); + $this->assertIsArray($metrics); + $this->assertCount(1, $metrics); + $this->assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); $metric = reset($metrics); $samples = $metric->getSamples(); - self::assertContainsOnlyInstancesOf(Sample::class, $samples); + $this->assertContainsOnlyInstancesOf(Sample::class, $samples); foreach ($samples as $sample) { $labels = array_combine( array_merge($metric->getLabelNames(), $sample->getLabelNames()), $sample->getLabelValues() ); - self::assertEquals($value, $labels[$label]); + $this->assertEquals($value, $labels[$label]); } } /** - * @see isShouldAcceptArbitraryLabelValues * @return array + * @see isShouldAcceptArbitraryLabelValues */ public function labelValuesDataProvider() { @@ -181,10 +183,8 @@ public function labelValuesDataProvider() // Basic Latin // See https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin for ($i = 32; $i <= 121; $i++) { - $cases['ASCII code ' . $i] = array(chr($i)); + $cases['ASCII code ' . $i] = [chr($i)]; } return $cases; } - - public abstract function configureAdapter(); } diff --git a/tests/Test/Prometheus/AbstractGaugeTest.php b/tests/Test/Prometheus/AbstractGaugeTest.php index 33ad02c..393c087 100644 --- a/tests/Test/Prometheus/AbstractGaugeTest.php +++ b/tests/Test/Prometheus/AbstractGaugeTest.php @@ -1,9 +1,9 @@ configureAdapter(); } + abstract public function configureAdapter(); + /** * @test */ public function itShouldAllowSetWithLabels() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->set(123, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->set(123, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 123, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); $this->assertThat($gauge->getHelp(), $this->equalTo('this is for testing')); @@ -68,24 +70,24 @@ public function itShouldAllowSetWithoutLabelWhenNoLabelsAreDefined() $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array(), - 'samples' => array( - array( + 'labelNames' => [], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 123, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); $this->assertThat($gauge->getHelp(), $this->equalTo('this is for testing')); @@ -102,24 +104,24 @@ public function itShouldAllowSetWithAFloatValue() $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array(), - 'samples' => array( - array( + 'labelNames' => [], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 123.5, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); $this->assertThat($gauge->getHelp(), $this->equalTo('this is for testing')); @@ -131,30 +133,30 @@ public function itShouldAllowSetWithAFloatValue() */ public function itShouldIncrementAValue() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->inc(array('lalal', 'lululu')); - $gauge->incBy(123, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->inc(['lalal', 'lululu']); + $gauge->incBy(123, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 124, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -164,30 +166,30 @@ public function itShouldIncrementAValue() */ public function itShouldIncrementWithFloatValue() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->inc(array('lalal', 'lululu')); - $gauge->incBy(123.5, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->inc(['lalal', 'lululu']); + $gauge->incBy(123.5, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 124.5, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -197,30 +199,30 @@ public function itShouldIncrementWithFloatValue() */ public function itShouldDecrementAValue() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->dec(array('lalal', 'lululu')); - $gauge->decBy(123, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->dec(['lalal', 'lululu']); + $gauge->decBy(123, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => -124, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -230,30 +232,30 @@ public function itShouldDecrementAValue() */ public function itShouldDecrementWithFloatValue() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->dec(array('lalal', 'lululu')); - $gauge->decBy(123, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->dec(['lalal', 'lululu']); + $gauge->decBy(123, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => -124, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -263,50 +265,50 @@ public function itShouldDecrementWithFloatValue() */ public function itShouldOverwriteWhenSettingTwice() { - $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', array('foo', 'bar')); - $gauge->set(123, array('lalal', 'lululu')); - $gauge->set(321, array('lalal', 'lululu')); + $gauge = new Gauge($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $gauge->set(123, ['lalal', 'lululu']); + $gauge->set(321, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Gauge::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 321, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } /** * @test - * @expectedException \InvalidArgumentException */ public function itShouldRejectInvalidMetricsNames() { + $this->expectException(InvalidArgumentException::class); new Gauge($this->adapter, 'test', 'some metric invalid metric', 'help'); } /** * @test - * @expectedException \InvalidArgumentException */ public function itShouldRejectInvalidLabelNames() { - new Gauge($this->adapter, 'test', 'some_metric', 'help', array('invalid label')); + $this->expectException(InvalidArgumentException::class); + new Gauge($this->adapter, 'test', 'some_metric', 'help', ['invalid label']); } /** @@ -318,30 +320,30 @@ public function itShouldRejectInvalidLabelNames() public function isShouldAcceptAnySequenceOfBasicLatinCharactersForLabelValues($value) { $label = 'foo'; - $histogram = new Gauge($this->adapter, 'test', 'some_metric', 'help', array($label)); - $histogram->inc(array($value)); + $histogram = new Gauge($this->adapter, 'test', 'some_metric', 'help', [$label]); + $histogram->inc([$value]); $metrics = $this->adapter->collect(); - self::assertInternalType('array', $metrics); - self::assertCount(1, $metrics); - self::assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); + $this->assertIsArray($metrics); + $this->assertCount(1, $metrics); + $this->assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); $metric = reset($metrics); $samples = $metric->getSamples(); - self::assertContainsOnlyInstancesOf(Sample::class, $samples); + $this->assertContainsOnlyInstancesOf(Sample::class, $samples); foreach ($samples as $sample) { $labels = array_combine( array_merge($metric->getLabelNames(), $sample->getLabelNames()), $sample->getLabelValues() ); - self::assertEquals($value, $labels[$label]); + $this->assertEquals($value, $labels[$label]); } } /** - * @see isShouldAcceptArbitraryLabelValues * @return array + * @see isShouldAcceptArbitraryLabelValues */ public function labelValuesDataProvider() { @@ -349,10 +351,8 @@ public function labelValuesDataProvider() // Basic Latin // See https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin for ($i = 32; $i <= 121; $i++) { - $cases['ASCII code ' . $i] = array(chr($i)); + $cases['ASCII code ' . $i] = [chr($i)]; } return $cases; } - - public abstract function configureAdapter(); } diff --git a/tests/Test/Prometheus/AbstractHistogramTest.php b/tests/Test/Prometheus/AbstractHistogramTest.php index 358fcad..d5f9ebb 100644 --- a/tests/Test/Prometheus/AbstractHistogramTest.php +++ b/tests/Test/Prometheus/AbstractHistogramTest.php @@ -1,30 +1,31 @@ configureAdapter(); } + abstract public function configureAdapter(); + /** * @test */ @@ -35,62 +36,62 @@ public function itShouldObserveWithLabels() 'test', 'some_metric', 'this is for testing', - array('foo', 'bar'), - array(100, 200, 300) + ['foo', 'bar'], + [100, 200, 300] ); - $histogram->observe(123, array('lalal', 'lululu')); - $histogram->observe(245, array('lalal', 'lululu')); + $histogram->observe(123, ['lalal', 'lululu']); + $histogram->observe(245, ['lalal', 'lululu']); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Histogram::TYPE, - 'labelNames' => array('foo', 'bar'), - 'samples' => array( - array( + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('lalal', 'lululu', 100), + 'labelNames' => ['le'], + 'labelValues' => ['lalal', 'lululu', 100], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('lalal', 'lululu', 200), + 'labelNames' => ['le'], + 'labelValues' => ['lalal', 'lululu', 200], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('lalal', 'lululu', 300), + 'labelNames' => ['le'], + 'labelValues' => ['lalal', 'lululu', 300], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('lalal', 'lululu', '+Inf'), + 'labelNames' => ['le'], + 'labelValues' => ['lalal', 'lululu', '+Inf'], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_count', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_sum', - 'labelNames' => array(), - 'labelValues' => array('lalal', 'lululu'), + 'labelNames' => [], + 'labelValues' => ['lalal', 'lululu'], 'value' => 368, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -105,61 +106,61 @@ public function itShouldObserveWithoutLabelWhenNoLabelsAreDefined() 'test', 'some_metric', 'this is for testing', - array(), - array(100, 200, 300) + [], + [100, 200, 300] ); $histogram->observe(245); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Histogram::TYPE, - 'labelNames' => array(), - 'samples' => array( - array( + 'labelNames' => [], + 'samples' => [ + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(100), + 'labelNames' => ['le'], + 'labelValues' => [100], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(200), + 'labelNames' => ['le'], + 'labelValues' => [200], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(300), + 'labelNames' => ['le'], + 'labelValues' => [300], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('+Inf'), + 'labelNames' => ['le'], + 'labelValues' => ['+Inf'], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_count', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_sum', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 245, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -174,62 +175,62 @@ public function itShouldObserveValuesOfTypeDouble() 'test', 'some_metric', 'this is for testing', - array(), - array(0.1, 0.2, 0.3) + [], + [0.1, 0.2, 0.3] ); $histogram->observe(0.11); $histogram->observe(0.3); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Histogram::TYPE, - 'labelNames' => array(), - 'samples' => array( - array( + 'labelNames' => [], + 'samples' => [ + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.1), + 'labelNames' => ['le'], + 'labelValues' => [0.1], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.2), + 'labelNames' => ['le'], + 'labelValues' => [0.2], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.3), + 'labelNames' => ['le'], + 'labelValues' => [0.3], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('+Inf'), + 'labelNames' => ['le'], + 'labelValues' => ['+Inf'], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_count', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_sum', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 0.41, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } @@ -246,180 +247,179 @@ public function itShouldProvideDefaultBuckets() 'test', 'some_metric', 'this is for testing', - array() - + [] ); $histogram->observe(0.11); $histogram->observe(0.03); $this->assertThat( $this->adapter->collect(), $this->equalTo( - array( + [ new MetricFamilySamples( - array( + [ 'name' => 'test_some_metric', 'help' => 'this is for testing', 'type' => Histogram::TYPE, - 'labelNames' => array(), - 'samples' => array( - array( + 'labelNames' => [], + 'samples' => [ + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.005), + 'labelNames' => ['le'], + 'labelValues' => [0.005], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.01), + 'labelNames' => ['le'], + 'labelValues' => [0.01], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.025), + 'labelNames' => ['le'], + 'labelValues' => [0.025], 'value' => 0, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.05), + 'labelNames' => ['le'], + 'labelValues' => [0.05], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.075), + 'labelNames' => ['le'], + 'labelValues' => [0.075], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.1), + 'labelNames' => ['le'], + 'labelValues' => [0.1], 'value' => 1, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.25), + 'labelNames' => ['le'], + 'labelValues' => [0.25], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.5), + 'labelNames' => ['le'], + 'labelValues' => [0.5], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(0.75), + 'labelNames' => ['le'], + 'labelValues' => [0.75], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(1.0), + 'labelNames' => ['le'], + 'labelValues' => [1.0], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(2.5), + 'labelNames' => ['le'], + 'labelValues' => [2.5], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(5), + 'labelNames' => ['le'], + 'labelValues' => [5], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(7.5), + 'labelNames' => ['le'], + 'labelValues' => [7.5], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array(10), + 'labelNames' => ['le'], + 'labelValues' => [10], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_bucket', - 'labelNames' => array('le'), - 'labelValues' => array('+Inf'), + 'labelNames' => ['le'], + 'labelValues' => ['+Inf'], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_count', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 2, - ), - array( + ], + [ 'name' => 'test_some_metric_sum', - 'labelNames' => array(), - 'labelValues' => array(), + 'labelNames' => [], + 'labelValues' => [], 'value' => 0.14, - ) - ) - ) - ) - ) + ], + ], + ] + ), + ] ) ); } /** * @test - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Histogram buckets must be in increasing order */ public function itShouldThrowAnExceptionWhenTheBucketSizesAreNotIncreasing() { - new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', array(), array(1, 1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Histogram buckets must be in increasing order'); + new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', [], [1, 1]); } /** * @test - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Histogram must have at least one bucket */ public function itShouldThrowAnExceptionWhenThereIsLessThanOneBucket() { - new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', array(), array()); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Histogram must have at least one bucket'); + new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', [], []); } /** * @test - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Histogram cannot have a label named */ public function itShouldThrowAnExceptionWhenThereIsALabelNamedLe() { - new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', array('le'), array(1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Histogram cannot have a label named'); + new Histogram($this->adapter, 'test', 'some_metric', 'this is for testing', ['le'], [1]); } /** * @test - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid metric name */ public function itShouldRejectInvalidMetricsNames() { - new Histogram($this->adapter, 'test', 'some invalid metric', 'help', array(), array(1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid metric name'); + new Histogram($this->adapter, 'test', 'some invalid metric', 'help', [], [1]); } /** * @test - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid label name */ public function itShouldRejectInvalidLabelNames() { - new Histogram($this->adapter, 'test', 'some_metric', 'help', array('invalid label'), array(1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid label name'); + new Histogram($this->adapter, 'test', 'some_metric', 'help', ['invalid label'], [1]); } /** @@ -431,30 +431,61 @@ public function itShouldRejectInvalidLabelNames() public function isShouldAcceptAnySequenceOfBasicLatinCharactersForLabelValues($value) { $label = 'foo'; - $histogram = new Histogram($this->adapter, 'test', 'some_metric', 'help', array($label), array(1)); - $histogram->observe(1, array($value)); + $histogram = new Histogram($this->adapter, 'test', 'some_metric', 'help', [$label], [1]); + $histogram->observe(1, [$value]); $metrics = $this->adapter->collect(); - self::assertInternalType('array', $metrics); - self::assertCount(1, $metrics); - self::assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); + $this->assertIsArray($metrics); + $this->assertCount(1, $metrics); + $this->assertContainsOnlyInstancesOf(MetricFamilySamples::class, $metrics); $metric = reset($metrics); $samples = $metric->getSamples(); - self::assertContainsOnlyInstancesOf(Sample::class, $samples); + $this->assertContainsOnlyInstancesOf(Sample::class, $samples); foreach ($samples as $sample) { $labels = array_combine( array_merge($metric->getLabelNames(), $sample->getLabelNames()), $sample->getLabelValues() ); - self::assertEquals($value, $labels[$label]); + $this->assertEquals($value, $labels[$label]); } } /** - * @see isShouldAcceptArbitraryLabelValues + * @test + */ + public function itShouldBeAbleToGenerateExponentialBucketsGivenSpecificBounds() + { + $start = 0.05; + $growthFactor = 1.5; + $numberOfbuckets = 14; + + $generatedBuckets = Histogram::exponentialBuckets($start, $growthFactor, $numberOfbuckets); + + $expectedBuckets = [ + 0.05, + 0.075, + 0.1125, + 0.16875, + 0.253125, + 0.3796875, + 0.56953125, + 0.854296875, + 1.2814453125, + 1.92216796875, + 2.883251953125, + 4.3248779296875, + 6.4873168945313, + 9.7309753417969, + ]; + + $this->assertEquals($generatedBuckets, $expectedBuckets); + } + + /** * @return array + * @see isShouldAcceptArbitraryLabelValues */ public function labelValuesDataProvider() { @@ -462,10 +493,8 @@ public function labelValuesDataProvider() // Basic Latin // See https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin for ($i = 32; $i <= 121; $i++) { - $cases['ASCII code ' . $i] = array(chr($i)); + $cases['ASCII code ' . $i] = [chr($i)]; } return $cases; } - - public abstract function configureAdapter(); } diff --git a/tests/Test/Prometheus/InMemory/CollectorRegistryTest.php b/tests/Test/Prometheus/InMemory/CollectorRegistryTest.php index 7309708..5e6b9c7 100644 --- a/tests/Test/Prometheus/InMemory/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/InMemory/CollectorRegistryTest.php @@ -1,6 +1,5 @@ adapter->flushMemory(); } } - diff --git a/tests/Test/Prometheus/PushGatewayTest.php b/tests/Test/Prometheus/PushGatewayTest.php new file mode 100644 index 0000000..e04dbf1 --- /dev/null +++ b/tests/Test/Prometheus/PushGatewayTest.php @@ -0,0 +1,79 @@ +createMock(CollectorRegistry::class); + $mockedCollectorRegistry->method('getMetricFamilySamples')->with()->willReturn([ + $this->createMock(MetricFamilySamples::class) + ]); + + $mockHandler = new MockHandler([ + new Response(200), + new Response(202), + ]); + $handler = HandlerStack::create($mockHandler); + $client = new Client(['handler' => $handler]); + + $pushGateway = new PushGateway('http://foo.bar', $client); + $pushGateway->push($mockedCollectorRegistry, 'foo'); + } + + /** + * @test + * + * @doesNotPerformAnyAssertions + */ + public function invalidResponseShouldThrowRuntimeException(): void + { + $this->expectException(\RuntimeException::class); + + $mockedCollectorRegistry = $this->createMock(CollectorRegistry::class); + $mockedCollectorRegistry->method('getMetricFamilySamples')->with()->willReturn([ + $this->createMock(MetricFamilySamples::class) + ]); + + $mockHandler = new MockHandler([ + new Response(201), + new Response(300), + ]); + $handler = HandlerStack::create($mockHandler); + $client = new Client(['handler' => $handler]); + + $pushGateway = new PushGateway('http://foo.bar', $client); + $pushGateway->push($mockedCollectorRegistry, 'foo'); + } + + /** + * @test + */ + public function clientGetsDefinedIfNotSpecified(): void + { + $this->expectException(\RuntimeException::class); + + $mockedCollectorRegistry = $this->createMock(CollectorRegistry::class); + $mockedCollectorRegistry->method('getMetricFamilySamples')->with()->willReturn([ + $this->createMock(MetricFamilySamples::class) + ]); + + $pushGateway = new PushGateway('http://foo.bar'); + $pushGateway->push($mockedCollectorRegistry, 'foo'); + } +} diff --git a/tests/Test/Prometheus/Redis/CollectorRegistryTest.php b/tests/Test/Prometheus/Redis/CollectorRegistryTest.php index 2e69ce9..fbf53b9 100644 --- a/tests/Test/Prometheus/Redis/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/Redis/CollectorRegistryTest.php @@ -1,9 +1,7 @@ adapter = new Redis(array('host' => REDIS_HOST)); + $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Redis/CounterTest.php b/tests/Test/Prometheus/Redis/CounterTest.php index 088f9dd..4aea278 100644 --- a/tests/Test/Prometheus/Redis/CounterTest.php +++ b/tests/Test/Prometheus/Redis/CounterTest.php @@ -1,6 +1,5 @@ adapter = new Redis(array('host' => REDIS_HOST)); + $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Redis/CounterWithPrefixTest.php b/tests/Test/Prometheus/Redis/CounterWithPrefixTest.php new file mode 100644 index 0000000..0409140 --- /dev/null +++ b/tests/Test/Prometheus/Redis/CounterWithPrefixTest.php @@ -0,0 +1,24 @@ +connect(REDIS_HOST); + + $connection->setOption(\Redis::OPT_PREFIX, 'prefix:'); + + $this->adapter = Redis::fromExistingConnection($connection); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Redis/GaugeTest.php b/tests/Test/Prometheus/Redis/GaugeTest.php index c359037..6ffd300 100644 --- a/tests/Test/Prometheus/Redis/GaugeTest.php +++ b/tests/Test/Prometheus/Redis/GaugeTest.php @@ -1,6 +1,5 @@ adapter = new Redis(array('host' => REDIS_HOST)); + $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Redis/GaugeWithPrefixTest.php b/tests/Test/Prometheus/Redis/GaugeWithPrefixTest.php new file mode 100644 index 0000000..1ba4d0e --- /dev/null +++ b/tests/Test/Prometheus/Redis/GaugeWithPrefixTest.php @@ -0,0 +1,24 @@ +connect(REDIS_HOST); + + $connection->setOption(\Redis::OPT_PREFIX, 'prefix:'); + + $this->adapter = Redis::fromExistingConnection($connection); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Redis/HistogramTest.php b/tests/Test/Prometheus/Redis/HistogramTest.php index da15c25..40fd314 100644 --- a/tests/Test/Prometheus/Redis/HistogramTest.php +++ b/tests/Test/Prometheus/Redis/HistogramTest.php @@ -1,6 +1,5 @@ adapter = new Redis(array('host' => REDIS_HOST)); + $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->flushRedis(); } } diff --git a/tests/Test/Prometheus/Redis/HistogramWithPrefixTest.php b/tests/Test/Prometheus/Redis/HistogramWithPrefixTest.php new file mode 100644 index 0000000..4c25388 --- /dev/null +++ b/tests/Test/Prometheus/Redis/HistogramWithPrefixTest.php @@ -0,0 +1,24 @@ +connect(REDIS_HOST); + + $connection->setOption(\Redis::OPT_PREFIX, 'prefix:'); + + $this->adapter = Redis::fromExistingConnection($connection); + $this->adapter->flushRedis(); + } +} diff --git a/tests/Test/Prometheus/Storage/RedisTest.php b/tests/Test/Prometheus/Storage/RedisTest.php index 8175475..9f2df78 100644 --- a/tests/Test/Prometheus/Storage/RedisTest.php +++ b/tests/Test/Prometheus/Storage/RedisTest.php @@ -1,22 +1,39 @@ 'doesntexist.test')); + $redis = new Redis(['host' => '/dev/null']); + + $this->expectException(StorageException::class); + $this->expectExceptionMessage("Can't connect to Redis server"); + + $redis->collect(); $redis->flushRedis(); } + /** + * @test + */ + public function itShouldThrowExceptionWhenInjectedRedisIsNotConnected() + { + $connection = new \Redis(); + + $this->expectException(StorageException::class); + $this->expectExceptionMessage('Connection to Redis server not established'); + + Redis::fromExistingConnection($connection); + } }