Skip to content

Commit d2d5146

Browse files
authored
Merge pull request #11 from worksome/feature/otel-config
feat: update to entirely rely on OTEL config
2 parents 3e1ea57 + cda0794 commit d2d5146

11 files changed

+178
-115
lines changed

.github/workflows/tests.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
stability: [prefer-lowest, prefer-stable]
2121
include:
2222
- laravel: 10.*
23-
testbench: 8.*
23+
testbench: ^8.21
2424
- laravel: 11.*
2525
testbench: 9.*
2626

@@ -34,7 +34,6 @@ jobs:
3434
uses: shivammathur/setup-php@v2
3535
with:
3636
php-version: ${{ matrix.php }}
37-
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
3837
coverage: none
3938

4039
- name: Setup problem matchers

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ You can publish the config file with:
2020
```shell
2121
php artisan vendor:publish --tag="laravel-telemetry-config"
2222
```
23+
2324
## Usage
2425

2526
This package will work out of the box with a default OTLP exporter configuration.

UPGRADE.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Upgrade Guide
2+
3+
## Upgrading To 0.5 From 0.4.x
4+
5+
### Configuration Changes
6+
7+
The `telemetry.enabled` configuration key has been moved and negated to `sdk.disabled` to match the underlying
8+
OpenTelemetry SDK.
9+
10+
Please update this value in your configuration if it has been published.
11+
12+
```diff
13+
- 'enabled' => env('LARAVEL_TELEMETRY_ENABLED', true),
14+
+ 'sdk' => [
15+
+ 'disabled' => ! env('LARAVEL_TELEMETRY_ENABLED', true)
16+
+ ],
17+
```

