Skip to content

Commit

Permalink
WIP: Draft
Browse files Browse the repository at this point in the history
  • Loading branch information
EdgarSedov committed Mar 11, 2021
1 parent 5d27b6d commit ef6aecc
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 4 deletions.
20 changes: 20 additions & 0 deletions src/Prometheus/Collector.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ protected function assertLabelsAreDefinedCorrectly(array $labels): void
}
}

/**
* @param array[] $labelValuesSet
*/
protected function assertValidInitLabelsValuesSet(array $labelValuesSet = []): void
{
$initLabelsKeys = array_keys($labelValuesSet);

$forgottenLabels = array_diff($this->getLabelNames(), $initLabelsKeys);
if (count($forgottenLabels) > 0) {
throw new InvalidArgumentException("Missing label values for: " . implode(',', $forgottenLabels));
}

$unnecessaryLabels = array_diff($initLabelsKeys, $this->getLabelNames());
if (count($unnecessaryLabels) > 0) {
throw new InvalidArgumentException(
"Some labels values are not mentioned on metric creation:" . implode(',', $unnecessaryLabels)
);
}
}

/**
* @param string $metricName
*/
Expand Down
18 changes: 18 additions & 0 deletions src/Prometheus/Counter.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,22 @@ public function incBy($count, array $labels = []): void
]
);
}

/**
* @param array[] $labelValuesSet
*/
public function init(array $labelValuesSet = []): void
{
$this->assertValidInitLabelsValuesSet($labelValuesSet);

$this->storageAdapter->initCounter(
[
'name' => $this->getName(),
'help' => $this->getHelp(),
'type' => $this->getType(),
'labelNames' => $this->getLabelNames(),
'labelValuesSet' => $labelValuesSet,
]
);
}
}
18 changes: 18 additions & 0 deletions src/Prometheus/Gauge.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,22 @@ public function decBy(int $value, array $labels = []): void
{
$this->incBy(-$value, $labels);
}

/**
* @param array[] $labelValuesSet
*/
public function init(array $labelValuesSet = []): void
{
$this->assertValidInitLabelsValuesSet($labelValuesSet);

$this->storageAdapter->initGauge(
[
'name' => $this->getName(),
'help' => $this->getHelp(),
'type' => $this->getType(),
'labelNames' => $this->getLabelNames(),
'labelValuesSet' => $labelValuesSet,
]
);
}
}
19 changes: 19 additions & 0 deletions src/Prometheus/Histogram.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,25 @@ public function observe(float $value, array $labels = []): void
);
}

/**
* @param array[] $labelValuesSet
*/
public function init(array $labelValuesSet = []): void
{
$this->assertValidInitLabelsValuesSet($labelValuesSet);

$this->storageAdapter->initHistogram(
[
'name' => $this->getName(),
'help' => $this->getHelp(),
'type' => $this->getType(),
'labelNames' => $this->getLabelNames(),
'labelValuesSet' => $labelValuesSet,
'buckets' => $this->buckets,
]
);
}

/**
* @return string
*/
Expand Down
15 changes: 15 additions & 0 deletions src/Prometheus/Storage/APC.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,21 @@ public function updateCounter(array $data): void
}
}

public function initHistogram(array $data): void
{
// TODO: Implement initHistogram() method.
}

public function initGauge(array $data): void
{
// TODO: Implement initGauge() method.
}

public function initCounter(array $data): void
{
// TODO: Implement initCounter() method.
}

/**
* @deprecated use replacement method wipeStorage from Adapter interface
*
Expand Down
27 changes: 23 additions & 4 deletions src/Prometheus/Storage/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ interface Adapter
const COMMAND_INCREMENT_FLOAT = 2;
const COMMAND_SET = 3;

/**
* Removes all previously stored metrics from underlying storage
*
* @throws StorageException
* @return void
*/
public function wipeStorage(): void;

/**
* @return MetricFamilySamples[]
*/
Expand All @@ -37,10 +45,21 @@ public function updateGauge(array $data): void;
public function updateCounter(array $data): void;

/**
* Removes all previously stored metrics from underlying storage
*
* @throws StorageException
* @param mixed[] $data
* @return void
*/
public function wipeStorage(): void;
public function initHistogram(array $data): void;


/**
* @param mixed[] $data
* @return void
*/
public function initGauge(array $data): void;

/**
* @param mixed[] $data
* @return void
*/
public function initCounter(array $data): void;
}
15 changes: 15 additions & 0 deletions src/Prometheus/Storage/InMemory.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,21 @@ public function updateCounter(array $data): void
}
}

public function initHistogram(array $data): void
{
// TODO: Implement initHistogram() method.
}

public function initGauge(array $data): void
{
// TODO: Implement initGauge() method.
}

public function initCounter(array $data): void
{
// TODO: Implement initCounter() method.
}

/**
* @param mixed[] $data
* @param string|int $bucket
Expand Down
189 changes: 189 additions & 0 deletions src/Prometheus/Storage/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,155 @@ public function updateCounter(array $data): void
);
}

/**
* @param mixed[] $data
* @throws StorageException
*/
public function initHistogram(array $data): void
{
$this->ensureOpenConnection();

$metricKey = $this->toMetricKey($data);

// If hash exists, we skip init
if ((bool) $this->redis->hLen($metricKey)) {
return;
}

$bucketsToSet = $data['buckets'];
array_unshift($bucketsToSet, 'sum');
$bucketsToSet[] = '+Inf';

$labelsCartesian = $this->cartesian($data['labelValuesSet']);

$values = [];
foreach ($bucketsToSet as $bucket) {
foreach ($labelsCartesian as $labelValues) {
$values[] = json_encode(['b' => $bucket, 'labelValues' => array_values($labelValues)]);
}
}

$valuesString = $this->makeLuaValuesString($values);

// metadata
unset($data['labelValuesSet']);

$this->redis->eval(
<<<LUA
redis.call('hSet', KEYS[1], '__meta', ARGV[1])
for _, subKey in pairs({{$valuesString}}) do
redis.call('hIncrBy', KEYS[1], subKey, 0)
end
redis.call('sAdd', KEYS[2], KEYS[1])
LUA
,
[
$metricKey, // key1
self::$prefix . Histogram::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
json_encode($data), // arg1
],
2
);
}

/**
* @param mixed[] $data
*
* @throws StorageException
*/
public function initGauge(array $data): void
{
$this->ensureOpenConnection();

$metricKey = $this->toMetricKey($data);

// If hash exists, we skip init
if ($this->redis->hLen($metricKey)) {
return;
}

$labelsCartesian = $this->cartesian($data['labelValuesSet']);

$values = [];
foreach ($labelsCartesian as $labelValues) {
$values[] = json_encode(array_values($labelValues));
}

$valuesString = $this->makeLuaValuesString($values);

// metadata
unset($data['labelValuesSet']);

$this->redis->eval(
<<<LUA
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
for _, subKey in pairs({{$valuesString}}) do
redis.call('hIncrBy', KEYS[1], subKey, 0)
end
redis.call('sAdd', KEYS[2], KEYS[1])
LUA
,
[
$metricKey, // key1
self::$prefix . Gauge::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
json_encode($data), // arg1
],
2
);
}

/**
* @param mixed[] $data
*
* @throws StorageException
*/
public function initCounter(array $data): void
{
$this->ensureOpenConnection();

$metricKey = $this->toMetricKey($data);

// If hash exists, we skip init
if ($this->redis->hLen($metricKey)) {
return;
}

$labelsCartesian = $this->cartesian($data['labelValuesSet']);

$values = [];
foreach ($labelsCartesian as $labelValues) {
$values[] = json_encode(array_values($labelValues));
}

$valuesString = $this->makeLuaValuesString($values);

// metadata
unset($data['labelValuesSet']);

$this->redis->eval(
<<<LUA
redis.call('hMSet', KEYS[1], '__meta', ARGV[1])
for _, subKey in pairs({{$valuesString}}) do
redis.call('hIncrBy', KEYS[1], subKey, 0)
end
redis.call('sAdd', KEYS[2], KEYS[1])
LUA
,
[
$metricKey, // key1
self::$prefix . Counter::TYPE . self::PROMETHEUS_METRIC_KEYS_SUFFIX, // key2
json_encode($data), // arg1
],
2
);
}

/**
* @return mixed[]
*/
Expand Down Expand Up @@ -468,4 +617,44 @@ private function toMetricKey(array $data): string
{
return implode(':', [self::$prefix, $data['type'], $data['name']]);
}

/**
* @param mixed[] $input
* @return mixed[]
*/
private function cartesian(array $input): array
{
$result = [[]];

foreach ($input as $key => $values) {
$append = [];

foreach ($result as $product) {
foreach ($values as $item) {
$product[$key] = $item;
$append[] = $product;
}
}

$result = $append;
}

return $result;
}

/**
* @param mixed[] $values
* @return string
*/
private function makeLuaValuesString(array $values): string
{
$values = array_map(
static function (string $value): string {
return '"' . addslashes($value) . '"';
},
$values
);

return implode(', ', $values);
}
}

0 comments on commit ef6aecc

Please sign in to comment.