Skip to content

Commit d4b1349

Browse files
committed
WIP: Draft
1 parent 5d27b6d commit d4b1349

File tree

8 files changed

+317
-4
lines changed

8 files changed

+317
-4
lines changed

src/Prometheus/Collector.php

+20
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,26 @@ protected function assertLabelsAreDefinedCorrectly(array $labels): void
9898
}
9999
}
100100

101+
/**
102+
* @param array[] $labelValuesSet
103+
*/
104+
protected function assertValidInitLabelsValuesSet(array $labelValuesSet = []): void
105+
{
106+
$initLabelsKeys = array_keys($labelValuesSet);
107+
108+
$forgottenLabels = array_diff($this->getLabelNames(), $initLabelsKeys);
109+
if (count($forgottenLabels) > 0) {
110+
throw new InvalidArgumentException("Missing label values for: " . implode(',', $forgottenLabels));
111+
}
112+
113+
$unnecessaryLabels = array_diff($initLabelsKeys, $this->getLabelNames());
114+
if (count($unnecessaryLabels) > 0) {
115+
throw new InvalidArgumentException(
116+
"Some labels values are not mentioned on metric creation:" . implode(',', $unnecessaryLabels)
117+
);
118+
}
119+
}
120+
101121
/**
102122
* @param string $metricName
103123
*/

src/Prometheus/Counter.php

+18
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,22 @@ public function incBy($count, array $labels = []): void
4646
]
4747
);
4848
}
49+
50+
/**
51+
* @param array[] $labelValuesSet
52+
*/
53+
public function init(array $labelValuesSet = []): void
54+
{
55+
$this->assertValidInitLabelsValuesSet($labelValuesSet);
56+
57+
$this->storageAdapter->initCounter(
58+
[
59+
'name' => $this->getName(),
60+
'help' => $this->getHelp(),
61+
'type' => $this->getType(),
62+
'labelNames' => $this->getLabelNames(),
63+
'labelValuesSet' => $labelValuesSet,
64+
]
65+
);
66+
}
4967
}

src/Prometheus/Gauge.php

+18
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,22 @@ public function decBy(int $value, array $labels = []): void
8484
{
8585
$this->incBy(-$value, $labels);
8686
}
87+
88+
/**
89+
* @param array[] $labelValuesSet
90+
*/
91+
public function init(array $labelValuesSet = []): void
92+
{
93+
$this->assertValidInitLabelsValuesSet($labelValuesSet);
94+
95+
$this->storageAdapter->initGauge(
96+
[
97+
'name' => $this->getName(),
98+
'help' => $this->getHelp(),
99+
'type' => $this->getType(),
100+
'labelNames' => $this->getLabelNames(),
101+
'labelValuesSet' => $labelValuesSet,
102+
]
103+
);
104+
}
87105
}

src/Prometheus/Histogram.php

+19
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,25 @@ public function observe(float $value, array $labels = []): void
133133
);
134134
}
135135

136+
/**
137+
* @param array[] $labelValuesSet
138+
*/
139+
public function init(array $labelValuesSet = []): void
140+
{
141+
$this->assertValidInitLabelsValuesSet($labelValuesSet);
142+
143+
$this->storageAdapter->initHistogram(
144+
[
145+
'name' => $this->getName(),
146+
'help' => $this->getHelp(),
147+
'type' => $this->getType(),
148+
'labelNames' => $this->getLabelNames(),
149+
'labelValuesSet' => $labelValuesSet,
150+
'buckets' => $this->buckets,
151+
]
152+
);
153+
}
154+
136155
/**
137156
* @return string
138157
*/

src/Prometheus/Storage/APC.php

+15
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,21 @@ public function updateCounter(array $data): void
124124
}
125125
}
126126

127+
public function initHistogram(array $data): void
128+
{
129+
// TODO: Implement initHistogram() method.
130+
}
131+
132+
public function initGauge(array $data): void
133+
{
134+
// TODO: Implement initGauge() method.
135+
}
136+
137+
public function initCounter(array $data): void
138+
{
139+
// TODO: Implement initCounter() method.
140+
}
141+
127142
/**
128143
* @deprecated use replacement method wipeStorage from Adapter interface
129144
*

src/Prometheus/Storage/Adapter.php

+23-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ interface Adapter
1313
const COMMAND_INCREMENT_FLOAT = 2;
1414
const COMMAND_SET = 3;
1515

16+
/**
17+
* Removes all previously stored metrics from underlying storage
18+
*
19+
* @throws StorageException
20+
* @return void
21+
*/
22+
public function wipeStorage(): void;
23+
1624
/**
1725
* @return MetricFamilySamples[]
1826
*/
@@ -37,10 +45,21 @@ public function updateGauge(array $data): void;
3745
public function updateCounter(array $data): void;
3846

3947
/**
40-
* Removes all previously stored metrics from underlying storage
41-
*
42-
* @throws StorageException
48+
* @param mixed[] $data
4349
* @return void
4450
*/
45-
public function wipeStorage(): void;
51+
public function initHistogram(array $data): void;
52+
53+
54+
/**
55+
* @param mixed[] $data
56+
* @return void
57+
*/
58+
public function initGauge(array $data): void;
59+
60+
/**
61+
* @param mixed[] $data
62+
* @return void
63+
*/
64+
public function initCounter(array $data): void;
4665
}

src/Prometheus/Storage/InMemory.php

+15
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,21 @@ public function updateCounter(array $data): void
244244
}
245245
}
246246

247+
public function initHistogram(array $data): void
248+
{
249+
// TODO: Implement initHistogram() method.
250+
}
251+
252+
public function initGauge(array $data): void
253+
{
254+
// TODO: Implement initGauge() method.
255+
}
256+
257+
public function initCounter(array $data): void
258+
{
259+
// TODO: Implement initCounter() method.
260+
}
261+
247262
/**
248263
* @param mixed[] $data
249264
* @param string|int $bucket

src/Prometheus/Storage/Redis.php

+189
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,155 @@ public function updateCounter(array $data): void
307307
);
308308
}
309309

310+
/**
311+
* @param mixed[] $data
312+
* @throws StorageException
313+
*/
314+
public function initHistogram(array $data): void
315+
{
316+
$this->ensureOpenConnection();
317+
318+
$metricKey = $this->toMetricKey($data);
319+
320+
// If hash exists, we skip init
321+
if ((bool) $this->redis->hLen($metricKey)) {
322+
return;
323+
}
324+
325+
$bucketsToSet = $data['buckets'];
326+
array_unshift($bucketsToSet, 'sum');
327+
$bucketsToSet[] = '+Inf';
328+
329+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
330+
331+
$values = [];
332+
foreach ($bucketsToSet as $bucket) {
333+
foreach ($labelsCartesian as $labelValues) {
334+
$values[] = json_encode(['b' => $bucket, 'labelValues' => array_values($labelValues)]);
335+
}
336+
}
337+
338+
$valuesString = $this->makeLuaValuesString($values);
339+
340+
// metadata
341+
unset($data['labelValuesSet']);
342+
343+
$this->redis->eval(
344+
<<<LUA
345+
redis.call('hSet', KEYS[1], '__meta', ARGV[1])
346+
347+
for _, subKey in pairs({{$valuesString}}) do
348+
redis.call('hIncrBy', KEYS[1], subKey, 0)
349+
end
350+
351+
redis.call('sAdd', KEYS[2], KEYS[1])
352+
LUA
353+
,
354+
[
355+
$metricKey, // key1
356+
self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
357+
json_encode($data), // arg1
358+
],
359+
2
360+
);
361+
}
362+
363+
/**
364+
* @param mixed[] $data
365+
*
366+
* @throws StorageException
367+
*/
368+
public function initGauge(array $data): void
369+
{
370+
$this->ensureOpenConnection();
371+
372+
$metricKey = $this->toMetricKey($data);
373+
374+
// If hash exists, we skip init
375+
if ((bool) $this->redis->hLen($metricKey)) {
376+
return;
377+
}
378+
379+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
380+
381+
$values = [];
382+
foreach ($labelsCartesian as $labelValues) {
383+
$values[] = json_encode(array_values($labelValues));
384+
}
385+
386+
$valuesString = $this->makeLuaValuesString($values);
387+
388+
// metadata
389+
unset($data['labelValuesSet']);
390+
391+
$this->redis->eval(
392+
<<<LUA
393+
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
394+
395+
for _, subKey in pairs({{$valuesString}}) do
396+
redis.call('hIncrBy', KEYS[1], subKey, 0)
397+
end
398+
399+
redis.call('sAdd', KEYS[2], KEYS[1])
400+
LUA
401+
,
402+
[
403+
$metricKey, // key1
404+
self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
405+
json_encode($data), // arg1
406+
],
407+
2
408+
);
409+
}
410+
411+
/**
412+
* @param mixed[] $data
413+
*
414+
* @throws StorageException
415+
*/
416+
public function initCounter(array $data): void
417+
{
418+
$this->ensureOpenConnection();
419+
420+
$metricKey = $this->toMetricKey($data);
421+
422+
// If hash exists, we skip init
423+
if ((bool) $this->redis->hLen($metricKey)) {
424+
return;
425+
}
426+
427+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
428+
429+
$values = [];
430+
foreach ($labelsCartesian as $labelValues) {
431+
$values[] = json_encode(array_values($labelValues));
432+
}
433+
434+
$valuesString = $this->makeLuaValuesString($values);
435+
436+
// metadata
437+
unset($data['labelValuesSet']);
438+
439+
$this->redis->eval(
440+
<<<LUA
441+
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
442+
443+
for _, subKey in pairs({{$valuesString}}) do
444+
redis.call('hIncrBy', KEYS[1], subKey, 0)
445+
end
446+
447+
redis.call('sAdd', KEYS[2], KEYS[1])
448+
LUA
449+
,
450+
[
451+
$metricKey, // key1
452+
self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
453+
json_encode($data), // arg1
454+
],
455+
2
456+
);
457+
}
458+
310459
/**
311460
* @return mixed[]
312461
*/
@@ -468,4 +617,44 @@ private function toMetricKey(array $data): string
468617
{
469618
return implode(':', [self::$prefix, $data['type'], $data['name']]);
470619
}
620+
621+
/**
622+
* @param mixed[] $input
623+
* @return mixed[]
624+
*/
625+
private function cartesian(array $input): array
626+
{
627+
$result = [[]];
628+
629+
foreach ($input as $key => $values) {
630+
$append = [];
631+
632+
foreach ($result as $product) {
633+
foreach ($values as $item) {
634+
$product[$key] = $item;
635+
$append[] = $product;
636+
}
637+
}
638+
639+
$result = $append;
640+
}
641+
642+
return $result;
643+
}
644+
645+
/**
646+
* @param mixed[] $values
647+
* @return string
648+
*/
649+
private function makeLuaValuesString(array $values): string
650+
{
651+
$values = array_map(
652+
static function (string $value): string {
653+
return '"' . addslashes($value) . '"';
654+
},
655+
$values
656+
);
657+
658+
return implode(', ', $values);
659+
}
471660
}

0 commit comments

Comments
 (0)