Skip to content

Commit c54a8ec

Browse files
committed
Reorganize concepts.
Signed-off-by: Arris Ray <arris.ray+github@gmail.com>
1 parent 7f7d050 commit c54a8ec

20 files changed

+1105
-614
lines changed

src/Prometheus/Storage/RedisTxn.php

Lines changed: 44 additions & 596 deletions
Large diffs are not rendered by default.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace Prometheus\Storage\RedisTxn\Collecter;
4+
5+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScriptHelper;
6+
use Redis;
7+
8+
abstract class AbstractCollecter implements CollecterInterface
9+
{
10+
/**
11+
* @var RedisScriptHelper
12+
*/
13+
private $helper;
14+
15+
/**
16+
* @var Redis
17+
*/
18+
private $redis;
19+
20+
/**
21+
* @param Redis $redis
22+
*/
23+
public function __construct(Redis $redis)
24+
{
25+
$this->helper = new RedisScriptHelper();
26+
$this->redis = $redis;
27+
}
28+
29+
/**
30+
* @inheritDoc
31+
*/
32+
public function getHelper(): RedisScriptHelper
33+
{
34+
return $this->helper;
35+
}
36+
37+
/**
38+
* @inheritDoc
39+
*/
40+
public function getRedis(): Redis
41+
{
42+
return $this->redis;
43+
}
44+
45+
/**
46+
* @inheritDoc
47+
*/
48+
public function getMetricFamilySamples(): array
49+
{
50+
$metricFamilySamples = [];
51+
$metrics = $this->getMetrics();
52+
foreach ($metrics as $metric) {
53+
$metricFamilySamples[] = $metric->toMetricFamilySamples();
54+
}
55+
return $metricFamilySamples;
56+
}
57+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Prometheus\Storage\RedisTxn\Collecter;
4+
5+
use Prometheus\Storage\RedisTxn\Metric\Metric;
6+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScript;
7+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScriptHelper;
8+
use Redis;
9+
10+
interface CollecterInterface
11+
{
12+
/**
13+
* @return RedisScriptHelper
14+
*/
15+
function getHelper(): RedisScriptHelper;
16+
17+
/**
18+
* @return Redis
19+
*/
20+
function getRedis(): Redis;
21+
22+
/**
23+
* @return RedisScript
24+
*/
25+
function getRedisScript(): RedisScript;
26+
27+
/**
28+
* @return Metric[]
29+
*/
30+
function getMetrics(): array;
31+
32+
/**
33+
* @return array
34+
*/
35+
function getMetricFamilySamples(): array;
36+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace Prometheus\Storage\RedisTxn\Collecter;
4+
5+
use Prometheus\Counter;
6+
use Prometheus\Storage\RedisTxn\Metric\MetadataBuilder;
7+
use Prometheus\Storage\RedisTxn\Metric\Metric;
8+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScript;
9+
10+
class CounterCollecter extends AbstractCollecter
11+
{
12+
const SCRIPT = <<<LUA
13+
-- Parse script input
14+
local registryKey = KEYS[1]
15+
local metadataKey = KEYS[2]
16+
17+
-- Process each registered counter metric
18+
local result = {}
19+
local metricKeys = redis.call('smembers', registryKey)
20+
for i, metricKey in ipairs(metricKeys) do
21+
local doesExist = redis.call('exists', metricKey)
22+
if doesExist then
23+
-- Get counter metadata
24+
local metadata = redis.call('hget', metadataKey, metricKey)
25+
26+
-- Get counter sample
27+
local sample = redis.call('get', metricKey)
28+
29+
-- Add the processed metric to the set of results
30+
result[metricKey] = {}
31+
result[metricKey]["metadata"] = metadata
32+
result[metricKey]["samples"] = sample
33+
else
34+
-- Remove metadata for expired key
35+
redis.call('srem', registryKey, metricKey)
36+
redis.call('hdel', metadataKey, metricKey)
37+
end
38+
end
39+
40+
-- Return the set of collected metrics
41+
return cjson.encode(result)
42+
LUA;
43+
44+
/**
45+
* @inheritDoc
46+
*/
47+
public function getRedisScript(): RedisScript
48+
{
49+
// Create Redis script args
50+
$numKeys = 2;
51+
$registryKey = $this->getHelper()->getRegistryKey(Counter::TYPE);
52+
$metadataKey = $this->getHelper()->getMetadataKey(Counter::TYPE);
53+
$scriptArgs = [
54+
$registryKey,
55+
$metadataKey,
56+
];
57+
58+
// Create Redis script
59+
return RedisScript::newBuilder()
60+
->withScript(self::SCRIPT)
61+
->withArgs($scriptArgs)
62+
->withNumKeys($numKeys)
63+
->build();
64+
}
65+
66+
/**
67+
* @inheritDoc
68+
*/
69+
public function getMetrics(): array
70+
{
71+
// Retrieve metrics from Redis
72+
$results = $this->getRedisScript()->eval($this->getRedis());
73+
74+
// Collate metrics by metric name
75+
$phpMetrics = [];
76+
$redisMetrics = json_decode($results, true);
77+
foreach ($redisMetrics as $redisMetric) {
78+
// Get metadata
79+
$phpMetadata = json_decode($redisMetric['metadata'], true);
80+
$metadata = MetadataBuilder::fromArray($phpMetadata)->build();
81+
82+
// Create or update metric
83+
$metricName = $metadata->getName();
84+
$builder = $phpMetrics[$metricName] ?? Metric::newScalarMetricBuilder()->withMetadata($metadata);
85+
$builder->withSample($redisMetric['samples'], $metadata->getLabelValues());
86+
$phpMetrics[$metricName] = $builder;
87+
}
88+
89+
// Build metrics
90+
$metrics = [];
91+
foreach ($phpMetrics as $_ => $metric) {
92+
$metrics[] = $metric->build();
93+
}
94+
return $metrics;
95+
}
96+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace Prometheus\Storage\RedisTxn\Collecter;
4+
5+
use Prometheus\Gauge;
6+
use Prometheus\Storage\RedisTxn\Metric\MetadataBuilder;
7+
use Prometheus\Storage\RedisTxn\Metric\Metric;
8+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScript;
9+
10+
class GaugeCollecter extends AbstractCollecter
11+
{
12+
const SCRIPT = <<<LUA
13+
-- Parse script input
14+
local registryKey = KEYS[1]
15+
local metadataKey = KEYS[2]
16+
17+
-- Process each registered metric
18+
local result = {}
19+
local metricKeys = redis.call('smembers', registryKey)
20+
for i, metricKey in ipairs(metricKeys) do
21+
local doesExist = redis.call('exists', metricKey)
22+
if doesExist then
23+
-- Get metric metadata
24+
local metadata = redis.call('hget', metadataKey, metricKey)
25+
26+
-- Get metric sample
27+
local sample = redis.call('get', metricKey)
28+
29+
-- Add the processed metric to the set of results
30+
result[metricKey] = {}
31+
result[metricKey]["metadata"] = metadata
32+
result[metricKey]["samples"] = sample
33+
else
34+
-- Remove metadata for expired key
35+
redis.call('srem', registryKey, metricKey)
36+
redis.call('hdel', metadataKey, metricKey)
37+
end
38+
end
39+
40+
-- Return the set of collected metrics
41+
return cjson.encode(result)
42+
LUA;
43+
44+
/**
45+
* @inheritDoc
46+
*/
47+
public function getRedisScript(): RedisScript
48+
{
49+
// Create Redis script args
50+
$numKeys = 2;
51+
$registryKey = $this->getHelper()->getRegistryKey(Gauge::TYPE);
52+
$metadataKey = $this->getHelper()->getMetadataKey(Gauge::TYPE);
53+
$scriptArgs = [
54+
$registryKey,
55+
$metadataKey,
56+
];
57+
58+
// Create Redis script
59+
return RedisScript::newBuilder()
60+
->withScript(self::SCRIPT)
61+
->withArgs($scriptArgs)
62+
->withNumKeys($numKeys)
63+
->build();
64+
}
65+
66+
/**
67+
* @inheritDoc
68+
*/
69+
public function getMetrics(): array
70+
{
71+
// Retrieve metrics from Redis
72+
$results = $this->getRedisScript()->eval($this->getRedis());
73+
74+
// Collate metrics by metric name
75+
$phpMetrics = [];
76+
$redisMetrics = json_decode($results, true);
77+
foreach ($redisMetrics as $redisMetric) {
78+
// Get metadata
79+
$phpMetadata = json_decode($redisMetric['metadata'], true);
80+
$metadata = MetadataBuilder::fromArray($phpMetadata)->build();
81+
82+
// Create or update metric
83+
$metricName = $metadata->getName();
84+
$builder = $phpMetrics[$metricName] ?? Metric::newScalarMetricBuilder()->withMetadata($metadata);
85+
$builder->withSample($redisMetric['samples'], $metadata->getLabelValues());
86+
$phpMetrics[$metricName] = $builder;
87+
}
88+
89+
// Build metrics
90+
$metrics = [];
91+
foreach ($phpMetrics as $_ => $metric) {
92+
$metrics[] = $metric->build();
93+
}
94+
return $metrics;
95+
}
96+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
namespace Prometheus\Storage\RedisTxn\Collecter;
4+
5+
use Prometheus\Storage\RedisTxn\Metric\Metric;
6+
use Prometheus\Storage\RedisTxn\RedisScript\RedisScript;
7+
use Prometheus\Summary;
8+
9+
class SummaryCollecter extends AbstractCollecter
10+
{
11+
const SCRIPT = <<<LUA
12+
-- Parse script input
13+
local summaryRegistryKey = KEYS[1]
14+
local metadataKey = KEYS[2]
15+
local currentTime = tonumber(ARGV[1])
16+
17+
-- Process each registered summary metric
18+
local result = {}
19+
local summaryKeys = redis.call('smembers', summaryRegistryKey)
20+
for i, summaryKey in ipairs(summaryKeys) do
21+
-- Get metric sample TTL
22+
local ttlFieldName = summaryKey .. ":ttl"
23+
redis.call('set', 'foo', ttlFieldName)
24+
local summaryTtl = redis.call("hget", metadataKey, ttlFieldName)
25+
if summaryTtl ~= nil then
26+
summaryTtl = tonumber(summaryTtl)
27+
end
28+
29+
-- Remove TTL'd metric samples
30+
local startScore = "-inf"
31+
if summaryTtl ~= nil and currentTime ~= nil and summaryTtl > 0 and summaryTtl < currentTime then
32+
local startScore = currentTime - summaryTtl
33+
redis.call("zremrangebyscore", summaryKey, "-inf", startScore)
34+
end
35+
36+
-- Retrieve the set of remaining metric samples
37+
local numSamples = redis.call('zcard', summaryKey)
38+
local summaryMetadata = {}
39+
local summarySamples = {}
40+
if numSamples > 0 then
41+
-- Configure results
42+
summaryMetadata = redis.call("hget", metadataKey, summaryKey)
43+
summarySamples = redis.call("zrange", summaryKey, startScore, "+inf", "byscore")
44+
else
45+
-- Remove the metric's associated metadata if there are no associated samples remaining
46+
redis.call('srem', summaryRegistryKey, summaryKey)
47+
redis.call('hdel', metadataKey, summaryKey)
48+
redis.call('hdel', metadataKey, ttlFieldName)
49+
end
50+
51+
-- Add the processed metric to the set of results
52+
result[summaryKey] = {}
53+
result[summaryKey]["metadata"] = summaryMetadata
54+
result[summaryKey]["samples"] = summarySamples
55+
end
56+
57+
-- Return the set of summary metrics
58+
return cjson.encode(result)
59+
LUA;
60+
61+
/**
62+
* @inheritDoc
63+
*/
64+
public function getRedisScript(): RedisScript
65+
{
66+
// Create Redis script args
67+
$numKeys = 2;
68+
$registryKey = $this->getHelper()->getRegistryKey(Summary::TYPE);
69+
$metadataKey = $this->getHelper()->getMetadataKey(Summary::TYPE);
70+
$currentTime = time();
71+
$scriptArgs = [
72+
$registryKey,
73+
$metadataKey,
74+
$currentTime
75+
];
76+
77+
// Create Redis script
78+
return RedisScript::newBuilder()
79+
->withScript(self::SCRIPT)
80+
->withArgs($scriptArgs)
81+
->withNumKeys($numKeys)
82+
->build();
83+
}
84+
85+
/**
86+
* @inheritDoc
87+
*/
88+
public function getMetrics(): array
89+
{
90+
// Retrieve metrics from Redis
91+
$results = $this->getRedisScript()->eval($this->getRedis());
92+
93+
// Format metrics as MetricFamilySamples
94+
$metrics = [];
95+
$redisMetrics = json_decode($results, true);
96+
foreach ($redisMetrics as $redisMetric) {
97+
$metrics[] = Metric::newSummaryMetricBuilder()
98+
->withMetadata($redisMetric['metadata'])
99+
->withSamples($redisMetric['samples'])
100+
->build();
101+
}
102+
return $metrics;
103+
}
104+
}

0 commit comments

Comments
 (0)