Skip to content

Commit a6ff731

Browse files
EdgarSedovEdgar
authored and
Edgar
committed
WIP: Draft
1 parent 1088114 commit a6ff731

File tree

8 files changed

+316
-4
lines changed

8 files changed

+316
-4
lines changed

src/Prometheus/Collector.php

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

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

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($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
@@ -155,6 +155,21 @@ public function updateCounter(array $data): void
155155
}
156156
}
157157

158+
public function initHistogram(array $data): void
159+
{
160+
// TODO: Implement initHistogram() method.
161+
}
162+
163+
public function initGauge(array $data): void
164+
{
165+
// TODO: Implement initGauge() method.
166+
}
167+
168+
public function initCounter(array $data): void
169+
{
170+
// TODO: Implement initCounter() method.
171+
}
172+
158173
/**
159174
* @deprecated use replacement method wipeStorage from Adapter interface
160175
*

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
*/
@@ -43,10 +51,21 @@ public function updateGauge(array $data): void;
4351
public function updateCounter(array $data): void;
4452

4553
/**
46-
* Removes all previously stored metrics from underlying storage
47-
*
48-
* @throws StorageException
54+
* @param mixed[] $data
4955
* @return void
5056
*/
51-
public function wipeStorage(): void;
57+
public function initHistogram(array $data): void;
58+
59+
60+
/**
61+
* @param mixed[] $data
62+
* @return void
63+
*/
64+
public function initGauge(array $data): void;
65+
66+
/**
67+
* @param mixed[] $data
68+
* @return void
69+
*/
70+
public function initCounter(array $data): void;
5271
}

src/Prometheus/Storage/InMemory.php

+15
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,21 @@ public function updateCounter(array $data): void
351351
}
352352
}
353353

354+
public function initHistogram(array $data): void
355+
{
356+
// TODO: Implement initHistogram() method.
357+
}
358+
359+
public function initGauge(array $data): void
360+
{
361+
// TODO: Implement initGauge() method.
362+
}
363+
364+
public function initCounter(array $data): void
365+
{
366+
// TODO: Implement initCounter() method.
367+
}
368+
354369
/**
355370
* @param mixed[] $data
356371
* @param string|int $bucket

src/Prometheus/Storage/Redis.php

+188
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,154 @@ public function updateCounter(array $data): void
374374
);
375375
}
376376

377+
/**
378+
* @param mixed[] $data
379+
* @throws StorageException
380+
*/
381+
public function initHistogram(array $data): void
382+
{
383+
$this->ensureOpenConnection();
384+
385+
$metricKey = $this->toMetricKey($data);
386+
387+
// If hash exists, we skip init TODO: new labels adding [checking __meta]
388+
if ((bool) $this->redis->hLen($metricKey)) {
389+
return;
390+
}
391+
392+
$bucketsToSet = $data['buckets'];
393+
array_unshift($bucketsToSet, 'sum');
394+
$bucketsToSet[] = '+Inf';
395+
396+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
397+
398+
$values = [];
399+
foreach ($bucketsToSet as $bucket) {
400+
foreach ($labelsCartesian as $labelValues) {
401+
$values[] = json_encode(['b' => $bucket, 'labelValues' => array_values($labelValues)]);
402+
}
403+
}
404+
405+
$valuesString = $this->makeLuaValuesString($values);
406+
407+
// metadata
408+
unset($data['labelValuesSet']);
409+
410+
$this->redis->eval(
411+
<<<LUA
412+
redis.call('hSet', KEYS[1], '__meta', ARGV[1])
413+
414+
for _, subKey in pairs({{$valuesString}}) do
415+
redis.call('hIncrBy', KEYS[1], subKey, 0)
416+
end
417+
418+
redis.call('sAdd', KEYS[2], KEYS[1])
419+
LUA
420+
,
421+
[
422+
$metricKey, // key1
423+
self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
424+
json_encode($data), // arg1
425+
],
426+
2
427+
);
428+
}
429+
430+
/**
431+
* @param mixed[] $data
432+
*
433+
* @throws StorageException
434+
*/
435+
public function initGauge(array $data): void
436+
{
437+
$this->ensureOpenConnection();
438+
439+
$metricKey = $this->toMetricKey($data);
440+
441+
// If hash exists, we skip init TODO: new labels adding [checking __meta]
442+
if ((bool) $this->redis->hLen($metricKey)) {
443+
return;
444+
}
445+
446+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
447+
448+
$values = [];
449+
foreach ($labelsCartesian as $labelValues) {
450+
$values[] = json_encode(array_values($labelValues));
451+
}
452+
453+
$valuesString = $this->makeLuaValuesString($values);
454+
455+
// metadata
456+
unset($data['labelValuesSet']);
457+
458+
$this->redis->eval(
459+
<<<LUA
460+
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
461+
462+
for _, subKey in pairs({{$valuesString}}) do
463+
redis.call('hIncrBy', KEYS[1], subKey, 0)
464+
end
465+
466+
redis.call('sAdd', KEYS[2], KEYS[1])
467+
LUA
468+
,
469+
[
470+
$metricKey, // key1
471+
self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
472+
json_encode($data), // arg1
473+
],
474+
2
475+
);
476+
}
477+
478+
/**
479+
* @param mixed[] $data
480+
*
481+
* @throws StorageException
482+
*/
483+
public function initCounter(array $data): void
484+
{
485+
$this->ensureOpenConnection();
486+
487+
$metricKey = $this->toMetricKey($data);
488+
489+
// If hash exists, we skip init TODO: new labels adding [checking __meta]
490+
if ((bool) $this->redis->hLen($metricKey)) {
491+
return;
492+
}
493+
494+
$labelsCartesian = $this->cartesian($data['labelValuesSet']);
495+
496+
$values = [];
497+
foreach ($labelsCartesian as $labelValues) {
498+
$values[] = json_encode(array_values($labelValues));
499+
}
500+
501+
$valuesString = $this->makeLuaValuesString($values);
502+
503+
// metadata
504+
unset($data['labelValuesSet']);
505+
506+
$this->redis->eval(
507+
<<<LUA
508+
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
509+
510+
for _, subKey in pairs({{$valuesString}}) do
511+
redis.call('hIncrBy', KEYS[1], subKey, 0)
512+
end
513+
514+
redis.call('sAdd', KEYS[2], KEYS[1])
515+
LUA
516+
,
517+
[
518+
$metricKey, // key1
519+
self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
520+
json_encode($data), // arg1
521+
],
522+
2
523+
);
524+
}
377525

378526
/**
379527
* @param mixed[] $data
@@ -682,4 +830,44 @@ private function decodeLabelValues(string $values): array
682830
}
683831
return $decodedValues;
684832
}
833+
834+
/**
835+
* @param mixed[] $input
836+
* @return mixed[]
837+
*/
838+
private function cartesian(array $input): array
839+
{
840+
$result = [[]];
841+
842+
foreach ($input as $key => $values) {
843+
$append = [];
844+
845+
foreach ($result as $product) {
846+
foreach ($values as $item) {
847+
$product[$key] = $item;
848+
$append[] = $product;
849+
}
850+
}
851+
852+
$result = $append;
853+
}
854+
855+
return $result;
856+
}
857+
858+
/**
859+
* @param mixed[] $values
860+
* @return string
861+
*/
862+
private function makeLuaValuesString(array $values): string
863+
{
864+
$values = array_map(
865+
static function (string $value): string {
866+
return '"' . addslashes($value) . '"';
867+
},
868+
$values
869+
);
870+
871+
return implode(', ', $values);
872+
}
685873
}

0 commit comments

Comments
 (0)