initial commit
This commit is contained in:
commit
bf1a4e1879
17 changed files with 822 additions and 0 deletions
34
src/CollectorInterface.php
Normal file
34
src/CollectorInterface.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
interface CollectorInterface
|
||||
{
|
||||
/**
|
||||
* Return the name of the collector.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Register all metrics associated with the collector.
|
||||
*
|
||||
* The metrics needs to be registered on the exporter object.
|
||||
* eg:
|
||||
* ```php
|
||||
* $exporter->registerCounter('search_requests_total', 'The total number of search requests.');
|
||||
* ```
|
||||
*
|
||||
* @param PrometheusExporter $exporter
|
||||
*/
|
||||
public function registerMetrics(PrometheusExporter $exporter);
|
||||
|
||||
/**
|
||||
* Collect metrics data, if need be, before exporting.
|
||||
*
|
||||
* As an example, this may be used to perform time consuming database queries and set the value of a counter
|
||||
* or gauge.
|
||||
*/
|
||||
public function collect();
|
||||
}
|
41
src/MetricsController.php
Normal file
41
src/MetricsController.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
use Illuminate\Routing\Controller;
|
||||
use Prometheus\RenderTextFormat;
|
||||
|
||||
class MetricsController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var $prometheusExporter
|
||||
*/
|
||||
protected $prometheusExporter;
|
||||
|
||||
/**
|
||||
* @param PrometheusExporter $prometheusExporter
|
||||
*/
|
||||
public function __construct(PrometheusExporter $prometheusExporter)
|
||||
{
|
||||
$this->prometheusExporter = $prometheusExporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /metrics
|
||||
*
|
||||
* The route path is configurable in the prometheus.metrics_route_path config var, or the
|
||||
* PROMETHEUS_METRICS_ROUTE_PATH env var.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function getMetrics()
|
||||
{
|
||||
$metrics = $this->prometheusExporter->export();
|
||||
|
||||
$renderer = new RenderTextFormat();
|
||||
$result = $renderer->render($metrics);
|
||||
|
||||
return response($result)
|
||||
->header('Content-Type', RenderTextFormat::MIME_TYPE);
|
||||
}
|
||||
}
|
235
src/PrometheusExporter.php
Normal file
235
src/PrometheusExporter.php
Normal file
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Prometheus\CollectorRegistry;
|
||||
|
||||
class PrometheusExporter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
/**
|
||||
* @var CollectorRegistry
|
||||
*/
|
||||
protected $prometheus;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $collectors = [];
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @param CollectorRegistry $prometheus
|
||||
* @param array $collectors
|
||||
*/
|
||||
public function __construct($namespace, CollectorRegistry $prometheus, array $collectors = [])
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->prometheus = $prometheus;
|
||||
|
||||
foreach ($collectors as $collector) {
|
||||
/** @var CollectorInterface $collector */
|
||||
$this->registerCollector($collector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the metric namespace.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CollectorRegistry.
|
||||
*
|
||||
* @return CollectorRegistry
|
||||
*/
|
||||
public function getPrometheus()
|
||||
{
|
||||
return $this->prometheus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a collector.
|
||||
*
|
||||
* @param CollectorInterface $collector
|
||||
*/
|
||||
public function registerCollector(CollectorInterface $collector)
|
||||
{
|
||||
$name = $collector->getName();
|
||||
|
||||
if (!isset($this->collectors[$name])) {
|
||||
$this->collectors[$name] = $collector;
|
||||
|
||||
$collector->registerMetrics($this->prometheus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all collectors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCollectors()
|
||||
{
|
||||
return $this->collectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a collector by name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return CollectorInterface
|
||||
*/
|
||||
public function getCollector($name)
|
||||
{
|
||||
if (!isset($this->collectors[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('The collector "%s" is not registered.', $name));
|
||||
}
|
||||
|
||||
return $this->collectors[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a counter.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @return \Prometheus\Counter
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#counter
|
||||
*/
|
||||
public function registerCounter($name, $help, $labels = [])
|
||||
{
|
||||
return $this->prometheus->registerCounter($this->namespace, $name, $help, $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a counter.
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Prometheus\Counter
|
||||
*/
|
||||
public function getCounter($name)
|
||||
{
|
||||
return $this->prometheus->getCounter($this->namespace, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return or register a counter.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @return \Prometheus\Counter
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#counter
|
||||
*/
|
||||
public function getOrRegisterCounter($name, $help, $labels = [])
|
||||
{
|
||||
return $this->prometheus->getOrRegisterCounter($this->namespace, $name, $help, $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a gauge.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @return \Prometheus\Gauge
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#gauge
|
||||
*/
|
||||
public function registerGauge($name, $help, $labels = [])
|
||||
{
|
||||
return $this->prometheus->registerGauge($this->namespace, $name, $help, $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a gauge.
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Prometheus\Counter
|
||||
*/
|
||||
public function getGauge($name)
|
||||
{
|
||||
return $this->prometheus->getCounter($this->namespace, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return or register a gauge.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @return \Prometheus\Gauge
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#gauge
|
||||
*/
|
||||
public function getOrRegisterGauge($name, $help, $labels = [])
|
||||
{
|
||||
return $this->prometheus->getOrRegisterGauge($this->namespace, $name, $help, $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a histogram.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @param array $buckets
|
||||
* @return \Prometheus\Histogram
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#histogram
|
||||
*/
|
||||
public function registerHistogram($name, $help, $labels = [], $buckets = null)
|
||||
{
|
||||
return $this->prometheus->registerHistogram($this->namespace, $name, $help, $labels, $buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a histogram.
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Prometheus\Histogram
|
||||
*/
|
||||
public function getHistogram($name)
|
||||
{
|
||||
return $this->prometheus->getHistogram($this->namespace, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return or register a histogram.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $help
|
||||
* @param array $labels
|
||||
* @param array $buckets
|
||||
* @return \Prometheus\Histogram
|
||||
* @see https://prometheus.io/docs/concepts/metric_types/#histogram
|
||||
*/
|
||||
public function getOrRegisterHistogram($name, $help, $labels = [], $buckets = null)
|
||||
{
|
||||
return $this->prometheus->getOrRegisterHistogram($this->namespace, $name, $help, $labels, $buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the metrics from all collectors.
|
||||
*
|
||||
* @return \Prometheus\MetricFamilySamples[]
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
foreach ($this->collectors as $collector) {
|
||||
/** @var CollectorInterface $collector */
|
||||
$collector->collect();
|
||||
}
|
||||
|
||||
return $this->prometheus->getMetricFamilySamples();
|
||||
}
|
||||
}
|
18
src/PrometheusFacade.php
Normal file
18
src/PrometheusFacade.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class PrometheusFacade extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'prometheus';
|
||||
}
|
||||
}
|
72
src/PrometheusServiceProvider.php
Normal file
72
src/PrometheusServiceProvider.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Prometheus\CollectorRegistry;
|
||||
use Prometheus\Storage\Adapter;
|
||||
|
||||
class PrometheusServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Perform post-registration booting of services.
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__ . '/../config/prometheus.php' => config_path('prometheus.php'),
|
||||
]);
|
||||
|
||||
if (config('prometheus.metrics_route_enabled')) {
|
||||
$this->loadRoutesFrom(__DIR__ . '/routes.php');
|
||||
}
|
||||
|
||||
$exporter = $this->app->make(PrometheusExporter::class); /** @var PrometheusExporter $exporter */
|
||||
foreach (config('prometheus.collectors') as $class) {
|
||||
$collector = $this->app->make($class);
|
||||
$exporter->registerCollector($collector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register bindings in the container.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->mergeConfigFrom(__DIR__ . '/../config/prometheus.php', 'prometheus');
|
||||
|
||||
$this->app->singleton(PrometheusExporter::class, function ($app) {
|
||||
$adapter = $app['prometheus.storage_adapter'];
|
||||
$prometheus = new CollectorRegistry($adapter);
|
||||
return new PrometheusExporter(config('prometheus.namespace'), $prometheus);
|
||||
});
|
||||
$this->app->alias(PrometheusExporter::class, 'prometheus');
|
||||
|
||||
$this->app->bind('prometheus.storage_adapter_factory', function ($app) {
|
||||
return new StorageAdapterFactory($app);
|
||||
});
|
||||
|
||||
$this->app->bind(Adapter::class, function ($app) {
|
||||
$factory = $app['prometheus.storage_adapter_factory']; /** @var StorageAdapterFactory $factory */
|
||||
$driver = config('prometheus.storage_adapter');
|
||||
$configs = config('storage_adapters');
|
||||
$config = array_get($configs, $driver, []);
|
||||
return $factory->make($driver, $config);
|
||||
});
|
||||
$this->app->alias(Adapter::class, 'prometheus.storage_adapter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the services provided by the provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provides()
|
||||
{
|
||||
return [
|
||||
'prometheus',
|
||||
'prometheus.storage_adapter_factory',
|
||||
'prometheus.storage_adapter',
|
||||
];
|
||||
}
|
||||
}
|
61
src/StorageAdapterFactory.php
Normal file
61
src/StorageAdapterFactory.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Superbalist\LaravelPrometheusExporter;
|
||||
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use InvalidArgumentException;
|
||||
use Prometheus\Storage\Adapter;
|
||||
use Prometheus\Storage\APC;
|
||||
use Prometheus\Storage\InMemory;
|
||||
use Prometheus\Storage\Redis;
|
||||
|
||||
class StorageAdapterFactory
|
||||
{
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @param Container $container
|
||||
*/
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory a storage adapter.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param array $config
|
||||
* @return Adapter
|
||||
*/
|
||||
public function make($driver, array $config = [])
|
||||
{
|
||||
switch ($driver) {
|
||||
case 'memory':
|
||||
return new InMemory();
|
||||
case 'redis':
|
||||
return $this->makeRedisAdapter($config);
|
||||
case 'apc':
|
||||
return new APC();
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('The driver [%s] is not supported.', $driver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory a redis storage adapter.
|
||||
*
|
||||
* @param array $config
|
||||
* @return Redis
|
||||
*/
|
||||
protected function makeRedisAdapter(array $config)
|
||||
{
|
||||
if (isset($config['prefix'])) {
|
||||
Redis::setPrefix($config['prefix']);
|
||||
}
|
||||
return new Redis($config);
|
||||
}
|
||||
}
|
5
src/routes.php
Normal file
5
src/routes.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
Route::get(config('prometheus.metrics_route_path'), 'MetricsController@getMetrics')
|
||||
->middleware(config('prometheus.metrics_route_middleware'))
|
||||
->name('metrics');
|
Loading…
Add table
Add a link
Reference in a new issue