Skip to content

Commit fd1aaac

Browse files
authored
Add methods to validate Metric Names & Labels Keys (#41)
* Add methods to validate Metric Names & Labels Keys Signed-off-by: Lukas Kämmerling <lukas.kaemmerling@hetzner-cloud.de>
1 parent 28d4ad4 commit fd1aaac

File tree

3 files changed

+107
-34
lines changed

3 files changed

+107
-34
lines changed

src/Prometheus/Collector.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,20 @@ abstract class Collector
3333

3434
/**
3535
* @param Adapter $storageAdapter
36-
* @param string $namespace
37-
* @param string $name
38-
* @param string $help
39-
* @param string[] $labels
36+
* @param string $namespace
37+
* @param string $name
38+
* @param string $help
39+
* @param string[] $labels
4040
*/
4141
public function __construct(Adapter $storageAdapter, string $namespace, string $name, string $help, array $labels = [])
4242
{
4343
$this->storageAdapter = $storageAdapter;
4444
$metricName = ($namespace !== '' ? $namespace . '_' : '') . $name;
45-
if (preg_match(self::RE_METRIC_LABEL_NAME, $metricName) !== 1) {
46-
throw new InvalidArgumentException("Invalid metric name: '" . $metricName . "'");
47-
}
45+
self::assertValidMetricName($metricName);
4846
$this->name = $metricName;
4947
$this->help = $help;
5048
foreach ($labels as $label) {
51-
if (preg_match(self::RE_METRIC_LABEL_NAME, $label) !== 1) {
52-
throw new InvalidArgumentException("Invalid label name: '" . $label . "'");
53-
}
49+
self::assertValidLabel($label);
5450
}
5551
$this->labels = $labels;
5652
}
@@ -101,4 +97,24 @@ protected function assertLabelsAreDefinedCorrectly(array $labels): void
10197
throw new InvalidArgumentException(sprintf('Labels are not defined correctly: %s', print_r($labels, true)));
10298
}
10399
}
100+
101+
/**
102+
* @param string $metricName
103+
*/
104+
public static function assertValidMetricName(string $metricName): void
105+
{
106+
if (preg_match(self::RE_METRIC_LABEL_NAME, $metricName) !== 1) {
107+
throw new InvalidArgumentException("Invalid metric name: '" . $metricName . "'");
108+
}
109+
}
110+
111+
/**
112+
* @param string $label
113+
*/
114+
public static function assertValidLabel(string $label): void
115+
{
116+
if (preg_match(self::RE_METRIC_LABEL_NAME, $label) !== 1) {
117+
throw new InvalidArgumentException("Invalid label name: '" . $label . "'");
118+
}
119+
}
104120
}

src/Prometheus/CollectorRegistry.php

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CollectorRegistry implements RegistryInterface
4545
* CollectorRegistry constructor.
4646
*
4747
* @param Adapter $storageAdapter
48-
* @param bool $registerDefaultMetrics
48+
* @param bool $registerDefaultMetrics
4949
*/
5050
public function __construct(Adapter $storageAdapter, bool $registerDefaultMetrics = true)
5151
{
@@ -72,9 +72,9 @@ public function getMetricFamilySamples(): array
7272
}
7373

7474
/**
75-
* @param string $namespace e.g. cms
76-
* @param string $name e.g. duration_seconds
77-
* @param string $help e.g. The duration something took in seconds.
75+
* @param string $namespace e.g. cms
76+
* @param string $name e.g. duration_seconds
77+
* @param string $help e.g. The duration something took in seconds.
7878
* @param string[] $labels e.g. ['controller', 'action']
7979
*
8080
* @return Gauge
@@ -106,16 +106,16 @@ public function registerGauge(string $namespace, string $name, string $help, $la
106106
public function getGauge(string $namespace, string $name): Gauge
107107
{
108108
$metricIdentifier = self::metricIdentifier($namespace, $name);
109-
if (! isset($this->gauges[$metricIdentifier])) {
109+
if (!isset($this->gauges[$metricIdentifier])) {
110110
throw new MetricNotFoundException("Metric not found:" . $metricIdentifier);
111111
}
112112
return $this->gauges[$metricIdentifier];
113113
}
114114

115115
/**
116-
* @param string $namespace e.g. cms
117-
* @param string $name e.g. duration_seconds
118-
* @param string $help e.g. The duration something took in seconds.
116+
* @param string $namespace e.g. cms
117+
* @param string $name e.g. duration_seconds
118+
* @param string $help e.g. The duration something took in seconds.
119119
* @param string[] $labels e.g. ['controller', 'action']
120120
*
121121
* @return Gauge
@@ -132,9 +132,9 @@ public function getOrRegisterGauge(string $namespace, string $name, string $help
132132
}
133133

134134
/**
135-
* @param string $namespace e.g. cms
136-
* @param string $name e.g. requests
137-
* @param string $help e.g. The number of requests made.
135+
* @param string $namespace e.g. cms
136+
* @param string $name e.g. requests
137+
* @param string $help e.g. The number of requests made.
138138
* @param string[] $labels e.g. ['controller', 'action']
139139
*
140140
* @return Counter
@@ -166,16 +166,16 @@ public function registerCounter(string $namespace, string $name, string $help, $
166166
public function getCounter(string $namespace, string $name): Counter
167167
{
168168
$metricIdentifier = self::metricIdentifier($namespace, $name);
169-
if (! isset($this->counters[$metricIdentifier])) {
169+
if (!isset($this->counters[$metricIdentifier])) {
170170
throw new MetricNotFoundException("Metric not found:" . $metricIdentifier);
171171
}
172172
return $this->counters[self::metricIdentifier($namespace, $name)];
173173
}
174174

175175
/**
176-
* @param string $namespace e.g. cms
177-
* @param string $name e.g. requests
178-
* @param string $help e.g. The number of requests made.
176+
* @param string $namespace e.g. cms
177+
* @param string $name e.g. requests
178+
* @param string $help e.g. The number of requests made.
179179
* @param string[] $labels e.g. ['controller', 'action']
180180
*
181181
* @return Counter
@@ -192,10 +192,10 @@ public function getOrRegisterCounter(string $namespace, string $name, string $he
192192
}
193193

194194
/**
195-
* @param string $namespace e.g. cms
196-
* @param string $name e.g. duration_seconds
197-
* @param string $help e.g. A histogram of the duration in seconds.
198-
* @param string[] $labels e.g. ['controller', 'action']
195+
* @param string $namespace e.g. cms
196+
* @param string $name e.g. duration_seconds
197+
* @param string $help e.g. A histogram of the duration in seconds.
198+
* @param string[] $labels e.g. ['controller', 'action']
199199
* @param mixed[]|null $buckets e.g. [100, 200, 300]
200200
*
201201
* @return Histogram
@@ -233,17 +233,17 @@ public function registerHistogram(
233233
public function getHistogram(string $namespace, string $name): Histogram
234234
{
235235
$metricIdentifier = self::metricIdentifier($namespace, $name);
236-
if (! isset($this->histograms[$metricIdentifier])) {
236+
if (!isset($this->histograms[$metricIdentifier])) {
237237
throw new MetricNotFoundException("Metric not found:" . $metricIdentifier);
238238
}
239239
return $this->histograms[self::metricIdentifier($namespace, $name)];
240240
}
241241

242242
/**
243-
* @param string $namespace e.g. cms
244-
* @param string $name e.g. duration_seconds
245-
* @param string $help e.g. A histogram of the duration in seconds.
246-
* @param string[] $labels e.g. ['controller', 'action']
243+
* @param string $namespace e.g. cms
244+
* @param string $name e.g. duration_seconds
245+
* @param string $help e.g. A histogram of the duration in seconds.
246+
* @param string[] $labels e.g. ['controller', 'action']
247247
* @param float[]|null $buckets e.g. [100, 200, 300]
248248
*
249249
* @return Histogram

tests/Test/Prometheus/AbstractCollectorRegistryTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,63 @@ public function itShouldNotRegisterAHistogramTwice(): void
361361
self::assertSame($histogramA, $histogramB);
362362
}
363363

364+
/**
365+
* @test
366+
* @dataProvider itShouldThrowAnExceptionOnInvalidMetricNamesDataProvider
367+
*/
368+
public function itShouldThrowAnExceptionOnInvalidMetricNames(string $namespace, string $metricName): void
369+
{
370+
$registry = new CollectorRegistry($this->adapter);
371+
372+
$this->expectException(\InvalidArgumentException::class);
373+
$registry->registerGauge($namespace, $metricName, 'help', ["foo", "bar"]);
374+
}
375+
376+
/**
377+
* @return string[][]
378+
*/
379+
public function itShouldThrowAnExceptionOnInvalidMetricNamesDataProvider(): array
380+
{
381+
return [
382+
[
383+
"foo",
384+
"invalid-metric-name"
385+
],
386+
[
387+
"invalid-namespace",
388+
"foo"
389+
],
390+
[
391+
"invalid-namespace",
392+
"both-invalid"
393+
],
394+
];
395+
}
396+
397+
/**
398+
* @test
399+
* @dataProvider itShouldThrowAnExceptionOnInvalidMetricLabelDataProvider
400+
*/
401+
public function itShouldThrowAnExceptionOnInvalidMetricLabel(string $invalidLabel): void
402+
{
403+
$registry = new CollectorRegistry($this->adapter);
404+
405+
$this->expectException(\InvalidArgumentException::class);
406+
$registry->registerGauge("foo", "bar", 'help', [$invalidLabel]);
407+
}
408+
409+
/**
410+
* @return string[][]
411+
*/
412+
public function itShouldThrowAnExceptionOnInvalidMetricLabelDataProvider(): array
413+
{
414+
return [
415+
[
416+
"invalid-label"
417+
],
418+
];
419+
}
420+
364421

365422
abstract public function configureAdapter(): void;
366423
}

0 commit comments

Comments
 (0)