Giter Club home page Giter Club logo

laravel-metrics's Introduction

Laravel Metrics

Latest Version on Packagist Total Downloads Software License

This package makes it incredibly easy to ship app metrics to backends such as PostHog, InfluxDB or CloudWatch.

There are two major components: a facade that lets you create metrics on your own, and an event listener to automatically send metrics for Laravel events.

Installation

You know the drill...

composer require stechstudio/laravel-metrics

Backend configuration

PostHog

  1. Install the PostHog PHP client: composer require posthog/posthog-php

  2. Add the following to your .env file:

METRICS_BACKEND=posthog
POSTHOG_API_KEY=...

InfluxDB v1.7 and under

  1. Install the InfluxDB PHP client: composer require influxdb/influxdb-php

  2. Add the following to your .env file:

METRICS_BACKEND=influxdb
IDB_USERNAME=...
IDB_PASSWORD=...
IDB_HOST=...
IDB_DATABASE=...
IDB_VERSION=1 # Default

# Only if you are not using the default 8086
IDB_TCP_PORT=...

# If you want to send metrics over UDP instead of TCP
IDB_UDP_PORT=...

InfluxDB V1.8 and above

  1. Install the InfluxDB PHP client: composer require influxdata/influxdb-client-php

  2. Add the following to your .env file:

  3. In order to use UDP with InfluxDB V1.8+ you must follow extra setup steps

Add the following to your .env file:

METRICS_BACKEND=influxdb
IDB_TOKEN=...
IDB_DATABASE=... # Use the name of your desired bucket for this value
IDB_HOST=...
IDB_ORG=...
IDB_VERSION=2

# Only if you are not using the default 8086
IDB_TCP_PORT=...

# If you want to send metrics over UDP instead of TCP
IDB_UDP_PORT=...

CloudWatch

  1. Install the AWS PHP SDK: composer require aws/aws-sdk-php.

  2. Add the following to your .env file:

METRICS_BACKEND=cloudwatch
CLOUDWATCH_NAMESPACE=...

AWS_DEFAULT_REGION=...
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

Prometheus

  1. Install the Prometheus PHP client: composer require promphp/prometheus_client_php
  2. Configuring the backend to use Prometheus, makes sense only if you have an endpoint to expose them. Its purpose is only to format the registered metrics in a way that Prometheus can scrape them.
METRICS_BACKEND=prometheus

NullDriver (for development)

If you need to disable metrics just set the backend to null:

METRICS_BACKEND=null

This null driver will simply discard any metrics.

Sending an individual metric

You can create metric by using the facade like this:

Metrics::create('order_placed')
    ->setValue(1)
    ->setTags([
        'source' => 'email-campaign',
        'user' => 54
    ]);

The only required attribute is the name, everything else is optional.

Driver mapping

This is how we are mapping metric attributes in our backends.

Metric attribute PostHog InfluxDB CloudWatch Prometheus
name event measurement MetricName name
value properties[value] fields[value] Value value
unit ignored ignored Unit ignored
resolution ignored ignored StorageResolution ignored
tags ignored tags Dimensions keys -> labelNames
values -> labelValues
extra properties fields ignored ignored
timestamp ignored timestamp Timestamp ignored
description ignored ignored ignored help
namespace ignored ignored ignored namespace
type ignored ignored ignored used to register counter or gauge metric

See the CloudWatch docs and InfluxDB docs for more information on their respective data formats. Note we only do minimal validation, you are expected to know what data types and formats your backend supports for a given metric attribute.

Sending metrics from Laravel events

The main motivation for this library was to send metrics automatically when certain events occur in a Laravel application. So this is where things really get fun!

Let's say you have a simple Laravel event called OrderReceived:

class OrderReceived {
    protected $order;
    
    public function __construct($order)
    {
        $this->order = $order;
    }
}

The first step is to implement an interface:

use STS\Metrics\Contracts\ShouldReportMetric;

class OrderReceived implements ShouldReportMetric {

This will tell the global event listener to send a metric for this event.

There are two different ways you can then provide the metric details.

1. Use the ProvidesMetric trait

You can also include a trait that helps with building this metric:

use STS\Metrics\Contracts\ShouldReportMetric;
use STS\Metrics\Traits\ProvidesMetric;

class OrderReceived implements ShouldReportMetric {
    use ProvidesMetric;

In this case, the trait will build a metric called order_received (taken from the class name) with a value of 1.

Customizing event metric data

If you decide to use the trait, you likely will want to customize the event metric data.

You can provide metric data with class attributes:

class OrderReceived implements ShouldReportMetric {
    use ProvidesMetric;
    
    protected $metricName = "new_order";
    protected $metricTags = ["category" => "revenue"];
    ...

Or if some of your metric data is dynamic you can use getter methods:

public function getMetricValue()
{
    return $this->order->total;
}

You can provide any of our metric attributes using these class attributes or getter methods.

2. Create the metric yourself

Depending on how much detail you need to provide for your metric, it may be simpler to just build it yourself. In this case you can ditch the trait and simply provide a public createMetric function that returns a new Metric instance:

use STS\Metrics\Contracts\ShouldReportMetric;
use STS\Metrics\Metric;

class OrderReceived implements ShouldReportMetric {
    protected $order;
    
    public function __construct($order)
    {
        $this->order = $order;
    }
    
    public function createMetric()
    {
        return (new Metric('order_received'))
            ->setValue(...)
            ->setTags([...])
            ->setTimestamp(...)
            ->setResolutions(...);
    }
}

laravel-metrics's People

Contributors

chinthakagodawita avatar djfrailey avatar dmtar avatar dp88 avatar fedeisas avatar ilya-nurullin avatar jansgescheit avatar jszobody avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

laravel-metrics's Issues

Prometheus support?

Are you guys planing adding dependency to prometheus_client_php and adding specific Driver that uses their RenderTextFormat for output?

Metrcis are never flushed when using Laravel Octane

Please add support for Laravel Octane by providing an event listener that calls the same logic registered as a php shutdown function. This will enable Octane users to use the event during the request terminated octane lifecycle event.

L8 Support - deprecated $app property of the Illuminate\Support\Manager

On my laravel 8 test branch i got the following error:

  Undefined property: STS\Metrics\MetricsManager::$app

