Metrics api (#155)

* Metrics API Templating

* Metrics API Templating

* Adding Style

* Added base Metrics Providers

* Rework this commit

* Minor changes in exporter

* Added test for abstract metrics exporter

* Fixed namespace in test

* Added Metrics interface stub

* Added additional check in GlobalMeterProvicerTest

* Style fixes

* Added fixes according to php stan

* Removed comments

* Refactored Exporter

* Removed unused array from AbstractExporter

* Refactored API and aded base files

* Installed new dependencies

* Added example for Prometheus Metrics

* Fixed Phan config

* Added UpDownCounter and tests for it

* Fixed prometheus misspelling, renamed shortcut command for metrics example

* Added docblocks

* Refactored structure of metrics prometheus example

* Added info in readme how to run metrics prometheus example

* Style fixes for counters

* Removed unused import in test

* Added more typization for metric labels

* Added todo for later

* Added versioning in MeterProvider

* Fix for versioning in MeterProvider

* Added ValueRecorder class

* Fixed typo in docblock

* Removed Assert library

* Removed assert library from phpstan config

* Fixed style

* Removed ValueRecorder from this branch

Co-authored-by: Bob Strecansky <bob.strecansky@gmail.com>
This commit is contained in:
Artem Prozorov 2020-08-10 23:32:19 +03:00 committed by GitHub
parent ce036e540f
commit b49df469d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1016 additions and 2 deletions

View File

@ -366,6 +366,7 @@ return [
'vendor/php-http',
'vendor/phan/phan/src/Phan',
'vendor/phpunit/phpunit/src',
'vendor/endclothing/prometheus_client_php/src',
],
// A list of individual files to include in analysis

View File

@ -13,6 +13,11 @@ examples: FORCE
$(DC_RUN_PHP) php ./examples/AlwaysOnTraceExample.php
$(DC_RUN_PHP) php ./examples/AlwaysOffTraceExample.php
$(DC_RUN_PHP) php ./examples/JaegerExporterExample.php
metrics-prometheus-example:
@docker-compose -f docker-compose.prometheus.yaml up -d web
@docker-compose -f docker-compose.prometheus.yaml run php-prometheus php /var/www/public/examples/prometheus/PrometheusMetricsExample.php
stop-prometheus:
@docker-compose -f docker-compose.prometheus.yaml stop
bash:
$(DC_RUN_PHP) bash
style:

View File

@ -50,13 +50,24 @@ To make sure the tests in this repo work as you expect, you can use the included
Execute `make test` from your bash compatible shell. This will output the test output as well as a test coverage analysis. Code that doesn't pass our currently defined tests will emit a failure in CI
## Examples
### Trace
You can use the [examples/AlwaysSampleTraceExample.php](/examples/AlwaysOnTraceExample.php) file to test out the reference implementation we have. This example perfoms a sample trace with a grouping of 5 spans and POSTs the result to a local zipkin instance.
The PHP should execute by itself (if you have a zipkin instance running on localhost), but if you'd like a no-fuss way to test this out with docker and docker-compose, you can perform the following simple steps:
1.) Install the necessary dependencies by running `make install`. This will install the composer dependencies and store them in `/vendor`
2.) Execute the example trace using `make examples`.
2.) Execute the example trace using `make examples`.
Exported spans can be seen in zipkin at [http://127.0.0.1:9411](http://127.0.0.1:9411)
Exported spans can also be seen in jaeger at [http://127.0.0.1:16686](http://127.0.0.1:16686)
### Metrics
You can use the [examples/prometheus/PrometheusMetricsExample.php](/examples/prometheus/PrometheusMetricsExample.php) file to test out the reference implementation we have. This example will create a counter that will be scraped by local Prometheus instance.
The easy way to test the example out with docker and docker-compose is:
1.) Run `make metrics-prometheus-example`. Make sure that local ports 8080, 6379 and 9090 are available.
2.) Open local Prometheus instance: http://localhost:9090
3.) Go to Graph section, type "opentelemetry_prometheus_counter" in the search field or select it in the dropdown menu. You will see the counter value. Every other time you run `make metrics-prometheus-example` will increment the counter but remember that Prometheus scrapes values once in 10 seconds.
4.) In order to stop docker containers for this example just run `make stop-prometheus`

33
api/Metrics/Counter.php Normal file
View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface Counter extends Metric
{
/**
* Adds value to the counter
*
* @access public
* @param int $value
* @return self
*/
public function add(int $value): Counter;
/**
* Increments value
*
* @access public
* @return self
*/
public function increment(): Counter;
/**
* Gets the value
*
* @access public
* @return int
*/
public function getValue(): int;
}

26
api/Metrics/Exporter.php Normal file
View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface Exporter
{
/**
* Possible return values as outlined in the OpenTelemetry spec
*/
const SUCCESS = 0;
const FAILED_NOT_RETRYABLE = 1;
const FAILED_RETRYABLE = 2;
/**
* export.
*
* @access public
* @param iterable<Metric> $metrics
* @return int
*
* todo Should we pass a result callback in the 2nd parameter like in JavaScript implementation?
*/
public function export(iterable $metrics): int;
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface LabelableMetric extends Metric
{
/**
* Get $labels
* todo: we will probably need a class Label and a typed collection for labels
*
* @return array<string>
*/
public function getLabels(): array;
/**
* Set $labels
*
* @param array<string> $labels
* @return self
*/
public function setLabels(array $labels);
/**
* Set $labels
*
* @param string $label
* @return self
*/
public function addLabel(string $label);
}

9
api/Metrics/Meter.php Normal file
View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface Meter
{
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface MeterProvider
{
/**
* @access public
* @param string $name - (required) - This name must identify the instrumentation library
* (e.g. io.opentelemetry.contrib.mongodb) and not the instrumented library.
* In case an invalid name (null or empty string) is specified, a working default Meter implementation is returned
* as a fallback rather than returning null or throwing an exception.
* A MeterProvider could also return a no-op Meter here if application owners configure the SDK to suppress
* telemetry produced by this library.
* @param ?string $version - (optional) - Specifies the version of the instrumentation library (e.g. semver:1.0.0)
* @return Meter
*/
public function getMeter(string $name, ?string $version = null): Meter;
}

32
api/Metrics/Metric.php Normal file
View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface Metric
{
/**
* Returns metric's name
*
* @access public
* @return string
*/
public function getName(): string;
/**
* Returns metric's description
*
* @access public
* @return string
*/
public function getDescription(): string;
/**
* Returns metric's type
*
* @access public
* @return int
*/
public function getType(): int;
}

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface MetricKind
{
public const COUNTER = 1;
public const UP_DOWN_COUNTER = 2;
public const VALUE_RECORDER = 3;
public const SUM_OBSERVER = 4;
public const UP_DOWN_SUM_OBSERVER = 4;
public const VALUE_OBSERVER = 5;
public const TYPES = [
self::COUNTER,
self::UP_DOWN_COUNTER,
self::VALUE_RECORDER,
self::SUM_OBSERVER,
self::UP_DOWN_SUM_OBSERVER,
self::VALUE_OBSERVER,
];
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface UpDownCounter extends Counter
{
/**
* Subtracts counter value
*
* @access public
* @param int $value
* @return UpDownCounter
*/
public function subtract(int $value) : UpDownCounter;
/**
* Decrements counter value
*
* @access public
* @return UpDownCounter
*/
public function decrement() : UpDownCounter;
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Metrics;
interface ValueRecorder
{
/**
* record.
*
* @access public
* @param int|float $value
* @return void
*/
public function record($value) : void;
}

View File

@ -8,7 +8,8 @@
"ext-json": "*",
"guzzlehttp/guzzle": "^6.5",
"psr/http-client": "^1.0",
"php-http/guzzle6-adapter": "^2.0"
"php-http/guzzle6-adapter": "^2.0",
"endclothing/prometheus_client_php": "^1.0"
},
"authors": [
{

View File

@ -0,0 +1,30 @@
version: '3.7'
services:
prometheus:
image: prom/prometheus
ports:
- 9090:9090
volumes:
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
redis:
image: redis
ports:
- 6379:6379
web:
image: nginx:alpine
ports:
- 8080:80
depends_on:
- php-prometheus
volumes:
- ./docker/prometheus/nginx.conf:/etc/nginx/conf.d/default.conf
- ./docker/prometheus/index.php:/var/www/public/index.php
php-prometheus:
build:
context: .
dockerfile: docker/prometheus/Dockerfile
volumes:
- ./:/var/www/public
depends_on:
- redis
- prometheus

View File

@ -0,0 +1,11 @@
FROM php:7.3-fpm-alpine
RUN apk update && apk add --no-cache \
$PHPIZE_DEPS
RUN pecl channel-update pecl.php.net && \
pecl install redis \
&& docker-php-ext-enable redis
# Clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/cache/*

25
docker/prometheus/nginx.conf Executable file
View File

@ -0,0 +1,25 @@
server {
listen 80;
index index.php index.html;
server_name 127.0.0.1 localhost;
root /var/www/public/examples/prometheus;
access_log /dev/stdout;
error_log /dev/stdout debug;
underscores_in_headers on;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-prometheus:9000;
fastcgi_index index.php;
fastcgi_read_timeout 1000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

View File

View File

@ -0,0 +1,32 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
external_labels:
monitor: 'prometheus-stack-monitor'
# Load and evaluate rules in this file every 'evaluation_interval' seconds.
# rule_files:
# - "prometheus.rules.yml"
scrape_configs:
- job_name: 'prometheus'
scrape_interval: 10s
scrape_timeout: 5s
static_configs:
- targets: ['localhost:9090']
- job_name: 'webserver'
scrape_interval: 10s
scrape_timeout: 5s
metrics_path: /index.php
static_configs:
- targets: ['web']

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
use OpenTelemetry\Sdk\Metrics\Counter;
use OpenTelemetry\Sdk\Metrics\Exporters\PrometheusExporter;
use Prometheus\CollectorRegistry;
use Prometheus\Storage\Redis;
Redis::setDefaultOptions(
[
'host' => 'redis',
'port' => 6379,
'password' => null,
'timeout' => 0.1, // in seconds
'read_timeout' => '10', // in seconds
'persistent_connections' => false,
]
);
$counter = new Counter('opentelemetry_prometheus_counter', 'Just a quick measurement');
$counter->increment();
$exporter = new PrometheusExporter(CollectorRegistry::getDefault());
$exporter->export([$counter]);

24
examples/prometheus/index.php Executable file
View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
\Prometheus\Storage\Redis::setDefaultOptions(
[
'host' => 'redis',
'port' => 6379,
'password' => null,
'timeout' => 0.1, // in seconds
'read_timeout' => '10', // in seconds
'persistent_connections' => false,
]
);
$registry = \Prometheus\CollectorRegistry::getDefault();
$renderer = new \Prometheus\RenderTextFormat();
$result = $renderer->render($registry->getMetricFamilySamples());
header('Content-type: ' . \Prometheus\RenderTextFormat::MIME_TYPE);
echo $result;

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics;
use OpenTelemetry\Metrics as API;
abstract class AbstractMetric implements API\Metric
{
/**
* @var string $name
*/
protected $name;
/**
* @var string $description
*/
protected $description;
public function __construct(string $name, string $description = '')
{
$this->name = $name;
$this->description = $description;
}
/**
* {@inheritDoc}
*/
public function getName(): string
{
return $this->name;
}
/**
* {@inheritDoc}
*/
public function getDescription(): string
{
return $this->description;
}
}

69
sdk/Metrics/Counter.php Normal file
View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics;
use InvalidArgumentException;
use OpenTelemetry\Metrics as API;
class Counter extends AbstractMetric implements API\Counter, API\LabelableMetric
{
use HasLabels;
/**
* @var int $value
*/
protected $value = 0;
/**
* Get $type
*
* @return int
*/
public function getType(): int
{
return API\MetricKind::COUNTER;
}
/**
* Returns the current value
*
* @access public
* @return int
*/
public function getValue(): int
{
return $this->value;
}
/**
* Increments the current value
*
* @access public
* @return self
*/
public function increment(): API\Counter
{
$this->value++;
return $this;
}
/**
* Adds the specified value to the current counter's value
*
* @access public
* @return self
*/
public function add(int $value): API\Counter
{
if ($value <= 0) {
throw new InvalidArgumentException('Only positive numbers can be added to the Counter');
}
$this->value += $value;
return $this;
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Exceptions;
class CantBeExported extends ExportException
{
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Exceptions;
use Exception;
class ExportException extends Exception
{
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Exceptions;
class RetryableExportException extends ExportException
{
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Exporters;
use Exception;
use OpenTelemetry\Metrics as API;
use OpenTelemetry\Sdk\Metrics\Exceptions\RetryableExportException;
abstract class AbstractExporter implements API\Exporter
{
/**
* {@inheritDoc}
*/
public function export(iterable $metrics): int
{
if (empty($metrics)) {
return API\Exporter::SUCCESS;
}
try {
foreach ($metrics as $metric) {
if (! $metric instanceof API\Metric) {
throw new \InvalidArgumentException('Metric must implement ' . API\Metric::class);
}
}
$this->doExport($metrics);
return API\Exporter::SUCCESS;
} catch (RetryableExportException $exception) {
return API\Exporter::FAILED_RETRYABLE;
} catch (Exception $exception) {
return API\Exporter::FAILED_NOT_RETRYABLE;
}
}
/**
* Sends metrics to the destination system
*
* @access protected
* @param iterable<API\Metric> $metrics
* @return void
*/
abstract protected function doExport(iterable $metrics): void;
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Exporters;
use OpenTelemetry\Metrics as API;
use OpenTelemetry\Sdk\Metrics\Counter;
use OpenTelemetry\Sdk\Metrics\Exceptions\CantBeExported;
use Prometheus\CollectorRegistry;
class PrometheusExporter extends AbstractExporter
{
/**
* @var CollectorRegistry $registry
*/
protected $registry;
/**
* @var string $namespace
*/
protected $namespace;
public function __construct(CollectorRegistry $registry, string $namespace = '')
{
$this->registry = $registry;
$this->namespace = $namespace;
}
/**
* {@inheritDoc}
*/
protected function doExport(iterable $metrics): void
{
foreach ($metrics as $metric) {
switch (get_class($metric)) {
case Counter::class:
$this->exportCounter($metric);
break;
default:
throw new CantBeExported('Unknown metrics type: ' . get_class($metric));
}
}
}
protected function exportCounter(API\Counter $counter): void
{
$labels = ($counter instanceof API\LabelableMetric) ? $counter->getLabels() : [];
$record = $this->registry->getOrRegisterCounter(
$this->namespace,
$counter->getName(),
$counter->getDescription(),
$labels
);
$record->incBy($counter->getValue(), $labels);
}
}

47
sdk/Metrics/HasLabels.php Normal file
View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics;
trait HasLabels
{
/**
* @var array $labels
*/
protected $labels = [];
/**
* {@inheritDoc}
*/
public function getLabels(): array
{
return $this->labels;
}
/**
* {@inheritDoc}
*/
public function setLabels(array $labels)
{
foreach ($labels as $label) {
if (! is_string($label)) {
throw new \InvalidArgumentException('The label is expected to be a string');
}
}
$this->labels = $labels;
return $this;
}
/**
* {@inheritDoc}
*/
public function addLabel(string $label)
{
$this->labels[] = $label;
return $this;
}
}

12
sdk/Metrics/Meter.php Normal file
View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics;
use OpenTelemetry\Metrics as API;
class Meter implements API\Meter
{
// Temp stub
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Providers;
use OpenTelemetry\Metrics as API;
/**
* https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/metrics/api.md#global-meter-provider
*/
final class GlobalMeterProvider
{
/**
* @var API\MeterProvider $globalProvider
*/
protected static $globalProvider;
/**
* Returns a global instance MeterProvider.
* If global instance is missing, new MeterProvider will be lazily created
*
* @access public static
* @return API\MeterProvider
*/
public static function getGlobalProvider(): API\MeterProvider
{
if (empty(static::$globalProvider)) {
static::$globalProvider = new MeterProvider();
}
return static::$globalProvider;
}
/**
* Sets a global instance of MeterProvider
*
* @access public static
* @param API\MeterProvider $globalProvider
* @return void
*/
public static function setGlobalProvider(API\MeterProvider $globalProvider): void
{
static::$globalProvider = $globalProvider;
}
/**
* Accessor for the global provider
*/
public static function __callStatic($name, $arguments)
{
return static::getGlobalProvider()->$name(...$arguments);
}
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics\Providers;
use OpenTelemetry\Metrics as API;
use OpenTelemetry\Sdk\Metrics\Meter;
class MeterProvider implements API\MeterProvider
{
/**
* @var array $meters
*/
protected $meters = [];
/**
* {@inheritDoc}
*/
public function getMeter(string $name, ?string $version = null): API\Meter
{
if (empty($this->meters[$name . $version])) {
$this->meters[$name . $version] = $this->getCreatedMeter($name, $version);
}
return $this->meters[$name . $version];
}
/**
* Creates a new Meter instance
*
* @access protected
* @param string $name
* @param string|null $version Default: null
* @return API\Meter
*/
protected function getCreatedMeter(string $name, string $version = null): API\Meter
{
// todo: once the Meter interface and an implementation are done, change this
return new Meter();
}
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Sdk\Metrics;
use OpenTelemetry\Metrics as API;
class UpDownCounter extends Counter implements API\UpDownCounter
{
/**
* @var int $value
*/
protected $value = 0;
/**
* Get $type
*
* @return int
*/
public function getType(): int
{
return API\MetricKind::UP_DOWN_COUNTER;
}
/**
* Adds the specified value to the current counter's value
*
* @access public
* @return self
*/
public function add(int $value): API\Counter
{
$this->value += $value;
return $this;
}
public function subtract(int $value) : API\UpDownCounter
{
$this->value -= $value;
return $this;
}
public function decrement() : API\UpDownCounter
{
$this->value--;
return $this;
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Sdk\Unit\Metrics;
use OpenTelemetry\Sdk\Metrics\Counter;
use OpenTelemetry\Sdk\Metrics\UpDownCounter;
use PHPUnit\Framework\TestCase;
class CounterTest extends TestCase
{
public function testCounterIncrements()
{
$counter = new Counter('some_counter');
$this->assertSame(0, $counter->getValue());
$counter->increment();
$this->assertSame(1, $counter->getValue());
}
public function testCounterDoesNotAcceptNegativeNumbers()
{
$counter = new Counter('some_counter');
$this->expectException(\InvalidArgumentException::class);
$counter->add(-1);
}
public function testUpDownCounterIncrementsAndDecrements()
{
$counter = new UpDownCounter('some_counter');
$this->assertSame(0, $counter->getValue());
$counter->increment();
$this->assertSame(1, $counter->getValue());
$counter->decrement();
$this->assertSame(0, $counter->getValue());
}
public function testUpDownCounterAcceptNegativeNumbers()
{
$counter = new UpDownCounter('some_up_down_counter');
$this->assertSame(0, $counter->getValue());
$counter->add(-1);
$this->assertSame(-1, $counter->getValue());
$counter->subtract(3);
$this->assertSame(-4, $counter->getValue());
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Sdk\Unit\Metrics\Exporters;
use OpenTelemetry\Metrics as API;
use OpenTelemetry\Sdk\Metrics\Exporters\AbstractExporter;
use PHPUnit\Framework\TestCase;
class AbstractExporterTest extends TestCase
{
public function testEmptyMetricsExportReturnsSuccess()
{
$this->assertEquals(
API\Exporter::SUCCESS,
$this->getExporter()->export([])
);
}
public function testErrorReturnsIfTryingToExportNotAMetric()
{
$this->assertEquals(
API\Exporter::FAILED_NOT_RETRYABLE,
$this->getExporter()->export([1])
);
}
protected function getExporter(): AbstractExporter
{
return new class() extends AbstractExporter {
protected function doExport(iterable $metrics): void
{
}
};
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Sdk\Unit\Metrics;
use OpenTelemetry\Sdk\Metrics\HasLabels;
use PHPUnit\Framework\TestCase;
class HasLabelTest extends TestCase
{
protected $labelable;
public function setUp(): void
{
$this->labelable = new class() {
use HasLabels;
};
}
public function testHasLabelAcceptsValues()
{
$this->assertEmpty($this->labelable->getLabels());
$expected = ['label_one', 'label_two'];
$this->labelable->setLabels($expected);
$this->assertSame($expected, $this->labelable->getLabels());
}
public function testHasLabelAcceptsOnlyStrings()
{
$this->expectException(\InvalidArgumentException::class);
$this->labelable->setLabels([new \stdClass()]);
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Sdk\Unit\Metrics\Providers;
use OpenTelemetry\Sdk\Metrics\Meter;
use OpenTelemetry\Sdk\Metrics\Providers\GlobalMeterProvider;
use OpenTelemetry\Sdk\Metrics\Providers\MeterProvider;
use PHPUnit\Framework\TestCase;
class GlobalMeterProvicerTest extends TestCase
{
public function testGLobalMeterProviderSettersAndGetters()
{
$defaultProvider = GlobalMeterProvider::getGlobalProvider();
$this->assertInstanceOf(MeterProvider::class, $defaultProvider);
$meter = GlobalMeterProvider::getMeter('test');
$this->assertInstanceOf(Meter::class, $meter);
$customGlobalProvider = new MeterProvider();
GlobalMeterProvider::setGlobalProvider($customGlobalProvider);
$this->assertSame($customGlobalProvider, GlobalMeterProvider::getGlobalProvider());
}
}