Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: Configuration\CompositeResolver and SPI discovery #1523

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@
},
"require-dev": {
"ext-grpc": "*",
"grpc/grpc": "^1.30",
"bamarni/composer-bin-plugin": "^1.8",
"dg/bypass-finals": "^1.4",
"grpc/grpc": "^1.30",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort package config re-ordered this.

"guzzlehttp/guzzle": "^7.4",
"guzzlehttp/psr7": "^2.1",
"mikey179/vfsstream": "^1.6.11",
Expand Down Expand Up @@ -176,6 +176,13 @@
],
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\Instrumentation": [
"OpenTelemetry\\Example\\ExampleInstrumentation"
],
"OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\ResolverInterface": [
"OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\SdkConfigurationResolver"
],
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\EnvSourceProvider": [
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\Adapter\\SymfonyDotenvProvider",
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\Adapter\\VlucasPhpdotenvProvider"
]
}
}
Expand Down
11 changes: 9 additions & 2 deletions deptrac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,14 @@ deptrac:
regex: ^Ramsey\\Uuid\\*
- name: NyholmPsr7Server
collectors:
- type: className
regex: ^Nyholm\\Psr7Server\\*
- type: className
regex: ^Nyholm\\Psr7Server\\*
- name: DotenvProvider
collectors:
- type: className
regex: ^Symfony\\Component\\Dotenv\\*
- type: className
regex: ^Dotenv\\*

ruleset:
Context:
Expand All @@ -124,6 +130,7 @@ deptrac:
- Context
- Contrib
- Extension
- DotenvProvider
API:
- Context
- PsrLog
Expand Down
17 changes: 16 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,19 @@ parameters:
-
message: "#.*return with type T is not subtype.*#"
paths:
- src/SDK/Common/InstrumentationScope
- src/SDK/Common/InstrumentationScope

-
message: "#^Call to (static )?method .* on an unknown class .*#"
paths:
- src/Config/SDK/Configuration/Environment/Adapter/

-
message: "#^Instantiated class .* not found\\.#"
paths:
- src/Config/SDK/Configuration/Environment/Adapter/

-
message: "#^Caught class .* not found\\.#"
paths:
- src/Config/SDK/Configuration/Environment/Adapter/
22 changes: 14 additions & 8 deletions src/Config/SDK/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
use OpenTelemetry\Config\SDK\Configuration\ComponentProvider;
use OpenTelemetry\Config\SDK\Configuration\ConfigurationFactory;
use OpenTelemetry\Config\SDK\Configuration\Context;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvReader;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceReader;
use OpenTelemetry\Config\SDK\Configuration\Environment\PhpIniEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\ServerEnvSource;
use OpenTelemetry\SDK\SdkBuilder;
use WeakMap;

