From ec889cd317bae9ccbd1d02d521b7d1562d6c98df Mon Sep 17 00:00:00 2001 From: Karol Sykala Date: Thu, 17 Sep 2026 12:46:03 +0200 Subject: [PATCH 1/3] write __meta unconditionally --- src/Prometheus/Storage/AbstractRedis.php | 20 ++----- src/Prometheus/Storage/RedisNg.php | 20 ++----- tests/Test/Prometheus/AbstractCounterTest.php | 55 +++++++++++++++++++ tests/Test/Prometheus/AbstractGaugeTest.php | 55 +++++++++++++++++++ 4 files changed, 118 insertions(+), 32 deletions(-) diff --git a/src/Prometheus/Storage/AbstractRedis.php b/src/Prometheus/Storage/AbstractRedis.php index 35bbde7a..785de482 100644 --- a/src/Prometheus/Storage/AbstractRedis.php +++ b/src/Prometheus/Storage/AbstractRedis.php @@ -217,18 +217,8 @@ public function updateGauge(array $data): void $this->redis->eval( <<<'LUA' local result = redis.call(ARGV[1], KEYS[1], ARGV[2], ARGV[3]) - -if ARGV[1] == 'hSet' then - if result == 1 then - redis.call('hSet', KEYS[1], '__meta', ARGV[4]) - redis.call('sAdd', KEYS[2], KEYS[1]) - end -else - if result == ARGV[3] then - redis.call('hSet', KEYS[1], '__meta', ARGV[4]) - redis.call('sAdd', KEYS[2], KEYS[1]) - end -end +redis.call('hSet', KEYS[1], '__meta', ARGV[4]) +redis.call('sAdd', KEYS[2], KEYS[1]) LUA , [ @@ -256,10 +246,8 @@ public function updateCounter(array $data): void $this->redis->eval( <<<'LUA' local result = redis.call(ARGV[1], KEYS[1], ARGV[3], ARGV[2]) -local added = redis.call('sAdd', KEYS[2], KEYS[1]) -if added == 1 then - redis.call('hMSet', KEYS[1], '__meta', ARGV[4]) -end +redis.call('sAdd', KEYS[2], KEYS[1]) +redis.call('hMSet', KEYS[1], '__meta', ARGV[4]) return result LUA , diff --git a/src/Prometheus/Storage/RedisNg.php b/src/Prometheus/Storage/RedisNg.php index a5bfc362..96bb38ed 100644 --- a/src/Prometheus/Storage/RedisNg.php +++ b/src/Prometheus/Storage/RedisNg.php @@ -335,18 +335,8 @@ public function updateGauge(array $data): void $this->redis->eval( <<redis->eval( <<adapter, false); + + $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); + $counterV1->inc(['val1']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $this->adapter->wipeStorage(); + $registry = new CollectorRegistry($this->adapter, false); + + $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); + $counterV2->inc(['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + + $renderer = new RenderTextFormat(); + $output = $renderer->render($metrics); + self::assertStringContainsString('test_some_metric{foo="val1",bar="val2"} 1', $output); + } + + /** + * @test + */ + public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); + $counterV1->inc(['val1']); + + $registry = new CollectorRegistry($this->adapter, false); + + $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); + $counterV2->inc(['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + + $renderer = new RenderTextFormat(); + $output = $renderer->render($metrics); + self::assertStringContainsString('test_some_metric', $output); + } } diff --git a/tests/Test/Prometheus/AbstractGaugeTest.php b/tests/Test/Prometheus/AbstractGaugeTest.php index 1e312729..92e73477 100644 --- a/tests/Test/Prometheus/AbstractGaugeTest.php +++ b/tests/Test/Prometheus/AbstractGaugeTest.php @@ -6,8 +6,10 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use Prometheus\CollectorRegistry; use Prometheus\Gauge; use Prometheus\MetricFamilySamples; +use Prometheus\RenderTextFormat; use Prometheus\Sample; use Prometheus\Storage\Adapter; @@ -357,4 +359,57 @@ public function labelValuesDataProvider(): array } return $cases; } + + /** + * @test + */ + public function itShouldUpdateMetadataWhenLabelSchemaChanges(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); + $gaugeV1->set(42, ['val1']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $this->adapter->wipeStorage(); + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); + $gaugeV2->set(99, ['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + + $renderer = new RenderTextFormat(); + $output = $renderer->render($metrics); + self::assertStringContainsString('test_some_metric{foo="val1",bar="val2"} 99', $output); + } + + /** + * @test + */ + public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); + $gaugeV1->set(42, ['val1']); + + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); + $gaugeV2->set(99, ['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + + $renderer = new RenderTextFormat(); + $output = $renderer->render($metrics); + self::assertStringContainsString('test_some_metric', $output); + } } From d8168d9313f51c37253fd0355200649fb5f0404b Mon Sep 17 00:00:00 2001 From: Karol Sykala Date: Thu, 17 Sep 2026 12:51:36 +0200 Subject: [PATCH 2/3] update tests --- tests/Test/Prometheus/AbstractCounterTest.php | 10 +++++----- tests/Test/Prometheus/AbstractGaugeTest.php | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Test/Prometheus/AbstractCounterTest.php b/tests/Test/Prometheus/AbstractCounterTest.php index 46e395b0..b4aef41e 100644 --- a/tests/Test/Prometheus/AbstractCounterTest.php +++ b/tests/Test/Prometheus/AbstractCounterTest.php @@ -258,13 +258,17 @@ public function itShouldUpdateMetadataWhenLabelSchemaChanges(): void /** * @test */ - public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): void + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void { $registry = new CollectorRegistry($this->adapter, false); $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); $counterV1->inc(['val1']); + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + $registry = new CollectorRegistry($this->adapter, false); $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); @@ -273,9 +277,5 @@ public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): v $metrics = $this->adapter->collect(); self::assertCount(1, $metrics); self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); - - $renderer = new RenderTextFormat(); - $output = $renderer->render($metrics); - self::assertStringContainsString('test_some_metric', $output); } } diff --git a/tests/Test/Prometheus/AbstractGaugeTest.php b/tests/Test/Prometheus/AbstractGaugeTest.php index 92e73477..95fd56af 100644 --- a/tests/Test/Prometheus/AbstractGaugeTest.php +++ b/tests/Test/Prometheus/AbstractGaugeTest.php @@ -392,13 +392,17 @@ public function itShouldUpdateMetadataWhenLabelSchemaChanges(): void /** * @test */ - public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): void + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void { $registry = new CollectorRegistry($this->adapter, false); $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); $gaugeV1->set(42, ['val1']); + $metrics = $this->adapter->collect(); + self::assertCount(1, $metrics); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + $registry = new CollectorRegistry($this->adapter, false); $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); @@ -407,9 +411,5 @@ public function itShouldRenderWithoutErrorAfterLabelSchemaChangeWithoutWipe(): v $metrics = $this->adapter->collect(); self::assertCount(1, $metrics); self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); - - $renderer = new RenderTextFormat(); - $output = $renderer->render($metrics); - self::assertStringContainsString('test_some_metric', $output); } } From 05fa7cfbd2c29c164a4fd1fa28d0eb36a844ac21 Mon Sep 17 00:00:00 2001 From: Karol Sykala Date: Thu, 17 Sep 2026 13:05:53 +0200 Subject: [PATCH 3/3] fix redis tests --- tests/Test/Prometheus/AbstractCounterTest.php | 29 ------------------- tests/Test/Prometheus/AbstractGaugeTest.php | 29 ------------------- tests/Test/Prometheus/Redis/CounterTest.php | 23 +++++++++++++++ tests/Test/Prometheus/Redis/GaugeTest.php | 23 +++++++++++++++ tests/Test/Prometheus/RedisNg/CounterTest.php | 23 +++++++++++++++ tests/Test/Prometheus/RedisNg/GaugeTest.php | 24 ++++++++++++++- .../Test/Prometheus/RenderTextFormatTest.php | 8 ++--- 7 files changed, 95 insertions(+), 64 deletions(-) diff --git a/tests/Test/Prometheus/AbstractCounterTest.php b/tests/Test/Prometheus/AbstractCounterTest.php index b4aef41e..26bf334f 100644 --- a/tests/Test/Prometheus/AbstractCounterTest.php +++ b/tests/Test/Prometheus/AbstractCounterTest.php @@ -9,7 +9,6 @@ use Prometheus\CollectorRegistry; use Prometheus\Counter; use Prometheus\MetricFamilySamples; -use Prometheus\RenderTextFormat; use Prometheus\Sample; use Prometheus\Storage\Adapter; @@ -249,33 +248,5 @@ public function itShouldUpdateMetadataWhenLabelSchemaChanges(): void $metrics = $this->adapter->collect(); self::assertCount(1, $metrics); self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); - - $renderer = new RenderTextFormat(); - $output = $renderer->render($metrics); - self::assertStringContainsString('test_some_metric{foo="val1",bar="val2"} 1', $output); - } - - /** - * @test - */ - public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void - { - $registry = new CollectorRegistry($this->adapter, false); - - $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); - $counterV1->inc(['val1']); - - $metrics = $this->adapter->collect(); - self::assertCount(1, $metrics); - self::assertSame(['foo'], $metrics[0]->getLabelNames()); - - $registry = new CollectorRegistry($this->adapter, false); - - $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); - $counterV2->inc(['val1', 'val2']); - - $metrics = $this->adapter->collect(); - self::assertCount(1, $metrics); - self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); } } diff --git a/tests/Test/Prometheus/AbstractGaugeTest.php b/tests/Test/Prometheus/AbstractGaugeTest.php index 95fd56af..20191559 100644 --- a/tests/Test/Prometheus/AbstractGaugeTest.php +++ b/tests/Test/Prometheus/AbstractGaugeTest.php @@ -9,7 +9,6 @@ use Prometheus\CollectorRegistry; use Prometheus\Gauge; use Prometheus\MetricFamilySamples; -use Prometheus\RenderTextFormat; use Prometheus\Sample; use Prometheus\Storage\Adapter; @@ -383,33 +382,5 @@ public function itShouldUpdateMetadataWhenLabelSchemaChanges(): void $metrics = $this->adapter->collect(); self::assertCount(1, $metrics); self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); - - $renderer = new RenderTextFormat(); - $output = $renderer->render($metrics); - self::assertStringContainsString('test_some_metric{foo="val1",bar="val2"} 99', $output); - } - - /** - * @test - */ - public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void - { - $registry = new CollectorRegistry($this->adapter, false); - - $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); - $gaugeV1->set(42, ['val1']); - - $metrics = $this->adapter->collect(); - self::assertCount(1, $metrics); - self::assertSame(['foo'], $metrics[0]->getLabelNames()); - - $registry = new CollectorRegistry($this->adapter, false); - - $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); - $gaugeV2->set(99, ['val1', 'val2']); - - $metrics = $this->adapter->collect(); - self::assertCount(1, $metrics); - self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); } } diff --git a/tests/Test/Prometheus/Redis/CounterTest.php b/tests/Test/Prometheus/Redis/CounterTest.php index df0c2b43..27157783 100644 --- a/tests/Test/Prometheus/Redis/CounterTest.php +++ b/tests/Test/Prometheus/Redis/CounterTest.php @@ -4,6 +4,7 @@ namespace Test\Prometheus\Redis; +use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; use Test\Prometheus\AbstractCounterTest; @@ -18,4 +19,26 @@ public function configureAdapter(): void $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->wipeStorage(); } + + /** + * @test + */ + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); + $counterV1->inc(['val1']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $registry = new CollectorRegistry($this->adapter, false); + + $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); + $counterV2->inc(['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + } } diff --git a/tests/Test/Prometheus/Redis/GaugeTest.php b/tests/Test/Prometheus/Redis/GaugeTest.php index fa53a452..db8e01c7 100644 --- a/tests/Test/Prometheus/Redis/GaugeTest.php +++ b/tests/Test/Prometheus/Redis/GaugeTest.php @@ -4,6 +4,7 @@ namespace Test\Prometheus\Redis; +use Prometheus\CollectorRegistry; use Prometheus\Storage\Redis; use Test\Prometheus\AbstractGaugeTest; @@ -18,4 +19,26 @@ public function configureAdapter(): void $this->adapter = new Redis(['host' => REDIS_HOST]); $this->adapter->wipeStorage(); } + + /** + * @test + */ + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); + $gaugeV1->set(42, ['val1']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); + $gaugeV2->set(99, ['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + } } diff --git a/tests/Test/Prometheus/RedisNg/CounterTest.php b/tests/Test/Prometheus/RedisNg/CounterTest.php index b497a8fd..5926ea15 100644 --- a/tests/Test/Prometheus/RedisNg/CounterTest.php +++ b/tests/Test/Prometheus/RedisNg/CounterTest.php @@ -4,6 +4,7 @@ namespace Test\Prometheus\RedisNg; +use Prometheus\CollectorRegistry; use Prometheus\Storage\RedisNg; use Test\Prometheus\AbstractCounterTest; @@ -18,4 +19,26 @@ public function configureAdapter(): void $this->adapter = new RedisNg(['host' => REDIS_HOST]); $this->adapter->wipeStorage(); } + + /** + * @test + */ + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $counterV1 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo']); + $counterV1->inc(['val1']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $registry = new CollectorRegistry($this->adapter, false); + + $counterV2 = $registry->getOrRegisterCounter('test', 'some_metric', 'help', ['foo', 'bar']); + $counterV2->inc(['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + } } diff --git a/tests/Test/Prometheus/RedisNg/GaugeTest.php b/tests/Test/Prometheus/RedisNg/GaugeTest.php index cc1f5ca5..b2df9db1 100644 --- a/tests/Test/Prometheus/RedisNg/GaugeTest.php +++ b/tests/Test/Prometheus/RedisNg/GaugeTest.php @@ -4,7 +4,7 @@ namespace Test\Prometheus\RedisNg; -use Prometheus\Storage\Redis; +use Prometheus\CollectorRegistry; use Prometheus\Storage\RedisNg; use Test\Prometheus\AbstractGaugeTest; @@ -19,4 +19,26 @@ public function configureAdapter(): void $this->adapter = new RedisNg(['host' => REDIS_HOST]); $this->adapter->wipeStorage(); } + + /** + * @test + */ + public function itShouldUpdateMetadataOnSubsequentWritesWithoutWipe(): void + { + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV1 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo']); + $gaugeV1->set(42, ['val1']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo'], $metrics[0]->getLabelNames()); + + $registry = new CollectorRegistry($this->adapter, false); + + $gaugeV2 = $registry->getOrRegisterGauge('test', 'some_metric', 'help', ['foo', 'bar']); + $gaugeV2->set(99, ['val1', 'val2']); + + $metrics = $this->adapter->collect(); + self::assertSame(['foo', 'bar'], $metrics[0]->getLabelNames()); + } } diff --git a/tests/Test/Prometheus/RenderTextFormatTest.php b/tests/Test/Prometheus/RenderTextFormatTest.php index cc3fba8f..56f82f64 100644 --- a/tests/Test/Prometheus/RenderTextFormatTest.php +++ b/tests/Test/Prometheus/RenderTextFormatTest.php @@ -94,7 +94,6 @@ public function testValueErrorThrownWithInvalidSamples(): void $registry->registerCounter($namespace, $counter, 'counter-help-text', ['label1', 'label2']) ->inc(['bob', 'alice']); - // Reload the registry with an updated counter config $registry = new CollectorRegistry($storage, false); $registry->registerCounter($namespace, $counter, 'counter-help-text', ['label1', 'label2', 'label3']) ->inc(['bob', 'alice', 'eve']); @@ -116,7 +115,6 @@ public function testOutputWithInvalidSamplesSkipped(): void $registry->registerCounter($namespace, $counter, 'counter-help-text', ['label1', 'label2']) ->inc(['bob', 'alice']); - // Reload the registry with an updated counter config $registry = new CollectorRegistry($storage, false); $registry->registerCounter($namespace, $counter, 'counter-help-text', ['label1', 'label2', 'label3']) ->inc(['bob', 'alice', 'eve']); @@ -124,10 +122,10 @@ public function testOutputWithInvalidSamplesSkipped(): void $expectedOutput = ' # HELP foo_bar counter-help-text # TYPE foo_bar counter -foo_bar{label1="bob",label2="alice"} 1 # Error: array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements -# Labels: ["label1","label2"] -# Values: ["bob","alice","eve"] +# Labels: ["label1","label2","label3"] +# Values: ["bob","alice"] +foo_bar{label1="bob",label2="alice",label3="eve"} 1 '; $renderer = new RenderTextFormat();