Add Sampler configuration factory (#5763)
This commit is contained in:
parent
604bdbd92a
commit
3a709a7059
|
|
@ -33,6 +33,7 @@ dependencies {
|
|||
testImplementation(project(":sdk:testing"))
|
||||
testImplementation(project(":sdk-extensions:autoconfigure"))
|
||||
testImplementation(project(":exporters:otlp:all"))
|
||||
testImplementation(project(":sdk-extensions:jaeger-remote-sampler"))
|
||||
testImplementation(project(":extensions:trace-propagators"))
|
||||
// As a part of the tests we check that we can parse examples without error. The https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yam contains a reference to the xray propagator
|
||||
testImplementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ final class FileConfigUtil {
|
|||
private FileConfigUtil() {}
|
||||
|
||||
/** Add the {@code closeable} to the {@code closeables} and return it. */
|
||||
static <T extends Closeable> T addAndReturn(List<Closeable> closeables, T closeable) {
|
||||
closeables.add(closeable);
|
||||
static <T> T addAndReturn(List<Closeable> closeables, T closeable) {
|
||||
if (closeable instanceof Closeable) {
|
||||
closeables.add((Closeable) closeable);
|
||||
}
|
||||
return closeable;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,6 @@ final class OpenTelemetryConfigurationFactory
|
|||
}
|
||||
|
||||
// TODO(jack-berg): add support for meter provider
|
||||
// TODO(jack-berg): add support for propagators
|
||||
// TODO(jack-berg): add support for resource
|
||||
// TODO(jack-berg): add support for general attribute limits
|
||||
|
||||
return FileConfigUtil.addAndReturn(closeables, builder.build());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.NamedSpiManager;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.JaegerRemote;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBased;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBased;
|
||||
import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder;
|
||||
import io.opentelemetry.sdk.trace.samplers.Sampler;
|
||||
import java.io.Closeable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class SamplerFactory
|
||||
implements Factory<
|
||||
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Sampler, Sampler> {
|
||||
|
||||
private static final SamplerFactory INSTANCE = new SamplerFactory();
|
||||
|
||||
private SamplerFactory() {}
|
||||
|
||||
static SamplerFactory getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sampler create(
|
||||
@Nullable io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Sampler model,
|
||||
SpiHelper spiHelper,
|
||||
List<Closeable> closeables) {
|
||||
if (model == null) {
|
||||
return Sampler.parentBased(Sampler.alwaysOn());
|
||||
}
|
||||
|
||||
if (model.getAlwaysOn() != null) {
|
||||
return Sampler.alwaysOn();
|
||||
}
|
||||
if (model.getAlwaysOff() != null) {
|
||||
return Sampler.alwaysOff();
|
||||
}
|
||||
TraceIdRatioBased traceIdRatioBasedModel = model.getTraceIdRatioBased();
|
||||
if (traceIdRatioBasedModel != null) {
|
||||
Double ratio = traceIdRatioBasedModel.getRatio();
|
||||
if (ratio == null) {
|
||||
ratio = 1.0d;
|
||||
}
|
||||
return Sampler.traceIdRatioBased(ratio);
|
||||
}
|
||||
ParentBased parentBasedModel = model.getParentBased();
|
||||
if (parentBasedModel != null) {
|
||||
Sampler root =
|
||||
parentBasedModel.getRoot() == null
|
||||
? Sampler.alwaysOn()
|
||||
: create(parentBasedModel.getRoot(), spiHelper, closeables);
|
||||
ParentBasedSamplerBuilder builder = Sampler.parentBasedBuilder(root);
|
||||
if (parentBasedModel.getRemoteParentSampled() != null) {
|
||||
builder.setRemoteParentSampled(
|
||||
create(parentBasedModel.getRemoteParentSampled(), spiHelper, closeables));
|
||||
}
|
||||
if (parentBasedModel.getRemoteParentNotSampled() != null) {
|
||||
builder.setRemoteParentNotSampled(
|
||||
create(parentBasedModel.getRemoteParentNotSampled(), spiHelper, closeables));
|
||||
}
|
||||
if (parentBasedModel.getLocalParentSampled() != null) {
|
||||
builder.setLocalParentSampled(
|
||||
create(parentBasedModel.getLocalParentSampled(), spiHelper, closeables));
|
||||
}
|
||||
if (parentBasedModel.getLocalParentNotSampled() != null) {
|
||||
builder.setLocalParentNotSampled(
|
||||
create(parentBasedModel.getLocalParentNotSampled(), spiHelper, closeables));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
JaegerRemote jaegerRemoteModel = model.getJaegerRemote();
|
||||
if (jaegerRemoteModel != null) {
|
||||
// Translate from file configuration scheme to environment variable scheme. This is ultimately
|
||||
// interpreted by JaegerRemoteSamplerProvider, but we want to avoid the dependency on
|
||||
// opentelemetry-sdk-extension-jaeger-remote-sampler
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
if (jaegerRemoteModel.getEndpoint() != null) {
|
||||
properties.put("endpoint", jaegerRemoteModel.getEndpoint());
|
||||
}
|
||||
if (jaegerRemoteModel.getInterval() != null) {
|
||||
properties.put("pollingInterval", String.valueOf(jaegerRemoteModel.getInterval()));
|
||||
}
|
||||
// TODO(jack-berg): determine how to support initial sampler. This is first case where a
|
||||
// component configured via SPI has property that isn't available in the environment variable
|
||||
// scheme.
|
||||
String otelTraceSamplerArg =
|
||||
properties.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + "=" + entry.getValue())
|
||||
.collect(joining(","));
|
||||
|
||||
// TODO(jack-berg): add method for creating from map
|
||||
ConfigProperties configProperties =
|
||||
DefaultConfigProperties.createForTest(
|
||||
Collections.singletonMap("otel.traces.sampler.arg", otelTraceSamplerArg));
|
||||
|
||||
return FileConfigUtil.addAndReturn(
|
||||
closeables,
|
||||
FileConfigUtil.assertNotNull(
|
||||
samplerSpiManager(configProperties, spiHelper).getByName("jaeger_remote"),
|
||||
"jaeger remote sampler"));
|
||||
}
|
||||
|
||||
// TODO(jack-berg): add support for generic SPI samplers
|
||||
if (!model.getAdditionalProperties().isEmpty()) {
|
||||
throw new ConfigurationException(
|
||||
"Unrecognized sampler(s): "
|
||||
+ model.getAdditionalProperties().keySet().stream().collect(joining(",", "[", "]")));
|
||||
}
|
||||
|
||||
return Sampler.parentBased(Sampler.alwaysOn());
|
||||
}
|
||||
|
||||
private static NamedSpiManager<Sampler> samplerSpiManager(
|
||||
ConfigProperties config, SpiHelper spiHelper) {
|
||||
return spiHelper.loadConfigurable(
|
||||
ConfigurableSamplerProvider.class,
|
||||
ConfigurableSamplerProvider::getName,
|
||||
ConfigurableSamplerProvider::createSampler,
|
||||
config);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Tracer
|
|||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
|
||||
import io.opentelemetry.sdk.trace.SpanLimits;
|
||||
import io.opentelemetry.sdk.trace.samplers.Sampler;
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -38,6 +39,10 @@ final class TracerProviderFactory implements Factory<TracerProvider, SdkTracerPr
|
|||
SpanLimitsFactory.getInstance().create(model.getLimits(), spiHelper, closeables);
|
||||
builder.setSpanLimits(spanLimits);
|
||||
|
||||
Sampler sampler =
|
||||
SamplerFactory.getInstance().create(model.getSampler(), spiHelper, closeables);
|
||||
builder.setSampler(sampler);
|
||||
|
||||
List<SpanProcessor> processors = model.getProcessors();
|
||||
if (processors != null) {
|
||||
processors.forEach(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
|
||||
|
|
@ -21,6 +22,7 @@ import io.opentelemetry.internal.testing.CleanupExtension;
|
|||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOn;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Attributes;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessor;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessor;
|
||||
|
|
@ -31,6 +33,7 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Logger
|
|||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfiguration;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Otlp;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Resource;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Sampler;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporter;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessor;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProvider;
|
||||
|
|
@ -153,6 +156,7 @@ class OpenTelemetryConfigurationFactoryTest {
|
|||
.setMaxNumberOfAttributesPerEvent(5)
|
||||
.setMaxNumberOfAttributesPerLink(6)
|
||||
.build())
|
||||
.setSampler(alwaysOn())
|
||||
.addSpanProcessor(
|
||||
io.opentelemetry.sdk.trace.export.BatchSpanProcessor.builder(
|
||||
OtlpGrpcSpanExporter.getDefault())
|
||||
|
|
@ -200,6 +204,7 @@ class OpenTelemetryConfigurationFactoryTest {
|
|||
.withLinkCountLimit(4)
|
||||
.withEventAttributeCountLimit(5)
|
||||
.withLinkAttributeCountLimit(6))
|
||||
.withSampler(new Sampler().withAlwaysOn(new AlwaysOn()))
|
||||
.withProcessors(
|
||||
Collections.singletonList(
|
||||
new SpanProcessor()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.internal.testing.CleanupExtension;
|
||||
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOff;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOn;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.JaegerRemote;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBased;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Sampler;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBased;
|
||||
import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler;
|
||||
import java.io.Closeable;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
// Suppress logs from JaegerRemoteSampler
|
||||
@SuppressLogger(
|
||||
loggerName = "io.opentelemetry.sdk.extension.trace.jaeger.sampler.OkHttpGrpcService")
|
||||
class SamplerFactoryTest {
|
||||
|
||||
@RegisterExtension CleanupExtension cleanup = new CleanupExtension();
|
||||
|
||||
private final SpiHelper spiHelper = SpiHelper.create(SamplerFactoryTest.class.getClassLoader());
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("createArguments")
|
||||
void create(
|
||||
@Nullable Sampler model, io.opentelemetry.sdk.trace.samplers.Sampler expectedSampler) {
|
||||
// Some samplers like JaegerRemoteSampler are Closeable - ensure these get cleaned up
|
||||
if (expectedSampler instanceof Closeable) {
|
||||
cleanup.addCloseable((Closeable) expectedSampler);
|
||||
}
|
||||
|
||||
List<Closeable> closeables = new ArrayList<>();
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler sampler =
|
||||
SamplerFactory.getInstance().create(model, spiHelper, closeables);
|
||||
cleanup.addCloseables(closeables);
|
||||
|
||||
assertThat(sampler.toString()).isEqualTo(expectedSampler.toString());
|
||||
}
|
||||
|
||||
private static Stream<Arguments> createArguments() {
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
null,
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.parentBased(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn())),
|
||||
Arguments.of(
|
||||
new Sampler().withAlwaysOn(new AlwaysOn()),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn()),
|
||||
Arguments.of(
|
||||
new Sampler().withAlwaysOff(new AlwaysOff()),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOff()),
|
||||
Arguments.of(
|
||||
new Sampler().withTraceIdRatioBased(new TraceIdRatioBased()),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(1.0d)),
|
||||
Arguments.of(
|
||||
new Sampler().withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.5d)),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.5)),
|
||||
Arguments.of(
|
||||
new Sampler().withParentBased(new ParentBased()),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.parentBased(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn())),
|
||||
Arguments.of(
|
||||
new Sampler()
|
||||
.withParentBased(
|
||||
new ParentBased()
|
||||
.withRoot(
|
||||
new Sampler()
|
||||
.withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.1d)))
|
||||
.withRemoteParentSampled(
|
||||
new Sampler()
|
||||
.withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.2d)))
|
||||
.withRemoteParentNotSampled(
|
||||
new Sampler()
|
||||
.withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.3d)))
|
||||
.withLocalParentSampled(
|
||||
new Sampler()
|
||||
.withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.4d)))
|
||||
.withLocalParentNotSampled(
|
||||
new Sampler()
|
||||
.withTraceIdRatioBased(new TraceIdRatioBased().withRatio(0.5d)))),
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.parentBasedBuilder(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.1d))
|
||||
.setRemoteParentSampled(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.2d))
|
||||
.setRemoteParentNotSampled(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.3d))
|
||||
.setLocalParentSampled(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.4d))
|
||||
.setLocalParentNotSampled(
|
||||
io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(0.5d))
|
||||
.build()),
|
||||
Arguments.of(
|
||||
new Sampler()
|
||||
.withJaegerRemote(
|
||||
new JaegerRemote()
|
||||
.withEndpoint("http://jaeger-remote-endpoint")
|
||||
.withInterval(10_000)
|
||||
.withInitialSampler(new Sampler().withAlwaysOff(new AlwaysOff()))),
|
||||
JaegerRemoteSampler.builder()
|
||||
.setEndpoint("http://jaeger-remote-endpoint")
|
||||
.setPollingInterval(Duration.ofSeconds(10))
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_SpiExporter() {
|
||||
List<Closeable> closeables = new ArrayList<>();
|
||||
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
SamplerFactory.getInstance()
|
||||
.create(
|
||||
new Sampler()
|
||||
.withAdditionalProperty("test", ImmutableMap.of("key1", "value1")),
|
||||
spiHelper,
|
||||
new ArrayList<>()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessage("Unrecognized sampler(s): [test]");
|
||||
cleanup.addCloseables(closeables);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,12 +6,15 @@
|
|||
package io.opentelemetry.sdk.extension.incubator.fileconfig;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn;
|
||||
|
||||
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
|
||||
import io.opentelemetry.internal.testing.CleanupExtension;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOn;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessor;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Otlp;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Sampler;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporter;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessor;
|
||||
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProvider;
|
||||
|
|
@ -75,6 +78,7 @@ class TracerProviderFactoryTest {
|
|||
.setMaxNumberOfAttributesPerEvent(5)
|
||||
.setMaxNumberOfAttributesPerLink(6)
|
||||
.build())
|
||||
.setSampler(alwaysOn())
|
||||
.addSpanProcessor(
|
||||
io.opentelemetry.sdk.trace.export.BatchSpanProcessor.builder(
|
||||
OtlpGrpcSpanExporter.getDefault())
|
||||
|
|
@ -95,6 +99,7 @@ class TracerProviderFactoryTest {
|
|||
.withLinkCountLimit(4)
|
||||
.withEventAttributeCountLimit(5)
|
||||
.withLinkAttributeCountLimit(6))
|
||||
.withSampler(new Sampler().withAlwaysOn(new AlwaysOn()))
|
||||
.withProcessors(
|
||||
Collections.singletonList(
|
||||
new SpanProcessor()
|
||||
|
|
|
|||
Loading…
Reference in New Issue