  at vendor/stechstudio/laravel-metrics/src/MetricsManager.php:21
     17▕      * @return string
     18▕      */
     19▕     public function getDefaultDriver()
     20▕     {
  ➜  21▕         return $this->app['config']['metrics.default'] == null
     22▕             ? 'null'
     23▕             : $this->app['config']['metrics.default'];
     24▕     }
     25▕ 

The Laravel 8 upgrade guide says:

Manager $app Property
Likelihood Of Impact: Low
The previously deprecated $app property of the Illuminate\Support\Manager class has been removed. If you were relying on this property, you should use the $container property instead.

Copied from her https://laravel.com/docs/8.x/upgrade

Log Driver support.

It would be helpful to have a driver that dumps all recorded metrics into a log file.

CloudWatch Formatter does not format the dimension correct

Used library version

docker-compose exec worker composer show stechstudio/laravel-metrics
name     : stechstudio/laravel-metrics
descrip. : Easily track metrics from Laravel events, or on your own
keywords : 
versions : * 1.2
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : 
source   : [git] https://github.com/stechstudio/laravel-metrics.git 506593d1ddbb42fbfd972959fc3414a46c6106b8
dist     : [zip] https://api.github.com/repos/stechstudio/laravel-metrics/zipball/506593d1ddbb42fbfd972959fc3414a46c6106b8 506593d1ddbb42fbfd972959fc3414a46c6106b8
path     : /var/www/html/vendor/stechstudio/laravel-metrics
names    : stechstudio/laravel-metrics

support
issues : https://github.com/stechstudio/laravel-metrics/issues
source : https://github.com/stechstudio/laravel-metrics/tree/1.2

autoload
psr-4
STS\Metrics\ => src

requires
illuminate/support ^5.0|^6.0|^7.0
influxdb/influxdb-php ^1.14

requires (dev)
aws/aws-sdk-php ^3.133
mockery/mockery ^1.0
orchestra/testbench ~5.0
phpunit/phpunit ^9.0

Step to reproduce

php artisan tinker
$metric = (new \STS\Metrics\Metric("file_uploaded"))
     ->setResolution(1)
     ->setValue(50)
     ->setUnit('Megabytes')
     ->setTags(['user' => 54]);

dd(
    app(STS\Metrics\Drivers\CloudWatch::class)->format($metric)
);

Result of the dd

[
     "MetricName" => "file_uploaded",
     "Dimensions" => [
          "user" => 54,
     ],
     "StorageResolution" => 1,
     "Timestamp" => 1599226806,
     "Unit" => "Megabytes",
     "Value" => 50,
]

Expected

See https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Dimension.html

[
     "MetricName" => "file_uploaded",
     "Dimensions" => [
           [
               "Name" => "user",
               "Value" => 54,
          ],
     ],
     "StorageResolution" => 1,
     "Timestamp" => 1599226806,
     "Unit" => "Megabytes",
     "Value" => 50,
]

Stack Trace

[04-Sep-2020 13:47:17 UTC] PHP Fatal error:  Uncaught InvalidArgumentException: Found 1 error while validating the input provided for the PutMetricData operation:
app_1            | [MetricData][0][Dimensions][user] must be an associative array. Found int(54) in /var/www/html/vendor/aws/aws-sdk-php/src/Api/Validator.php:65
app_1            | Stack trace:
app_1            | #0 /var/www/html/vendor/aws/aws-sdk-php/src/Middleware.php(78): Aws\Api\Validator->validate('PutMetricData', Object(Aws\Api\StructureShape), Array)
app_1            | #1 /var/www/html/vendor/aws/aws-sdk-php/src/IdempotencyTokenMiddleware.php(77): Aws\Middleware::Aws\{closure}(Object(Aws\Command), NULL)
app_1            | #2 /var/www/html/vendor/aws/aws-sdk-php/src/AwsClientTrait.php(64): Aws\IdempotencyTokenMiddleware->__invoke(Object(Aws\Command))
app_1            | #3 /var/www/html/vendor/aws/aws-sdk-php/src/AwsClientTrait.php(58): Aws\AwsClient->executeAsync(Object(Aws\Command))
app_1            | #4 /var/www/html/vendor/aws/aws-sdk-php/src/AwsClientTrait.php(86): Aws\AwsClient->execute(Object(Aws\Command))
app_1            | #5 /var/www/html/vendor/stechstudio/laravel-metrics/src/Drivers/CloudWatch.php(82): Aws\AwsClient->__call( in /var/www/html/vendor/aws/aws-sdk-php/src/Api/Validator.php on line 65

Used AWS SDK

composer show aws/aws-sdk-php
name     : aws/aws-sdk-php
descrip. : AWS SDK for PHP - Use Amazon Web Services in your PHP project
keywords : amazon, aws, cloud, dynamodb, ec2, glacier, s3, sdk
versions : * 3.148.1
type     : library
license  : Apache License 2.0 (Apache-2.0) (OSI approved) https://spdx.org/licenses/Apache-2.0.html#licenseText
homepage : http://aws.amazon.com/sdkforphp
source   : [git] https://github.com/aws/aws-sdk-php.git 56caf889ddc8dcc5b6999c234998f3b945d787e3
dist     : [zip] https://api.github.com/repos/aws/aws-sdk-php/zipball/56caf889ddc8dcc5b6999c234998f3b945d787e3 56caf889ddc8dcc5b6999c234998f3b945d787e3
path     : /var/www/html/vendor/aws/aws-sdk-php
names    : aws/aws-sdk-php

autoload
psr-4
Aws\ => src/
files

requires
ext-json *
ext-pcre *
ext-simplexml *
guzzlehttp/guzzle ^5.3.3|^6.2.1|^7.0
guzzlehttp/promises ^1.0
guzzlehttp/psr7 ^1.4.1
mtdowling/jmespath.php ^2.5
php >=5.5

requires (dev)
andrewsville/php-token-reflection ^1.4
aws/aws-php-sns-message-validator ~1.0
behat/behat ~3.0
doctrine/cache ~1.4
ext-dom *
ext-openssl *
ext-pcntl *
ext-sockets *
nette/neon ^2.3
paragonie/random_compat >= 2
phpunit/phpunit ^4.8.35|^5.4.3
psr/cache ^1.0
psr/simple-cache ^1.0
sebastian/comparator ^1.2.3

suggests
aws/aws-php-sns-message-validator To validate incoming SNS notifications
doctrine/cache To use the DoctrineCacheAdapter
ext-curl To send requests using cURL
ext-openssl Allows working with CloudFront private distributions and verifying received SNS messages
ext-sockets To use client-side monitoring

Is this 5.7 compatible?

I'm sending metrics to cloudwatch from Laravel 5.7 but I never seen them.

Also trying to implement in an Event class adding implements ShouldReportMetric { gives a php error about the class must be to be abstract.

is this package compatible with Laravel 5.7?

Request: Ability to disable metrics

It is useful to be able to disable the metric collection when developing. I suggest to add new .env variable METRICS_ENABLED = true/false.

Perhaps the easiest way to do this:
MetricsServiceProvider.php

protected function setupListener()
{
    if (env('METRICS_ENABLED', true) === true) {
        $this->app['events']->listen("*", function ($eventName, $payload) {
            $event = array_pop($payload);

            if (is_object($event) && $event instanceof ShouldReportMetric) {
                $this->app->make(MetricsManager::class)->driver()
                    ->add($event->createMetric());
            }
        });
    }
}

protected function createManager()
{
    $metrics = new MetricsManager($this->app);

    // Flush all queued metrics when PHP shuts down when METRICS_ENABLED=true
    if (env('METRICS_ENABLED', true) === true) {
      register_shutdown_function(function () use ($metrics) {
        foreach ($metrics->getDrivers() AS $driver) {
          $driver->flush();
        }
      });
    }

    return $metrics;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.