From d4b1349a5a709cb5dd65018f7a76c18d4621d945 Mon Sep 17 00:00:00 2001 From: Edgar Date: Wed, 10 Mar 2021 20:35:23 +0300 Subject: [PATCH] WIP: Draft --- src/Prometheus/Collector.php | 20 +++ src/Prometheus/Counter.php | 18 +++ src/Prometheus/Gauge.php | 18 +++ src/Prometheus/Histogram.php | 19 +++ src/Prometheus/Storage/APC.php | 15 +++ src/Prometheus/Storage/Adapter.php | 27 +++- src/Prometheus/Storage/InMemory.php | 15 +++ src/Prometheus/Storage/Redis.php | 189 ++++++++++++++++++++++++++++ 8 files changed, 317 insertions(+), 4 deletions(-) diff --git a/src/Prometheus/Collector.php b/src/Prometheus/Collector.php index cb17656d..1b05f97f 100644 --- a/src/Prometheus/Collector.php +++ b/src/Prometheus/Collector.php @@ -98,6 +98,26 @@ protected function assertLabelsAreDefinedCorrectly(array $labels): void } } + /** + * @param array[] $labelValuesSet + */ + protected function assertValidInitLabelsValuesSet(array $labelValuesSet = []): void + { + $initLabelsKeys = array_keys($labelValuesSet); + + $forgottenLabels = array_diff($this->getLabelNames(), $initLabelsKeys); + if (count($forgottenLabels) > 0) { + throw new InvalidArgumentException("Missing label values for: " . implode(',', $forgottenLabels)); + } + + $unnecessaryLabels = array_diff($initLabelsKeys, $this->getLabelNames()); + if (count($unnecessaryLabels) > 0) { + throw new InvalidArgumentException( + "Some labels values are not mentioned on metric creation:" . implode(',', $unnecessaryLabels) + ); + } + } + /** * @param string $metricName */ diff --git a/src/Prometheus/Counter.php b/src/Prometheus/Counter.php index 6fa20022..18fb176e 100644 --- a/src/Prometheus/Counter.php +++ b/src/Prometheus/Counter.php @@ -46,4 +46,22 @@ public function incBy($count, array $labels = []): void ] ); } + + /** + * @param array[] $labelValuesSet + */ + public function init(array $labelValuesSet = []): void + { + $this->assertValidInitLabelsValuesSet($labelValuesSet); + + $this->storageAdapter->initCounter( + [ + 'name' => $this->getName(), + 'help' => $this->getHelp(), + 'type' => $this->getType(), + 'labelNames' => $this->getLabelNames(), + 'labelValuesSet' => $labelValuesSet, + ] + ); + } } diff --git a/src/Prometheus/Gauge.php b/src/Prometheus/Gauge.php index e1ccbf6c..0883e35c 100644 --- a/src/Prometheus/Gauge.php +++ b/src/Prometheus/Gauge.php @@ -84,4 +84,22 @@ public function decBy(int $value, array $labels = []): void { $this->incBy(-$value, $labels); } + + /** + * @param array[] $labelValuesSet + */ + public function init(array $labelValuesSet = []): void + { + $this->assertValidInitLabelsValuesSet($labelValuesSet); + + $this->storageAdapter->initGauge( + [ + 'name' => $this->getName(), + 'help' => $this->getHelp(), + 'type' => $this->getType(), + 'labelNames' => $this->getLabelNames(), + 'labelValuesSet' => $labelValuesSet, + ] + ); + } } diff --git a/src/Prometheus/Histogram.php b/src/Prometheus/Histogram.php index 0e8fc926..e2621994 100644 --- a/src/Prometheus/Histogram.php +++ b/src/Prometheus/Histogram.php @@ -133,6 +133,25 @@ public function observe(float $value, array $labels = []): void ); } + /** + * @param array[] $labelValuesSet + */ + public function init(array $labelValuesSet = []): void + { + $this->assertValidInitLabelsValuesSet($labelValuesSet); + + $this->storageAdapter->initHistogram( + [ + 'name' => $this->getName(), + 'help' => $this->getHelp(), + 'type' => $this->getType(), + 'labelNames' => $this->getLabelNames(), + 'labelValuesSet' => $labelValuesSet, + 'buckets' => $this->buckets, + ] + ); + } + /** * @return string */ diff --git a/src/Prometheus/Storage/APC.php b/src/Prometheus/Storage/APC.php index 179e4b07..9d534a7c 100644 --- a/src/Prometheus/Storage/APC.php +++ b/src/Prometheus/Storage/APC.php @@ -124,6 +124,21 @@ public function updateCounter(array $data): void } } + public function initHistogram(array $data): void + { + // TODO: Implement initHistogram() method. + } + + public function initGauge(array $data): void + { + // TODO: Implement initGauge() method. + } + + public function initCounter(array $data): void + { + // TODO: Implement initCounter() method. + } + /** * @deprecated use replacement method wipeStorage from Adapter interface * diff --git a/src/Prometheus/Storage/Adapter.php b/src/Prometheus/Storage/Adapter.php index d3547e65..9f3b7250 100644 --- a/src/Prometheus/Storage/Adapter.php +++ b/src/Prometheus/Storage/Adapter.php @@ -13,6 +13,14 @@ interface Adapter const COMMAND_INCREMENT_FLOAT = 2; const COMMAND_SET = 3; + /** + * Removes all previously stored metrics from underlying storage + * + * @throws StorageException + * @return void + */ + public function wipeStorage(): void; + /** * @return MetricFamilySamples[] */ @@ -37,10 +45,21 @@ public function updateGauge(array $data): void; public function updateCounter(array $data): void; /** - * Removes all previously stored metrics from underlying storage - * - * @throws StorageException + * @param mixed[] $data * @return void */ - public function wipeStorage(): void; + public function initHistogram(array $data): void; + + + /** + * @param mixed[] $data + * @return void + */ + public function initGauge(array $data): void; + + /** + * @param mixed[] $data + * @return void + */ + public function initCounter(array $data): void; } diff --git a/src/Prometheus/Storage/InMemory.php b/src/Prometheus/Storage/InMemory.php index 46445f8c..6d82c6e2 100644 --- a/src/Prometheus/Storage/InMemory.php +++ b/src/Prometheus/Storage/InMemory.php @@ -244,6 +244,21 @@ public function updateCounter(array $data): void } } + public function initHistogram(array $data): void + { + // TODO: Implement initHistogram() method. + } + + public function initGauge(array $data): void + { + // TODO: Implement initGauge() method. + } + + public function initCounter(array $data): void + { + // TODO: Implement initCounter() method. + } + /** * @param mixed[] $data * @param string|int $bucket diff --git a/src/Prometheus/Storage/Redis.php b/src/Prometheus/Storage/Redis.php index d69280ff..dd11033c 100644 --- a/src/Prometheus/Storage/Redis.php +++ b/src/Prometheus/Storage/Redis.php @@ -307,6 +307,155 @@ public function updateCounter(array $data): void ); } + /** + * @param mixed[] $data + * @throws StorageException + */ + public function initHistogram(array $data): void + { + $this->ensureOpenConnection(); + + $metricKey = $this->toMetricKey($data); + + // If hash exists, we skip init + if ((bool) $this->redis->hLen($metricKey)) { + return; + } + + $bucketsToSet = $data['buckets']; + array_unshift($bucketsToSet, 'sum'); + $bucketsToSet[] = '+Inf'; + + $labelsCartesian = $this->cartesian($data['labelValuesSet']); + + $values = []; + foreach ($bucketsToSet as $bucket) { + foreach ($labelsCartesian as $labelValues) { + $values[] = json_encode(['b' => $bucket, 'labelValues' => array_values($labelValues)]); + } + } + + $valuesString = $this->makeLuaValuesString($values); + + // metadata + unset($data['labelValuesSet']); + + $this->redis->eval( + <<ensureOpenConnection(); + + $metricKey = $this->toMetricKey($data); + + // If hash exists, we skip init + if ((bool) $this->redis->hLen($metricKey)) { + return; + } + + $labelsCartesian = $this->cartesian($data['labelValuesSet']); + + $values = []; + foreach ($labelsCartesian as $labelValues) { + $values[] = json_encode(array_values($labelValues)); + } + + $valuesString = $this->makeLuaValuesString($values); + + // metadata + unset($data['labelValuesSet']); + + $this->redis->eval( + <<ensureOpenConnection(); + + $metricKey = $this->toMetricKey($data); + + // If hash exists, we skip init + if ((bool) $this->redis->hLen($metricKey)) { + return; + } + + $labelsCartesian = $this->cartesian($data['labelValuesSet']); + + $values = []; + foreach ($labelsCartesian as $labelValues) { + $values[] = json_encode(array_values($labelValues)); + } + + $valuesString = $this->makeLuaValuesString($values); + + // metadata + unset($data['labelValuesSet']); + + $this->redis->eval( + << $values) { + $append = []; + + foreach ($result as $product) { + foreach ($values as $item) { + $product[$key] = $item; + $append[] = $product; + } + } + + $result = $append; + } + + return $result; + } + + /** + * @param mixed[] $values + * @return string + */ + private function makeLuaValuesString(array $values): string + { + $values = array_map( + static function (string $value): string { + return '"' . addslashes($value) . '"'; + }, + $values + ); + + return implode(', ', $values); + } }