OpenTelemetry Sampling [PHP]

What is sampling?

Sampling is a process that restricts the amount of traces that are generated by a system. In high-volume applications, collecting 100% of traces can be expensive and unnecessary. Sampling allows you to collect a representative subset of traces while reducing costs and performance overhead.

PHP sampling

OpenTelemetry PHP SDK provides head-based sampling capabilities where the sampling decision is made at the beginning of a trace. By default, the tracer provider uses a ParentBased sampler with the AlwaysOnSampler. A sampler can be set on the tracer provider when creating it.

Built-in samplers

AlwaysOnSampler

Samples every trace. Useful for development environments but be careful in production with significant traffic:

php
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;

$tracerProvider = new TracerProvider(
    sampler: new AlwaysOnSampler()
);

AlwaysOffSampler

Samples no traces. Useful for completely disabling tracing:

php
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler;

$tracerProvider = new TracerProvider(
    sampler: new AlwaysOffSampler()
);

TraceIdRatioBased

Samples a fraction of spans based on the trace ID. The fraction should be between 0.0 and 1.0:

php
use OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBased;

// Sample 10% of traces
$tracerProvider = new TracerProvider(
    sampler: new TraceIdRatioBased(0.1)
);

// Sample 50% of traces
$tracerProvider = new TracerProvider(
    sampler: new TraceIdRatioBased(0.5)
);

ParentBased

A sampler decorator that behaves differently based on the parent of the span. If the span has no parent, the decorated sampler is used to make the sampling decision:

php
use OpenTelemetry\SDK\Trace\Sampler\ParentBased;
use OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBased;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;

// ParentBased with TraceIdRatioBased root sampler
$tracerProvider = new TracerProvider(
    sampler: new ParentBased(new TraceIdRatioBased(0.1))
);

// ParentBased with AlwaysOnSampler root sampler (default behavior)
$tracerProvider = new TracerProvider(
    sampler: new ParentBased(new AlwaysOnSampler())
);

Configuration in PHP

Environment variables

You can configure sampling using environment variables:

bash
# TraceIdRatio sampler with 50% sampling
export OTEL_TRACES_SAMPLER="traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.5"

# ParentBased with TraceIdRatio
export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.1"

# Always sample
export OTEL_TRACES_SAMPLER="always_on"

# Never sample
export OTEL_TRACES_SAMPLER="always_off"

Programmatic configuration

php
<?php

use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\Sampler\ParentBased;
use OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBased;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SemConv\ResourceAttributes;

function setupTracing(): TracerProvider
{
    // Create OTLP exporter
    $transport = (new OtlpHttpTransportFactory())->create(
        'https://api.uptrace.dev:4318/v1/traces',
        'application/json',
        ['uptrace-dsn' => $_ENV['UPTRACE_DSN']]
    );
    $exporter = new SpanExporter($transport);

    // Create resource
    $resource = ResourceInfo::create(Attributes::create([
        ResourceAttributes::SERVICE_NAME => 'my-service',
        ResourceAttributes::SERVICE_VERSION => '1.0.0',
    ]));

    // Configure sampler based on environment
    $env = $_ENV['APP_ENV'] ?? 'development';
    $sampler = match ($env) {
        'development' => new AlwaysOnSampler(),
        'production' => new ParentBased(new TraceIdRatioBased(0.1)), // 10% sampling
        default => new ParentBased(new TraceIdRatioBased(0.25)), // 25% sampling
    };

    // Create tracer provider with correct parameter order
    return new TracerProvider(
        spanProcessors: [new BatchSpanProcessor($exporter)],
        sampler: $sampler,
        resource: $resource
    );
}

What's next?