Skip to content

Commit 9b044c4

Browse files
authored
Merge pull request #7874 from ProcessMaker/FOUR-21032
FOUR-21032 Task Execution Time Metrics Collection
2 parents d7c99de + 0b7eceb commit 9b044c4

15 files changed

Lines changed: 272 additions & 29 deletions

File tree

‎ProcessMaker/Cache/Monitoring/CacheMetricsDecorator.php‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use ProcessMaker\Cache\CacheInterface;
66
use ProcessMaker\Cache\Monitoring\CacheMetricsInterface;
7+
use ProcessMaker\Contracts\PrometheusMetricInterface;
78

89
/**
910
* Decorator class that adds metrics tracking about cache operations
@@ -64,11 +65,18 @@ public function get(string $key, mixed $default = null): mixed
6465
$endTime = microtime(true);
6566
$duration = $endTime - $startTime;
6667

68+
// Get extra labels for metrics
69+
$labels = [];
70+
if ($value instanceof PrometheusMetricInterface) {
71+
$labels['label'] = $value->getPrometheusMetricLabel();
72+
} else {
73+
$labels['label'] = $key;
74+
}
6775
// Record metrics based on key existence, not value comparison
6876
if ($exists) {
69-
$this->metrics->recordHit($key, $duration);
77+
$this->metrics->recordHit($key, $duration, $labels);
7078
} else {
71-
$this->metrics->recordMiss($key, $duration);
79+
$this->metrics->recordMiss($key, $duration, $labels);
7280
}
7381

7482
return $value;
@@ -88,10 +96,18 @@ public function set(string $key, mixed $value, null|int|\DateInterval $ttl = nul
8896
{
8997
$result = $this->cache->set($key, $value, $ttl);
9098

99+
// Get extra labels for metrics
100+
$labels = [];
101+
if ($value instanceof PrometheusMetricInterface) {
102+
$labels['label'] = $value->getPrometheusMetricLabel();
103+
} else {
104+
$labels['label'] = $key;
105+
}
106+
91107
if ($result) {
92108
// Calculate approximate size in bytes
93109
$size = $this->calculateSize($value);
94-
$this->metrics->recordWrite($key, $size);
110+
$this->metrics->recordWrite($key, $size, $labels);
95111
}
96112

97113
return $result;

‎ProcessMaker/Cache/Monitoring/CacheMetricsInterface.php‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@ interface CacheMetricsInterface
1212
*
1313
* @param string $key Cache key that was accessed
1414
* @param float $microtime Time taken for the operation in microseconds
15+
* @param array $labels Additional labels to attach to the metric
1516
*/
16-
public function recordHit(string $key, $microtime): void;
17+
public function recordHit(string $key, $microtime, array $labels = []): void;
1718

1819
/**
1920
* Record a cache miss event
2021
*
2122
* @param string $key Cache key that was accessed
2223
* @param float $microtime Time taken for the operation in microseconds
2324
*/
24-
public function recordMiss(string $key, $microtime): void;
25+
public function recordMiss(string $key, $microtime, array $labels = []): void;
2526

2627
/**
2728
* Record a cache write operation
2829
*
2930
* @param string $key Cache key that was written
3031
* @param int $size Size of the cached data in bytes
3132
*/
32-
public function recordWrite(string $key, int $size): void;
33+
public function recordWrite(string $key, int $size, array $labels = []): void;
3334
}

‎ProcessMaker/Cache/Monitoring/PrometheusMetricsManager.php‎

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@ public function __construct(string $namespace = 'cache')
3535
* @param string $key Cache key
3636
* @param float $microtime Time taken in microseconds
3737
*/
38-
public function recordHit(string $key, $microtime): void
38+
public function recordHit(string $key, $microtime, array $labels = []): void
3939
{
4040
$sanitizedKey = $this->sanitizeKey($key);
41+
$labelKeys = array_keys($labels);
4142

4243
$this->metrics->counter(
4344
'cache_hits_total',
4445
'Total number of cache hits',
45-
['cache_key']
46-
)->inc(['cache_key' => $sanitizedKey]);
46+
['cache_key', ...$labelKeys]
47+
)->inc(['cache_key' => $sanitizedKey, ...$labels]);
4748
// record the last write timestamp
4849
$this->metrics->gauge(
4950
'cache_last_write_timestamp',
5051
'Last write timestamp',
51-
['cache_key']
52-
)->set($microtime, ['cache_key' => $sanitizedKey]);
52+
['cache_key', ...$labelKeys]
53+
)->set($microtime, ['cache_key' => $sanitizedKey, ...$labels]);
5354
}
5455

