From 0e837eabbd744506bfaea3793632d1eed7a15140 Mon Sep 17 00:00:00 2001 From: Garry Filakhtov Date: Tue, 3 Sep 2024 17:55:38 +1000 Subject: [PATCH] Ensure that label values are strings in APCNg adapter APCNg is crashing if the label value provided wasn't a string, but something that can be coerced to string (such as int). The problem occurs in two different places: - when a metric is emitted, the `storeLabelKeys()` calls into `addItemToKey()` which has its second parameter type hinted as a `string` and throws a type error if anything else is passed. This results in partially stored state; - when trying to scrape metrics with partially stored state, the `APCng::collect()` will try to build all the permutations and expect all the key-value pairs for labels to exist, but numeric label values aren't persisted and so it will cause the `Undefined array key` error as reported in #154; This change ensures that label values are cast to the string type before encoding them and using as APC keys. Signed-off-by: Garry Filakhtov --- src/Prometheus/Storage/APCng.php | 4 ++-- tests/Test/Prometheus/Storage/APCngTest.php | 23 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Prometheus/Storage/APCng.php b/src/Prometheus/Storage/APCng.php index 5448fc9..416a46f 100644 --- a/src/Prometheus/Storage/APCng.php +++ b/src/Prometheus/Storage/APCng.php @@ -254,7 +254,7 @@ private function storeLabelKeys(array $data): void $data['name'], $label, 'label' - ]), isset($data['labelValues']) ? $data['labelValues'][$seq] : ''); // may not need the isset check + ]), isset($data['labelValues']) ? (string)$data['labelValues'][$seq] : ''); // may not need the isset check } } @@ -860,7 +860,7 @@ private function sortSamples(array &$samples): void */ private function encodeLabelValues(array $values): string { - $json = json_encode($values); + $json = json_encode(array_map("strval", $values)); if (false === $json) { throw new RuntimeException(json_last_error_msg()); } diff --git a/tests/Test/Prometheus/Storage/APCngTest.php b/tests/Test/Prometheus/Storage/APCngTest.php index 8bf2ea2..740947e 100644 --- a/tests/Test/Prometheus/Storage/APCngTest.php +++ b/tests/Test/Prometheus/Storage/APCngTest.php @@ -42,6 +42,29 @@ public function itShouldNotClearWholeAPCacheOnFlush(): void ); } + /** + * @test + */ + public function nonStringLabelValuesAreCastToStrings(): void + { + apcu_clear_cache(); + + $adapter = new APCng(); + $registry = new CollectorRegistry($adapter); + $registry->getOrRegisterCounter( + 'ns', + 'int_label_values', + 'test int label values', + ['int_label'], + )->inc([3]); + + $jsonLabels = json_encode(["3"]); + $encodedLabels = base64_encode($jsonLabels); + + $counter = apcu_fetch("prom:counter:ns_int_label_values:{$encodedLabels}:value"); + $this->assertSame(1000, $counter); + } + /** * @test */