composer.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,20 @@
1717
],
1818
"require": {
1919
"php": "^8.2",
20-
"illuminate/contracts": "^10.0 || ^11.0",
20+
"illuminate/contracts": "^10.48 || ^11.0",
2121
"open-telemetry/api": "^1.0.3",
2222
"open-telemetry/sdk": "^1.0.8",
23-
"open-telemetry/exporter-otlp": "^1.0.3",
23+
"open-telemetry/exporter-otlp": "^1.0.4",
2424
"php-http/guzzle7-adapter": "^1.0"
2525
},
2626
"require-dev": {
27+
"google/protobuf": "^3.25",
28+
"larastan/larastan": "^2.9",
2729
"nunomaduro/collision": "^7.10 || ^8.1",
28-
"larastan/larastan": "^2.8",
29-
"orchestra/testbench": "^8.15 || ^9.0",
30-
"pestphp/pest": "^2.33",
31-
"pestphp/pest-plugin-laravel": "^2.2",
32-
"worksome/coding-style": "^2.8"
30+
"orchestra/testbench": "^8.21.1 || ^9.2",
31+
"pestphp/pest": "^2.34",
32+
"pestphp/pest-plugin-laravel": "^2.4",
33+
"worksome/coding-style": "^2.11"
3334
},
3435
"autoload": {
3536
"psr-4": {

config/telemetry.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
// The Configuration is based on OpenTelemetry's naming convention.
66
return [
77

8-
'enabled' => env('LARAVEL_TELEMETRY_ENABLED', true),
8+
'sdk' => [
9+
'disabled' => ! env('LARAVEL_TELEMETRY_ENABLED', true)
10+
],
911

1012
'exporter' => [
1113
'otlp' => [

src/ConfigConfigurationResolver.php

+11-15
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,28 @@
44

55
namespace Worksome\LaravelTelemetry;
66

7-
use Illuminate\Contracts\Config\Repository;
87
use OpenTelemetry\SDK\Common\Configuration\Resolver\ResolverInterface;
98

109
/**
1110
* Resolves Open Telemetry configuration via Laravel config.
11+
*
12+
* The `config()` function is intentionally used to ensure that the latest config is always used.
1213
*/
1314
class ConfigConfigurationResolver implements ResolverInterface
1415
{
1516
private const PREFIX = 'telemetry';
1617

17-
public function __construct(
18-
private readonly Repository $config,
19-
) {
18+
public function retrieveValue(string $variableName)
19+
{
20+
return config()->get($this->variableNameToConfigKey($variableName));
2021
}
2122

22-
private function getKey(string $variableName): string
23+
public function hasVariable(string $variableName): bool
24+
{
25+
return config()->has($this->variableNameToConfigKey($variableName));
26+
}
27+
28+
private function variableNameToConfigKey(string $variableName): string
2329
{
2430
$names = collect(explode('_', $variableName))
2531
->map(fn(string $key) => strtolower($key))
@@ -28,14 +34,4 @@ private function getKey(string $variableName): string
2834

2935
return implode('.', [self::PREFIX, ...$names]);
3036
}
31-
32-
public function retrieveValue(string $variableName)
33-
{
34-
return $this->config->get($this->getKey($variableName));
35-
}
36-
37-
public function hasVariable(string $variableName): bool
38-
{
39-
return $this->config->has($this->getKey($variableName));
40-
}
4137
}

src/LaravelTelemetryServiceProvider.php

+25-60
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,14 @@
99
use Illuminate\Queue\Events\WorkerStopping;
1010
use Illuminate\Support\ServiceProvider;
1111
use OpenTelemetry\API\LoggerHolder;
12+
use OpenTelemetry\API\Logs\LoggerProviderInterface;
1213
use OpenTelemetry\API\Metrics\MeterProviderInterface;
1314
use OpenTelemetry\API\Trace\TracerProviderInterface;
14-
use OpenTelemetry\SDK\Common\Attribute\Attributes;
1515
use OpenTelemetry\SDK\Common\Configuration\Resolver\CompositeResolver;
16-
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
17-
use OpenTelemetry\SDK\Common\Time\ClockFactory;
18-
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter;
19-
use OpenTelemetry\SDK\Metrics\MeterProvider;
16+
use OpenTelemetry\SDK\Logs\LoggerProviderFactory;
17+
use OpenTelemetry\SDK\Logs\LoggerProviderInterface as LoggerProviderSdkInterface;
18+
use OpenTelemetry\SDK\Metrics\MeterProviderFactory;
2019
use OpenTelemetry\SDK\Metrics\MeterProviderInterface as MeterProviderSdkInterface;
21-
use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader;
22-
use OpenTelemetry\SDK\Metrics\StalenessHandler\NoopStalenessHandlerFactory;
23-
use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry;
24-
use OpenTelemetry\SDK\Registry;
25-
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
2620
use OpenTelemetry\SDK\Trace\TracerProviderFactory;
2721
use OpenTelemetry\SDK\Trace\TracerProviderInterface as TracerProviderSdkInterface;
2822
use Psr\Log\LoggerInterface;
@@ -31,35 +25,19 @@ class LaravelTelemetryServiceProvider extends ServiceProvider
3125
{
3226
public function register(): void
3327
{
34-
$this->app->singleton(MeterProviderSdkInterface::class, function () {
35-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
36-
return null;
37-
}
28+
$this->app->singleton(LoggerProviderSdkInterface::class, function () {
29+
return (new LoggerProviderFactory())->create();
30+
});
3831

39-
return new MeterProvider(
40-
null,
41-
ResourceInfoFactory::defaultResource(),
42-
ClockFactory::getDefault(),
43-
Attributes::factory(),
44-
new InstrumentationScopeFactory(Attributes::factory()),
45-
[
46-
new ExportingReader(
47-
Registry::metricExporterFactory('otlp')->create(),
48-
),
49-
],
50-
new CriteriaViewRegistry(),
51-
new WithSampledTraceExemplarFilter(),
52-
new NoopStalenessHandlerFactory(),
53-
);
32+
$this->app->bind(LoggerProviderInterface::class, LoggerProviderSdkInterface::class);
33+
34+
$this->app->singleton(MeterProviderSdkInterface::class, function () {
35+
return (new MeterProviderFactory())->create();
5436
});
5537

5638
$this->app->bind(MeterProviderInterface::class, MeterProviderSdkInterface::class);
5739

5840
$this->app->singleton(TracerProviderSdkInterface::class, function () {
59-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
60-
return null;
61-
}
62-
6341
return (new TracerProviderFactory())->create();
6442
});
6543

@@ -77,42 +55,18 @@ public function boot(): void
7755
'telemetry',
7856
);
7957

80-
$this->app->beforeResolving(MeterProviderInterface::class, function () {
81-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
82-
return;
83-
}
84-
85-
/** @var LoggerInterface $logger */
86-
$logger = $this->app->get(LoggerInterface::class);
87-
/** @var ConfigConfigurationResolver $configResolver */
88-
$configResolver = $this->app->get(ConfigConfigurationResolver::class);
89-
LoggerHolder::set($logger);
90-
CompositeResolver::instance()->addResolver($configResolver);
91-
});
92-
93-
$this->app->beforeResolving(TracerProviderInterface::class, function () {
94-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
95-
return;
96-
}
97-
98-
/** @var LoggerInterface $logger */
99-
$logger = $this->app->get(LoggerInterface::class);
100-
/** @var ConfigConfigurationResolver $configResolver */
101-
$configResolver = $this->app->get(ConfigConfigurationResolver::class);
102-
LoggerHolder::set($logger);
103-
CompositeResolver::instance()->addResolver($configResolver);
104-
});
58+
$this->prepareConfigResolver();
10559

10660
$this->callAfterResolving(Dispatcher::class, function (Dispatcher $event) {
107-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
61+
if ($this->app->make(Repository::class)->get('telemetry.sdk.disabled')) {
10862
return;
10963
}
11064

11165
$event->listen(WorkerStopping::class, WorkerStoppingFlush::class);
11266
});
11367

11468
$this->app->terminating(function () {
115-
if (! $this->app->make(Repository::class)->get('telemetry.enabled')) {
69+
if ($this->app->make(Repository::class)->get('telemetry.sdk.disabled')) {
11670
return;
11771
}
11872

@@ -129,4 +83,15 @@ public function boot(): void
12983
}
13084
});
13185
}
86+
87+
private function prepareConfigResolver(): void
88+
{
89+
/** @var LoggerInterface $logger */
90+
$logger = $this->app->get(LoggerInterface::class);
91+
92+
LoggerHolder::set($logger);
93+
CompositeResolver::instance()->addResolver(
94+
new ConfigConfigurationResolver()
95+
);
96+
}
13297
}

tests/ExampleTest.php

-5
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Contracts\Config\Repository as ConfigRepository;
6+
use OpenTelemetry\API\Logs\LoggerInterface;
7+
use OpenTelemetry\API\Logs\LoggerProviderInterface;
8+
use OpenTelemetry\API\Logs\NoopLogger;
9+
use OpenTelemetry\API\Metrics\MeterInterface;
10+
use OpenTelemetry\API\Metrics\MeterProviderInterface;
11+
use OpenTelemetry\API\Metrics\Noop\NoopMeter;
12+
use OpenTelemetry\API\Trace\NoopTracer;
13+
use OpenTelemetry\API\Trace\TracerInterface;
14+
use OpenTelemetry\API\Trace\TracerProviderInterface;
15+
use OpenTelemetry\SDK\Logs\LoggerProviderInterface as LoggerProviderSdkInterface;
16+
use OpenTelemetry\SDK\Metrics\MeterProviderInterface as MeterProviderSdkInterface;
17+
use OpenTelemetry\SDK\Sdk;
18+
use OpenTelemetry\SDK\Trace\TracerProviderInterface as TracerProviderSdkInterface;
19+
20+
it('registers the default config', function () {
21+
/** @var ConfigRepository $config */
22+
$config = $this->app->get(ConfigRepository::class);
23+
24+
expect($config->get('telemetry'))
25+
->sdk->disabled->toBeFalse()
26+
->exporter->otlp->endpoint->toBe('http://localhost:4318');
27+
});
28+
29+
it('can update the config at runtime', function () {
30+
/** @var ConfigRepository $config */
31+
$config = $this->app->get(ConfigRepository::class);
32+
33+
expect(Sdk::isDisabled())->toBeFalse();
34+
35+
$config->set('telemetry.sdk.disabled', true);
36+
37+
expect(Sdk::isDisabled())->toBeTrue();
38+
});
39+
40+
it('registers the logger provider', function () {
41+
expect(
42+
$this->app->get(LoggerProviderInterface::class)
43+
)
44+
->toBeInstanceOf(LoggerProviderInterface::class)
45+
->toBeInstanceOf(LoggerProviderSdkInterface::class);
46+
});
47+
48+
it('registers the metric provider', function () {
49+
expect(
50+
$this->app->get(MeterProviderInterface::class)
51+
)
52+
->toBeInstanceOf(MeterProviderInterface::class)
53+
->toBeInstanceOf(MeterProviderSdkInterface::class);
54+
});
55+
56+
it('registers the tracer provider', function () {
57+
expect(
58+
$this->app->get(TracerProviderInterface::class)
59+
)
60+
->toBeInstanceOf(TracerProviderInterface::class)
61+
->toBeInstanceOf(TracerProviderSdkInterface::class);
62+
});
63+
64+
it('can get a logger from the logger provider', function () {
65+
expect(
66+
$this->app->get(LoggerProviderInterface::class)->getLogger('test')
67+
)
68+
->toBeInstanceOf(LoggerInterface::class);
69+
});
70+
71+
it('can get a meter from the meter provider', function () {
72+
expect(
73+
$this->app->get(MeterProviderInterface::class)->getMeter('test')
74+
)
75+
->toBeInstanceOf(MeterInterface::class);
76+
});
77+
78+
it('can get a tracer from the tracer provider', function () {
79+
expect(
80+
$this->app->get(TracerProviderInterface::class)->getTracer('test')
81+
)
82+
->toBeInstanceOf(TracerInterface::class);
83+
});
84+
85+
it('returns no-op instances when the SDK is disabled', function () {
86+
/** @var ConfigRepository $config */
87+
$config = $this->app->get(ConfigRepository::class);
88+
89+
$config->set('telemetry.sdk.disabled', true);
90+
91+
expect(
92+
$this->app->get(LoggerProviderInterface::class)->getLogger('test')
93+
)
94+
->toBeInstanceOf(NoopLogger::class);
95+
96+
expect(
97+
$this->app->get(MeterProviderInterface::class)->getMeter('test')
98+
)
99+
->toBeInstanceOf(NoopMeter::class);
100+
101+
expect(
102+
$this->app->get(TracerProviderInterface::class)->getTracer('test')
103+
)
104+
->toBeInstanceOf(NoopTracer::class);
105+
});

tests/Pest.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
use Worksome\LaravelTelemetry\Tests\TestCase;
46

5-
uses(TestCase::class)->in(__DIR__);
7+
uses(TestCase::class)->in('Feature');

0 commit comments

Comments
 (0)