@@ -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