prototype: generate registry from composer autoload-dump
To resolve our long-standing race conditions stemming from using composer's autoload->files to register SDK components at runtime, this changes things so that:
- components can be registered in various composer.json files, under
extra.spi - the SDK Registry is modified to make manually registering components a no-op (currently behind a flag, OTEL_PHP_EXPERIMENTAL_SPI_REGISTRY), and instead configure itself via SPI's ServiceLoader
If we move ahead with this approach, a follow-up PR could tidy up the Registry and remove our various late-binding providers.
todo:
- [ ] add config to appropriate composer.json files (currently only in root composer.json)
Deploy Preview for opentelemetry-php canceled.
| Name | Link |
|---|---|
| Latest commit | 5ffe83be2c000d079eb1afe1e7381b315dd779f9 |
| Latest deploy log | https://app.netlify.com/sites/opentelemetry-php/deploys/671f1d38fe1753000839d348 |
Codecov Report
Attention: Patch coverage is 44.97817% with 126 lines in your changes missing coverage. Please review.
Project coverage is 72.07%. Comparing base (
a19455c) to head (67891d0). Report is 40 commits behind head on 2.x.
Additional details and impacted files
@@ Coverage Diff @@
## 2.x #1412 +/- ##
============================================
- Coverage 72.31% 72.07% -0.24%
- Complexity 2729 2758 +29
============================================
Files 401 405 +4
Lines 8148 8200 +52
============================================
+ Hits 5892 5910 +18
- Misses 2256 2290 +34
| Flag | Coverage Δ | |
|---|---|---|
| 8.2 | 71.91% <44.97%> (-0.22%) |
:arrow_down: |
| 8.3 | 71.87% <44.97%> (-0.26%) |
:arrow_down: |
| 8.4 | 71.89% <44.97%> (-0.38%) |
:arrow_down: |
| 8.5 | 71.98% <44.97%> (-0.21%) |
:arrow_down: |
Flags with carried forward coverage won't be shown. Click here to find out more.
| Files with missing lines | Coverage Δ | |
|---|---|---|
| ...entProvider/Propagator/TextMapPropagatorJaeger.php | 0.00% <ø> (ø) |
|
| src/Contrib/Grpc/GrpcTransportFactory.php | 73.17% <100.00%> (+1.37%) |
:arrow_up: |
| src/Contrib/Otlp/LogsExporterFactory.php | 97.61% <100.00%> (+0.18%) |
:arrow_up: |
| src/Contrib/Otlp/MetricExporterFactory.php | 98.03% <100.00%> (+0.12%) |
:arrow_up: |
| src/Contrib/Otlp/SpanExporterFactory.php | 97.50% <100.00%> (+0.20%) |
:arrow_up: |
| src/SDK/Common/Export/Http/PsrTransportFactory.php | 81.25% <100.00%> (+2.67%) |
:arrow_up: |
| src/SDK/Common/Export/Http/PsrUtils.php | 92.64% <100.00%> (ø) |
|
| ...DK/Common/Export/Stream/StreamTransportFactory.php | 91.11% <100.00%> (+0.86%) |
:arrow_up: |
| src/SDK/Common/Services/Loader.php | 100.00% <100.00%> (ø) |
|
| src/SDK/Logs/Exporter/ConsoleExporterFactory.php | 100.00% <100.00%> (ø) |
|
| ... and 36 more |
... and 14 files with indirect coverage changes
Continue to review full report in Codecov by Sentry.
Legend - Click here to learn more
Δ = absolute <relative> (impact),ø = not affected,? = missing dataPowered by Codecov. Last update a19455c...67891d0. Read the comment docs.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
An alternative idea if we want to avoid duplicating the "load implementations from composer.json" approach:
The main difference between the solution in this PR and an SPI-based approach is the addition of a name/key for each implementation within the composer.json configuration. This information could instead be added as additional method in the interfaces[^1] to allow loading them using SPI.
[^1]: See also Java ServiceLoader - Designing Services: > A service should declare as many methods as needed to allow service providers to communicate their domain-specific properties and other quality-of-implementation factors. An application which obtains a service loader for the service may then invoke these methods on each instance of a service provider, in order to choose the best provider for the application.
Registry is currently used for two different types of implementations:
- factories used to initialize the SDK from environment variables
- transport factory implementations, which are also used outside of environment variables configuration
Transport factory implementations
We can extend TransportFactoryInterface with the necessary information to populate the transport factories:
$factories = iterator_to_array(ServiceLoader::load(TransportFactoryServiceInterface::class));
array_multisort(
array_map(static fn($factory) => $factory->priority(), $factories),
SORT_DESC,
$factories,
);
$factoriesByProtocol = [];
foreach ($factories as $factory) {
$factoriesByProtocol[$factory->protocol()] ??= $factory;
}
self::$transportFactories = $factoriesByProtocol;
interface TransportFactoryServiceInterface extends TransportFactoryInterface {
public function protocol(): string;
public function priority(): int;
}
Factories to initialize the SDK from environment variables
We could align the implementation with the file-based implementation by adding a new, from the current implementation independent interface[^2] similar to Configuration\ComponentProvider and deprecate the current registry methods and factory interfaces.
Very basic interface definition:
namespace OpenTelemetry\Config\SDK\Environment;
/**
* @template T
*/
interface ComponentProvider {
/**
* @return T
*/
public function createPlugin(): mixed;
public function name(): string;
}
Alternatively we could follow the approach mentioned for transport factory implementations and add a name(/priority) method to the factory interfaces and continue using the Registry.
[^2]: FWIW I've been using the following Env\Loader interface for env-based configuration, its implementations are loaded via SPI:
```php
/**
* @template T
*/
interface Loader {
/**
* @return T
*/
public function load(EnvResolver $env, LoaderRegistry $registry, Context $context): mixed;
public function name(): string;
}
```
updated to use SPI, and implemented the idea of having factories declare their key & priority.
- [ ] The Vneno i
I understand that the Registry stuff will not be used when using extra.spi. Is it correct that third-party libraries (in my case, proprietary code/packages within a company) can also add their instrumentation through the SPI way, as shown in composer.json?
@xvilo That's right. It's still up for debate exactly how registry/SPI should interact, and which one would be the default. The SPI mechanism will definitely allow custom components like we have now.
@open-telemetry/php-approvers @Nevay I think this is ready for review: NB that it targets 2.x branch and has some BC breakage, which I've started to document in docs/upgrading.md
@open-telemetry/php-approvers this is ready for another review. I think all feedback from Nevay addressed and OK'd.