From ac7f0edc103bc7f405119a434797b01a4f923dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Fri, 6 Nov 2020 13:25:50 +0100 Subject: [PATCH 1/3] Remove usage of apcu_inc for counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Kämmerling --- src/Prometheus/Storage/APC.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Prometheus/Storage/APC.php b/src/Prometheus/Storage/APC.php index 29899be8..53cd9929 100644 --- a/src/Prometheus/Storage/APC.php +++ b/src/Prometheus/Storage/APC.php @@ -91,11 +91,21 @@ public function updateGauge(array $data): void */ public function updateCounter(array $data): void { - $new = apcu_add($this->valueKey($data), 0); - if ($new) { + $valueKey = $this->valueKey($data); + // Check if value key already exists + if (apcu_exists($this->valueKey($data)) === false) { + apcu_add($this->valueKey($data), 0); apcu_store($this->metaKey($data), json_encode($this->metaData($data))); } - apcu_inc($this->valueKey($data), $data['value']); + + // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 + $done = false; + while (!$done) { + $old = apcu_fetch($valueKey); + if ($old !== false) { + $done = apcu_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + } + } } /** @@ -180,7 +190,7 @@ private function collectCounters(): array 'name' => $metaData['name'], 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $value['value'], + 'value' => $this->fromInteger($value['value']), ]; } $this->sortSamples($data['samples']); From 0502df1f764de1416b3158e3c29fa5945042cb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Fri, 6 Nov 2020 14:01:05 +0100 Subject: [PATCH 2/3] Allow incrementing counters with a float MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Kämmerling --- src/Prometheus/Counter.php | 6 ++-- tests/Test/Prometheus/AbstractCounterTest.php | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Prometheus/Counter.php b/src/Prometheus/Counter.php index 115950eb..6fa20022 100644 --- a/src/Prometheus/Counter.php +++ b/src/Prometheus/Counter.php @@ -27,10 +27,10 @@ public function inc(array $labels = []): void } /** - * @param int $count e.g. 2 + * @param int|float $count e.g. 2 * @param mixed[] $labels e.g. ['status', 'opcode'] */ - public function incBy(int $count, array $labels = []): void + public function incBy($count, array $labels = []): void { $this->assertLabelsAreDefinedCorrectly($labels); @@ -42,7 +42,7 @@ public function incBy(int $count, array $labels = []): void 'labelNames' => $this->getLabelNames(), 'labelValues' => $labels, 'value' => $count, - 'command' => Adapter::COMMAND_INCREMENT_INTEGER, + 'command' => is_float($count) ? Adapter::COMMAND_INCREMENT_FLOAT : Adapter::COMMAND_INCREMENT_INTEGER, ] ); } diff --git a/tests/Test/Prometheus/AbstractCounterTest.php b/tests/Test/Prometheus/AbstractCounterTest.php index dc2a4987..f21e38f2 100644 --- a/tests/Test/Prometheus/AbstractCounterTest.php +++ b/tests/Test/Prometheus/AbstractCounterTest.php @@ -127,6 +127,40 @@ public function itShouldIncreaseTheCounterByAnArbitraryInteger(): void ); } + /** + * @test + */ + public function itShouldIncreaseTheCounterWithAFloat(): void + { + $counter = new Counter($this->adapter, 'test', 'some_metric', 'this is for testing', ['foo', 'bar']); + $counter->inc(['lalal', 'lululu']); + $counter->incBy(1.5, ['lalal', 'lululu']); + self::assertThat( + $this->adapter->collect(), + self::equalTo( + [ + new MetricFamilySamples( + [ + 'type' => Counter::TYPE, + 'help' => 'this is for testing', + 'name' => 'test_some_metric', + 'labelNames' => ['foo', 'bar'], + 'samples' => [ + [ + 'labelValues' => ['lalal', 'lululu'], + 'value' => 2.5, + 'name' => 'test_some_metric', + 'labelNames' => [], + ], + ], + ] + ), + ] + ) + ); + } + + /** * @test */ From 7e3186ed26436174dc0610b5ba443fdae66ff6e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Tue, 17 Nov 2020 11:52:11 +0100 Subject: [PATCH 3/3] Rename toInteger and fromInteger to be more meaningful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Kämmerling --- src/Prometheus/Storage/APC.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Prometheus/Storage/APC.php b/src/Prometheus/Storage/APC.php index 53cd9929..00c1f33c 100644 --- a/src/Prometheus/Storage/APC.php +++ b/src/Prometheus/Storage/APC.php @@ -30,7 +30,7 @@ public function updateHistogram(array $data): void { // Initialize the sum $sumKey = $this->histogramBucketValueKey($data, 'sum'); - $new = apcu_add($sumKey, $this->toInteger(0)); + $new = apcu_add($sumKey, $this->toBinaryRepresentationAsInteger(0)); // If sum does not exist, assume a new histogram and store the metadata if ($new) { @@ -43,7 +43,7 @@ public function updateHistogram(array $data): void while (!$done) { $old = apcu_fetch($sumKey); if ($old !== false) { - $done = apcu_cas($sumKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + $done = apcu_cas($sumKey, $old, $this->toBinaryRepresentationAsInteger($this->fromBinaryRepresentationAsInteger($old) + $data['value'])); } } @@ -68,10 +68,10 @@ public function updateGauge(array $data): void { $valueKey = $this->valueKey($data); if ($data['command'] === Adapter::COMMAND_SET) { - apcu_store($valueKey, $this->toInteger($data['value'])); + apcu_store($valueKey, $this->toBinaryRepresentationAsInteger($data['value'])); apcu_store($this->metaKey($data), json_encode($this->metaData($data))); } else { - $new = apcu_add($valueKey, $this->toInteger(0)); + $new = apcu_add($valueKey, $this->toBinaryRepresentationAsInteger(0)); if ($new) { apcu_store($this->metaKey($data), json_encode($this->metaData($data))); } @@ -80,7 +80,7 @@ public function updateGauge(array $data): void while (!$done) { $old = apcu_fetch($valueKey); if ($old !== false) { - $done = apcu_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + $done = apcu_cas($valueKey, $old, $this->toBinaryRepresentationAsInteger($this->fromBinaryRepresentationAsInteger($old) + $data['value'])); } } } @@ -103,7 +103,7 @@ public function updateCounter(array $data): void while (!$done) { $old = apcu_fetch($valueKey); if ($old !== false) { - $done = apcu_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + $done = apcu_cas($valueKey, $old, $this->toBinaryRepresentationAsInteger($this->fromBinaryRepresentationAsInteger($old) + $data['value'])); } } } @@ -190,7 +190,7 @@ private function collectCounters(): array 'name' => $metaData['name'], 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $this->fromInteger($value['value']), + 'value' => $this->fromBinaryRepresentationAsInteger($value['value']), ]; } $this->sortSamples($data['samples']); @@ -221,7 +221,7 @@ private function collectGauges(): array 'name' => $metaData['name'], 'labelNames' => [], 'labelValues' => $this->decodeLabelValues($labelValues), - 'value' => $this->fromInteger($value['value']), + 'value' => $this->fromBinaryRepresentationAsInteger($value['value']), ]; } @@ -298,7 +298,7 @@ private function collectHistograms(): array 'name' => $metaData['name'] . '_sum', 'labelNames' => [], 'labelValues' => $decodedLabelValues, - 'value' => $this->fromInteger($histogramBuckets[$labelValues]['sum']), + 'value' => $this->fromBinaryRepresentationAsInteger($histogramBuckets[$labelValues]['sum']), ]; } $histograms[] = new MetricFamilySamples($data); @@ -310,7 +310,7 @@ private function collectHistograms(): array * @param mixed $val * @return int */ - private function toInteger($val): int + private function toBinaryRepresentationAsInteger($val): int { return unpack('Q', pack('d', $val))[1]; } @@ -319,7 +319,7 @@ private function toInteger($val): int * @param mixed $val * @return float */ - private function fromInteger($val): float + private function fromBinaryRepresentationAsInteger($val): float { return unpack('d', pack('Q', $val))[1]; }