renoki-co/laravel-exporter-contracts

Base contracts implementation for Prometheus exports in Laravel.


README

CI codecov StyleCI Latest Stable Version Total Downloads Monthly Downloads License

Base contracts implementation for Prometheus exports in Laravel.

🤝 Supporting

If you are using one or more Renoki Co. open-source packages in your production apps, in presentation demos, hobby projects, school projects or so, sponsor our work with Github Sponsors. 📦

🚀 Installation

You can install the package via composer:

composer require renoki-co/laravel-exporter-contracts

Publish the config:

$ php artisan vendor:publish --provider="RenokiCo\LaravelExporter\LaravelExporterServiceProvider" --tag="config"

🙌 Usage

All you have to do is to create a \RenokiCo\LaravelExporter\Metric class that defines how the values will update on each Prometheus call to scrap, and the definition of the collector.

By default, metrics are available on the /exporter/group/metrics endpoint and you can point Prometheus towards it for scraping. (i.e. http://localhost/exporter/group/metrics)

You can choose one of the following classes to extend:

  • \RenokiCo\LaravelExporter\GaugeMetric for gauges
  • \RenokiCo\LaravelExporter\CounterMetric for counters

For example, you can define gauges for users:

use RenokiCo\LaravelExporter\GaugeMetric;

class DatabaseUsers extends GaugeMetric
{
    /**
     * Get the metric help.
     *
     * @return string
     */
    protected function help(): string
    {
        return 'Get the total amount of users.';
    }

    /**
     * Perform the update call on the collector.
     * Optional, as some metrics can be modified somewhere else.
     *
     * @return void
     */
    public function update(): void
    {
        $this->set(User::count());
    }
}

In your AppServiceProvider's boot() method, register your metric:

use RenokiCo\LaravelExporter\Exporter;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Exporter::register(DatabaseUsers::class);
    }

    // ...
}

You don't need to set the values. When the Prometheus scraper will make the request for metrics, the gauge will automatically be set.

Labelling

You may label data by setting default values (i.e. server name, static data, etc.) and on-update.

class DatabaseRecords extends GaugeMetric
{
    /**
     * Define the default labels with their values.
     *
     * @return array
     */
    protected function defaultLabels(): array
    {
        return [
            'static_label' => 'static-value',
        ];
    }

    /**
     * Get the metric allowed labels.
     *
     * @return array
     */
    protected function allowedLabels(): array
    {
        return [
            'model',
            'static_label',
        ];
    }

    /**
     * Perform the update call on the collector.
     * Optional, as some metrics can be modified somewhere else.
     *
     * @return void
     */
    public function update(): void
    {
        $models = [
            User::class,
            Post::class,
            Team::class,
        ];

        foreach ($models as $model) {
            $this->set(
                value: $model::count(),
                labels: ['model' => $model,
            ]);
        }
    }
}

Grouping

If you wish to have separate endpoints for different metrics, consider specifying it in the $showsOnGroup property:

class CustomMetrics extends Metric
{
    /**
     * The group this metric gets shown into.
     *
     * @var string|null
     */
    public static $showsOnGroup = 'metrics-reloaded';

    // ...
}

Under the hood, Laravel Exporter registers a route that allows you to scrape any group:

Route::get('/exporter/group/{group?}', ...);

To scrape this specifc metric (and other metrics that are associated with this group), the endpoint is /exporter/group/metrics-reloaded (i.e. http://localhost/exporter/group/metrics-reloaded).

Sending string responses

In some cases you may want to export the string-alike, Prometheus-formatted response without using the internal metrics.

To do so, use the exportResponse function. The function will return the response directly instead of relying on the Metric class and subsequent class registrations via the Exporter::register() function.

use RenokiCo\LaravelExporter\Exporter;

Exporter::exportResponse(function () {
    return <<<'PROM'
    # TYPE openswoole_max_conn gauge
    openswoole_max_conn 256
    # TYPE openswoole_coroutine_num gauge
    openswoole_coroutine_num 1
    PROM;
);

When accessing the /metrics endpoint, the response will be the one declared earlier.

For custom groups, pass a second parameter with the group name:

use RenokiCo\LaravelExporter\Exporter;

Exporter::exportResponse(..., 'metrics-reloaded');

🐛 Testing

vendor/bin/phpunit

🤝 Contributing

Please see CONTRIBUTING for details.

🔒 Security

If you discover any security related issues, please email alex@renoki.org instead of using the issue tracker.

🎉 Credits