5556
/**
@@ -58,22 +59,23 @@ public function recordHit(string $key, $microtime): void
5859
* @param string $key Cache key
5960
* @param float $microtime Time taken in microseconds
6061
*/
61-
public function recordMiss(string $key, $microtime): void
62+
public function recordMiss(string $key, $microtime, array $labels = []): void
6263
{
6364
$sanitizedKey = $this->sanitizeKey($key);
65+
$labelKeys = array_keys($labels);
6466

6567
$this->metrics->counter(
6668
'cache_misses_total',
6769
'Total number of cache misses',
68-
['cache_key']
69-
)->inc(['cache_key' => $sanitizedKey]);
70+
['cache_key', ...$labelKeys]
71+
)->inc(['cache_key' => $sanitizedKey, ...$labels]);
7072

7173
// record the last write timestamp
7274
$this->metrics->gauge(
7375
'cache_last_write_timestamp',
7476
'Last write timestamp',
75-
['cache_key']
76-
)->set($microtime, ['cache_key' => $sanitizedKey]);
77+
['cache_key', ...$labelKeys]
78+
)->set($microtime, ['cache_key' => $sanitizedKey, ...$labels]);
7779
}
7880

7981
/**
@@ -82,15 +84,16 @@ public function recordMiss(string $key, $microtime): void
8284
* @param string $key Cache key
8385
* @param int $size Size in bytes
8486
*/
85-
public function recordWrite(string $key, int $size): void
87+
public function recordWrite(string $key, int $size, array $labels = []): void
8688
{
8789
$sanitizedKey = $this->sanitizeKey($key);
90+
$labelKeys = array_keys($labels);
8891

8992
$this->metrics->gauge(
9093
'cache_memory_bytes',
9194
'Memory usage in bytes',
92-
['cache_key']
93-
)->set($size, ['cache_key' => $sanitizedKey]);
95+
['cache_key', ...$labelKeys]
96+
)->set($size, ['cache_key' => $sanitizedKey, ...$labels]);
9497
}
9598