final class Configuration
{
Expand All @@ -37,24 +39,28 @@ public static function parseFile(
string|array $file,
?string $cacheFile = null,
bool $debug = true,
?EnvReader $envReader = null,
): Configuration {
return new self(self::factory()->parseFile($file, $cacheFile, $debug));
return new self(self::factory($envReader)->parseFile($file, $cacheFile, $debug));
}

/**
* @return ConfigurationFactory<SdkBuilder>
*/
private static function factory(): ConfigurationFactory
private static function factory(?EnvReader $envReader): ConfigurationFactory
{
static $factory;
static $defaultEnvReader;
static $factories = new WeakMap();

return $factory ??= new ConfigurationFactory(
$envReader ??= $defaultEnvReader ??= new EnvSourceReader([
new ServerEnvSource(),
new PhpIniEnvSource(),
]);

return $factories[$envReader] ??= new ConfigurationFactory(
ServiceLoader::load(ComponentProvider::class),
new OpenTelemetrySdk(),
new EnvSourceReader([
new ServerEnvSource(),
new PhpIniEnvSource(),
]),
$envReader,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\Configuration\Environment\Adapter;

use function array_diff_key;
use Composer\InstalledVersions;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Config\SDK\Configuration\Environment\ArrayEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceProvider;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Dotenv\Exception\PathException;

#[PackageDependency('symfony/dotenv', '^5.4 || ^6.4 || ^7.0')]
final class SymfonyDotenvProvider implements EnvSourceProvider
{
/** @psalm-suppress UndefinedClass */
public function getEnvSource(): EnvSource
{
$installPath = InstalledVersions::getRootPackage()['install_path'];

$backup = [$_SERVER, $_ENV];
$env = [];

try {
(new Dotenv())->bootEnv($installPath . '/.env');
$env = $_SERVER;
} catch (PathException) {
} finally {
[$_SERVER, $_ENV] = $backup;
}

return new ArrayEnvSource(array_diff_key($env, $_SERVER));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\Configuration\Environment\Adapter;

use Composer\InstalledVersions;
use Dotenv\Dotenv;
use Dotenv\Exception\InvalidPathException;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Config\SDK\Configuration\Environment\ArrayEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceProvider;

#[PackageDependency('vlucas/phpdotenv', '^4.0 || ^5.0')]
final class VlucasPhpdotenvProvider implements EnvSourceProvider
{
/** @psalm-suppress UndefinedClass */
public function getEnvSource(): EnvSource
{
$backup = [$_SERVER, $_ENV];
$env = [];

try {
$env = Dotenv::createImmutable([InstalledVersions::getRootPackage()['install_path']])->load();
} catch (InvalidPathException) {
} finally {
[$_SERVER, $_ENV] = $backup;
}

return new ArrayEnvSource(array_diff_key($env, $_SERVER));
}
}
10 changes: 10 additions & 0 deletions src/Config/SDK/Configuration/Environment/EnvSourceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\Configuration\Environment;

interface EnvSourceProvider
{
public function getEnvSource(): EnvSource;
}
27 changes: 27 additions & 0 deletions src/Config/SDK/Configuration/Environment/LazyEnvSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\Configuration\Environment;

use Closure;

final class LazyEnvSource implements EnvSource
{
/**
* @param Closure(): EnvSource|EnvSource $env
*/
public function __construct(
private Closure|EnvSource $env,
) {
}

public function readRaw(string $name): mixed
{
if (!$this->env instanceof EnvSource) {
$this->env = ($this->env)();
}

return $this->env->readRaw($name);
}
}
22 changes: 14 additions & 8 deletions src/Config/SDK/Instrumentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
use OpenTelemetry\Config\SDK\Configuration\ComponentProvider;
use OpenTelemetry\Config\SDK\Configuration\ConfigurationFactory;
use OpenTelemetry\Config\SDK\Configuration\Context;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvReader;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceReader;
use OpenTelemetry\Config\SDK\Configuration\Environment\PhpIniEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\ServerEnvSource;
use WeakMap;

final class Instrumentation
{
Expand All @@ -39,24 +41,28 @@ public static function parseFile(
string|array $file,
?string $cacheFile = null,
bool $debug = true,
?EnvReader $envReader = null,
): Instrumentation {
return new self(self::factory()->parseFile($file, $cacheFile, $debug));
return new self(self::factory($envReader)->parseFile($file, $cacheFile, $debug));
}

/**
* @return ConfigurationFactory<ConfigurationRegistry>
*/
private static function factory(): ConfigurationFactory
private static function factory(?EnvReader $envReader): ConfigurationFactory
{
static $factory;
static $defaultEnvReader;
static $factories = new WeakMap();

return $factory ??= new ConfigurationFactory(
$envReader ??= $defaultEnvReader ??= new EnvSourceReader([
new ServerEnvSource(),
new PhpIniEnvSource(),
]);

return $factories[$envReader] ??= new ConfigurationFactory(
ServiceLoader::load(ComponentProvider::class),
new InstrumentationConfigurationRegistry(),
new EnvSourceReader([
new ServerEnvSource(),
new PhpIniEnvSource(),
]),
$envReader,
);
}
}
4 changes: 4 additions & 0 deletions src/Config/SDK/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@

"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Instrumentation\\General\\HttpConfigProvider",
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Instrumentation\\General\\PeerConfigProvider"
],
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\EnvSourceProvider": [
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\Adapter\\SymfonyDotenvProvider",
"OpenTelemetry\\Config\\SDK\\Configuration\\Environment\\Adapter\\VlucasPhpdotenvProvider"
]
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/SDK/Common/Configuration/Resolver/CompositeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace OpenTelemetry\SDK\Common\Configuration\Resolver;

use Nevay\SPI\ServiceLoader;
use OpenTelemetry\SDK\Common\Configuration\Configuration;

/**
Expand All @@ -18,6 +19,7 @@ public static function instance(): self
{
static $instance;
$instance ??= new self([
...ServiceLoader::load(ResolverInterface::class),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This effectively replaces the below resolvers because it will use the ServerEnvSource & PhpIniEnvSource sources.

--

Should open-telemetry/sdk-configuration be promoted to the SDK rather than remain as an optional dependency? 🤔

new EnvironmentResolver(),
new PhpIniResolver(),
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\SDK\Common\Configuration\Resolver;

use Nevay\SPI\ServiceLoader;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceProvider;
use OpenTelemetry\Config\SDK\Configuration\Environment\EnvSourceReader;
use OpenTelemetry\Config\SDK\Configuration\Environment\LazyEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\PhpIniEnvSource;
use OpenTelemetry\Config\SDK\Configuration\Environment\ServerEnvSource;
use OpenTelemetry\SDK\Common\Configuration\Configuration;

/**
* @internal
*/
#[PackageDependency('open-telemetry/sdk-configuration', '*')]
class SdkConfigurationResolver implements ResolverInterface
{
private readonly EnvSourceReader $reader;

public function __construct()
{
$envSources = [];
$envSources[] = new ServerEnvSource();
$envSources[] = new PhpIniEnvSource();

/** @var EnvSourceProvider $envSourceProvider */
foreach (ServiceLoader::load(EnvSourceProvider::class) as $envSourceProvider) {
$envSources[] = new LazyEnvSource($envSourceProvider->getEnvSource(...));
}

$this->reader = new EnvSourceReader($envSources);
}

public function retrieveValue(string $variableName)
{
return $this->reader->read($variableName);
}

public function hasVariable(string $variableName): bool
{
return !Configuration::isEmpty($this->reader->read($variableName));
}
}
3 changes: 3 additions & 0 deletions src/SDK/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
"spi": {
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\HookManagerInterface": [
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\ExtensionHookManager"
],
"OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\ResolverInterface": [
"OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\SdkConfigurationResolver"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only kicks in when open-telemetry/sdk-configuration is available.

]
}
}
Expand Down
Loading