Skip to content

Commit fab3409

Browse files
committed
Handle metrics for databases
1 parent 9ba3ff3 commit fab3409

File tree

3 files changed

+73
-15
lines changed

3 files changed

+73
-15
lines changed

config/metrics.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
<?php
22

33
return [
4+
// Allowed values: 'redis', 'apc', 'apcng', 'memory' (default)
5+
'adapter' => env('METRICS_ADAPTER', 'memory'),
6+
7+
// What metrics do we want to report on?
8+
'handle' => [
9+
'database' => env('METRICS_HANDLE_DATABASE', true),
10+
'http' => env('METRICS_HANDLE_HTTP', true),
11+
],
12+
413
// The route configuration controls which path the metrics data is served on
514
'route' => [
615
'enabled' => env('ENABLE_METRICS', true),

src/CloudNativeServiceProvider.php

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,32 @@
44

55
use Illuminate\Contracts\Config\Repository;
66
use Illuminate\Contracts\Http\Kernel;
7+
use Illuminate\Database\Events\QueryExecuted;
78
use Illuminate\Routing\Router;
9+
use Illuminate\Support\Facades\App;
10+
use Illuminate\Support\Facades\DB;
11+
use Illuminate\Support\Facades\Log;
812
use Illuminate\Support\ServiceProvider;
13+
use Jobilla\CloudNative\Laravel\Exceptions\UnsupportedAdapterException;
914
use Jobilla\CloudNative\Laravel\Http\Controllers\ServeMetrics;
1015
use Jobilla\CloudNative\Laravel\Http\Middleware\RecordPrometheusMetrics;
1116
use Prometheus\CollectorRegistry;
1217
use Prometheus\Storage\APC;
18+
use Prometheus\Storage\APCng;
19+
use Prometheus\Storage\InMemory;
20+
use Prometheus\Storage\Redis;
1321

1422
class CloudNativeServiceProvider extends ServiceProvider
1523
{
24+
protected CollectorRegistry $registry;
25+
1626
public function register()
1727
{
1828
$this->mergeConfigFrom(__DIR__.'/../config/metrics.php', 'metrics');
19-
20-
$this->app->singleton(CollectorRegistry::class, function () {
21-
return new CollectorRegistry(new APC());
22-
});
2329
}
2430

2531
public function boot(Repository $config, Kernel $kernel)
2632
{
27-
$this->publishes([
28-
__DIR__.'/../config/logging.php' => config_path('logging.php'),
29-
__DIR__.'/../config/metrics.php' => config_path('metrics.php'),
30-
], 'cloud-native-config');
31-
32-
$this->publishes([
33-
__DIR__.'/../config/logging.php' => config_path('logging.php'),
34-
], 'cloud-native-logging');
35-
3633
$this->publishes([
3734
__DIR__.'/../config/metrics.php' => config_path('metrics.php'),
3835
], 'cloud-native-metrics');
@@ -41,11 +38,55 @@ public function boot(Repository $config, Kernel $kernel)
4138
__DIR__.'/../assets/Dockerfile' => base_path('Dockerfile'),
4239
], 'dockerfile');
4340

44-
if ($config->get('metrics.route.enabled')) {
41+
$this->app->singleton(CollectorRegistry::class, function () use ($config) {
42+
$adapter = $config->get('metrics.adapter', 'memory');
43+
44+
switch ($adapter) {
45+
case 'redis':
46+
return new CollectorRegistry(new Redis);
47+
break;
48+
case 'apc':
49+
if (filter_var(ini_get('apcu.enable_cli'), FILTER_VALIDATE_BOOLEAN) === false && App::runningInConsole()) {
50+
Log::warning('Metrics adapter temporarily turned to "memory" because apc is disabled in CLI. See: https://www.php.net/manual/en/apcu.configuration.php');
51+
return new CollectorRegistry(new InMemory);
52+
}
53+
54+
return new CollectorRegistry(new APC);
55+
break;
56+
case 'apcng':
57+
return new CollectorRegistry(new APCng);
58+
break;
59+
case 'memory':
60+
return new CollectorRegistry(new InMemory);
61+
break;
62+
default:
63+
throw new UnsupportedAdapterException("Adapter `{$adapter}` is not supported.");
64+
break;
65+
}
66+
});
67+
68+
$this->registry = $this->app->make(CollectorRegistry::class);
69+
70+
if ($this->registry && $config->get('metrics.handle.database')) {
71+
DB::listen(function(QueryExecuted $query) use ($config) {
72+
$query_labels = ['query' => $query->sql, 'mode' => strtok($query->sql, ' ')];
73+
74+
$query_counter = $this->registry->getOrRegisterCounter('db', 'query_total', 'Counter of total queries', array_keys($query_labels));
75+
$query_counter->inc(array_values($query_labels));
76+
77+
$query_duration = $this->registry->getOrRegisterHistogram('db', 'query_duration_ms', 'Duration of query', array_keys($query_labels), $config->get('metrics.buckets'));
78+
$query_duration->observe($query->time, array_values($query_labels));
79+
});
80+
}
81+
82+
if ($this->registry && $config->get('metrics.handle.http')) {
83+
$kernel->prependMiddleware(RecordPrometheusMetrics::class);
84+
}
85+
86+
if ($this->registry && $config->get('metrics.route.enabled')) {
4587
/** @var Router $router */
4688
$router = $this->app['router'];
4789
$router->get($config->get('metrics.route.path'), ServeMetrics::class);
48-
$kernel->prependMiddleware(RecordPrometheusMetrics::class);
4990
}
5091
}
5192
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Jobilla\CloudNative\Laravel\Exceptions;
4+
5+
class UnsupportedAdapterException extends \Exception
6+
{
7+
8+
}

0 commit comments

Comments
 (0)