9699
/**

‎ProcessMaker/Cache/Monitoring/RedisMetricsManager.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class RedisMetricsManager implements CacheMetricsInterface
2626
* @param string $key Cache key
2727
* @param float $microtime Time taken in microseconds
2828
*/
29-
public function recordHit(string $key, $microtime): void
29+
public function recordHit(string $key, $microtime, array $labels = []): void
3030
{
3131
$baseKey = self::METRICS_PREFIX . $key;
3232
Redis::pipeline(function ($pipe) use ($baseKey, $microtime) {
@@ -42,7 +42,7 @@ public function recordHit(string $key, $microtime): void
4242
* @param string $key Cache key
4343
* @param float $microtime Time taken in microseconds
4444
*/
45-
public function recordMiss(string $key, $microtime): void
45+
public function recordMiss(string $key, $microtime, array $labels = []): void
4646
{
4747
$baseKey = self::METRICS_PREFIX . $key;
4848
Redis::pipeline(function ($pipe) use ($baseKey, $microtime) {
@@ -58,7 +58,7 @@ public function recordMiss(string $key, $microtime): void
5858
* @param string $key Cache key
5959
* @param int $size Size in bytes
6060
*/
61-
public function recordWrite(string $key, int $size): void
61+
public function recordWrite(string $key, int $size, array $labels = []): void
6262
{
6363
$baseKey = self::METRICS_PREFIX . $key;
6464
Redis::pipeline(function ($pipe) use ($baseKey, $size) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace ProcessMaker\Cache\Screens;
4+
5+
use Illuminate\Support\Collection;
6+
use ProcessMaker\Contracts\PrometheusMetricInterface;
7+
8+
class ScreenCache extends Collection implements PrometheusMetricInterface
9+
{
10+
11+
public string $label;
12+
13+
public static function makeFrom(PrometheusMetricInterface $screen, $items): ScreenCache
14+
{
15+
$self = new static($items);
16+
$self->label = $screen->getPrometheusMetricLabel();
17+
18+
return $self;
19+
}
20+
21+
/**
22+
* Returns a legible or friendly name for Prometheus metrics.
23+
*
24+
* @return string
25+
*/
26+
public function getPrometheusMetricLabel(): string
27+
{
28+
return $this->label;
29+
}
30+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace ProcessMaker\Contracts;
4+
5+
interface PrometheusMetricInterface
6+
{
7+
/**
8+
* Returns a legible or friendly name for Prometheus metrics.
9+
*
10+
* @return string
11+
*/
12+
public function getPrometheusMetricLabel(): string;
13+
}

‎ProcessMaker/Facades/Metrics.php‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
use Illuminate\Support\Facades\Facade;
66
use ProcessMaker\Services\MetricsService;
77

8+
/**
9+
* @method static \Prometheus\Counter counter(string $name, string $help = null, array $labels = [])
10+
* @method static \Prometheus\Gauge gauge(string $name, string $help = null, array $labels = [])
11+
* @method static \Prometheus\Histogram histogram(string $name, string $help = null, array $labels = [], array $buckets = [0.1, 1, 5, 10])
12+
* @method static void setGauge(string $name, float $value, array $labelValues = [])
13+
* @method static string renderMetrics()
14+
* @method static \Prometheus\CollectorRegistry getCollectionRegistry()
15+
*/
816
class Metrics extends Facade
917
{
1018
/**

‎ProcessMaker/Jobs/CompleteActivity.php‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace ProcessMaker\Jobs;
44

55
use Illuminate\Contracts\Queue\ShouldQueue;
6-
use Illuminate\Database\DatabaseManager;
6+
use ProcessMaker\Facades\Metrics;
77
use ProcessMaker\Managers\DataManager;
88
use ProcessMaker\Models\Process as Definitions;
99
use ProcessMaker\Models\ProcessRequestToken;
@@ -46,5 +46,23 @@ public function action(ProcessRequestToken $token, ActivityInterface $element, a
4646
$manager->updateData($token, $data);
4747
$this->engine->runToNextState();
4848
$element->complete($token);
49+
50+
Metrics::counter(
51+
'activity_completed_total',
52+
'Total number of activities completed',
53+
[
54+
'activity_id',
55+
'activity_name',
56+
'process_id',
57+
'request_id',
58+
]
59+
)->inc(
60+
[
61+
'activity_id' => $element->getId(),
62+
'activity_name' => $element->getName(),
63+
'process_id' => $this->definitionsId,
64+
'request_id' => $this->instanceId,
65+
]
66+
);
4967
}
5068
}

‎ProcessMaker/Models/Screen.php‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Support\Facades\DB;
77
use Illuminate\Validation\Rule;
88
use ProcessMaker\Assets\ScreensInScreen;
9+
use ProcessMaker\Contracts\PrometheusMetricInterface;
910
use ProcessMaker\Contracts\ScreenInterface;
1011
use ProcessMaker\Events\TranslationChanged;
1112
use ProcessMaker\Traits\Exportable;
@@ -63,7 +64,7 @@
6364
* @OA\Property(property="url", type="string"),
6465
* )
6566
*/
66-
class Screen extends ProcessMakerModel implements ScreenInterface
67+
class Screen extends ProcessMakerModel implements ScreenInterface, PrometheusMetricInterface
6768
{
6869
use SerializeToIso8601;
6970
use HideSystemResources;
@@ -283,4 +284,14 @@ public function scopeFilter($query, $filterStr)
283284

284285
return $query;
285286
}
287+
288+
/**
289+
* Return the label to be used in grafana reports
290+
*
291+
* @return string
292+
*/
293+
public function getPrometheusMetricLabel(): string
294+
{
295+
return 'screen.' . $this->id;
296+
}
286297
}

‎ProcessMaker/Models/ScreenVersion.php‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
namespace ProcessMaker\Models;
44

55
use Illuminate\Database\Eloquent\Builder;
6+
use ProcessMaker\Contracts\PrometheusMetricInterface;
67
use ProcessMaker\Contracts\ScreenInterface;
78
use ProcessMaker\Events\TranslationChanged;
89
use ProcessMaker\Traits\HasCategories;
910
use ProcessMaker\Traits\HasScreenFields;
1011

11-
class ScreenVersion extends ProcessMakerModel implements ScreenInterface
12+
class ScreenVersion extends ProcessMakerModel implements ScreenInterface, PrometheusMetricInterface
1213
{
1314
use HasCategories;
1415
use HasScreenFields;
@@ -77,4 +78,9 @@ public function scopePublished(Builder $query)
7778
{
7879
return $query->where('draft', false);
7980
}
81+
82+
public function getPrometheusMetricLabel(): string
83+
{
84+
return 'screen.' . $this->screen_id;
85+
}
8086
}

0 commit comments

Comments
 (0)