Skip to content

Conversation

@cedricziel
Copy link
Contributor

@cedricziel cedricziel commented Jan 22, 2026

Summary

Add ability to register custom sampler factories via the Registry, allowing users to extend the SDK with custom sampling strategies.

Packages can now call registerSamplerFactory to register a factory for their custom, named sampler.

SDK will now register its own samplers via autoloading as well:

\OpenTelemetry\SDK\Registry::registerSamplerFactory('always_on', \OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSamplerFactory::class);
\OpenTelemetry\SDK\Registry::registerSamplerFactory('always_off', \OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSamplerFactory::class);
\OpenTelemetry\SDK\Registry::registerSamplerFactory('traceidratio', \OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBasedSamplerFactory::class);
\OpenTelemetry\SDK\Registry::registerSamplerFactory('parentbased_always_on', \OpenTelemetry\SDK\Trace\Sampler\ParentBasedAlwaysOnSamplerFactory::class);
\OpenTelemetry\SDK\Registry::registerSamplerFactory('parentbased_always_off', \OpenTelemetry\SDK\Trace\Sampler\ParentBasedAlwaysOffSamplerFactory::class);
\OpenTelemetry\SDK\Registry::registerSamplerFactory('parentbased_traceidratio', \OpenTelemetry\SDK\Trace\Sampler\ParentBasedTraceIdRatioSamplerFactory::class);

Changes

Implementation

  • SamplerFactoryInterface - Contract for sampler factories
  • AlwaysOnSamplerFactory, AlwaysOffSamplerFactory - Simple sampler factories
  • TraceIdRatioBasedSamplerFactory - Ratio-based sampler factory (reads from env)
  • ParentBasedAlwaysOnSamplerFactory, ParentBasedAlwaysOffSamplerFactory, ParentBasedTraceIdRatioSamplerFactory - Parent-based variants
  • Registry::registerSamplerFactory() and Registry::samplerFactory() - Registry methods
  • _register.php - Auto-registers built-in sampler factories
  • Refactored SamplerFactory to use the registry instead of hardcoded logic

@cedricziel cedricziel requested a review from a team as a code owner January 22, 2026 07:23
@codecov
Copy link

codecov bot commented Jan 22, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.10%. Comparing base (6957241) to head (8609391).

Files with missing lines Patch % Lines
src/SDK/Trace/Sampler/_register.php 0.00% 6 Missing ⚠️
src/SDK/Registry.php 94.44% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main    #1867      +/-   ##
============================================
+ Coverage     68.03%   68.10%   +0.06%     
- Complexity     3012     3019       +7     
============================================
  Files           453      460       +7     
  Lines          8819     8850      +31     
============================================
+ Hits           6000     6027      +27     
- Misses         2819     2823       +4     
Flag Coverage Δ
8.1 67.77% <83.33%> (?)
8.2 67.98% <83.33%> (+0.04%) ⬆️
8.3 68.00% <83.33%> (+0.04%) ⬆️
8.4 68.01% <83.33%> (+0.03%) ⬆️
8.5 67.17% <83.33%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/SDK/Trace/Sampler/AlwaysOffSamplerFactory.php 100.00% <100.00%> (ø)
src/SDK/Trace/Sampler/AlwaysOnSamplerFactory.php 100.00% <100.00%> (ø)
...ace/Sampler/ParentBasedAlwaysOffSamplerFactory.php 100.00% <100.00%> (ø)
...race/Sampler/ParentBasedAlwaysOnSamplerFactory.php 100.00% <100.00%> (ø)
.../Sampler/ParentBasedTraceIdRatioSamplerFactory.php 100.00% <100.00%> (ø)
.../Trace/Sampler/TraceIdRatioBasedSamplerFactory.php 100.00% <100.00%> (ø)
src/SDK/Trace/SamplerFactory.php 100.00% <100.00%> (ø)
src/SDK/Registry.php 73.04% <94.44%> (+3.97%) ⬆️
src/SDK/Trace/Sampler/_register.php 0.00% <0.00%> (ø)

... and 4 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 data
Powered by Codecov. Last update 6957241...8609391. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cedricziel cedricziel force-pushed the feature/custom-sampler-registry-tests branch 4 times, most recently from 1e9d1f7 to fd15d7f Compare January 22, 2026 07:48
Add ability to register custom sampler factories via the Registry,
allowing users to extend the SDK with custom sampling strategies.

Implementation:
- Add SamplerFactoryInterface for sampler factory contracts
- Add factory classes for all built-in samplers (AlwaysOn, AlwaysOff,
  TraceIdRatioBased, ParentBased variants)
- Add Registry::registerSamplerFactory() and Registry::samplerFactory()
- Refactor SamplerFactory to use the registry instead of hardcoded logic
- Add _register.php to auto-register built-in sampler factories

Tests:
- Add unit tests for all sampler factory classes
- Add registry tests for sampler factory registration
- Add tests for custom sampler registration with clobber behavior
@cedricziel cedricziel force-pushed the feature/custom-sampler-registry-tests branch from fd15d7f to 82be09b Compare January 22, 2026 07:56
Add reportUnmatchedIgnoredErrors: false to PHPStan config to prevent
failures when ignore patterns for PHP 8.1-specific Symfony Config
errors don't match on newer PHP versions.
Add tests/Integration/Config and tests/Unit/Config to the ignore paths
for Symfony Config NodeParentInterface errors on PHP 8.1.
#[\Override]
public function create(): SamplerInterface
{
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG);
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG, 1.);

#[\Override]
public function create(): SamplerInterface
{
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG);
$ratio = Configuration::getRatio(Variables::OTEL_TRACES_SAMPLER_ARG, 1.);


use OpenTelemetry\SDK\Trace\SamplerInterface;

interface SamplerFactoryInterface
Copy link
Contributor

@Nevay Nevay Jan 22, 2026

Choose a reason for hiding this comment

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

I would prefer if we use EnvComponentLoader instead of adding another {type}Factory to work towards #1681 / to align with file-based config ComponentProviders.

If we want to start with just samplers:

class SamplerFactory
{
    public function create(): SamplerInterface
    {
        $registry = new EnvComponentLoaderRegistry();
        foreach (ServiceLoader::load(EnvComponentLoader::class) as $loader) {
            $registry->register($loader);
        }

        $env = new EnvResolver();
        $context = new Context();

        $samplerName = $env->string(Variables::OTEL_TRACES_SAMPLER) ?? Defaults::OTEL_TRACES_SAMPLER;

        return $registry->load(SamplerInterface::class, $samplerName, $env, $context);
    }
}
/**
 * @implements EnvComponentLoader<SamplerInterface>
 */
final class SamplerLoaderTraceIdRatioBased implements EnvComponentLoader
{
    #[\Override]
    public function load(EnvResolver $env, EnvComponentLoaderRegistry $registry, Context $context): SamplerInterface
    {
        return new TraceIdRatioBasedSampler($env->numeric(Variables::OTEL_TRACES_SAMPLER_ARG, max: 1) ?? 1.);
    }

    #[\Override]
    public function name(): string
    {
        return 'traceidratio';
    }
}
# _register.php
ServiceLoader::register(EnvComponentLoader::class, SamplerLoaderTraceIdRatioBased::class);
// ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants