Hide implementation of MultiSpanExporter/Processor behind interface. (#2091)
* Hide implementation of MultiSpanExporter behind interface. * spanprocessor too * composite * composite * Optimize composites based on number of items. * Spotless * IntelliJ + spotless race condition * Fix test
This commit is contained in:
parent
c0b53e9901
commit
d940947e53
|
|
@ -10,7 +10,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.common.export.ConfigBuilder;
|
||||
import io.opentelemetry.sdk.trace.MultiSpanProcessor;
|
||||
import io.opentelemetry.sdk.trace.ReadWriteSpan;
|
||||
import io.opentelemetry.sdk.trace.ReadableSpan;
|
||||
import io.opentelemetry.sdk.trace.SpanProcessor;
|
||||
|
|
@ -225,7 +224,7 @@ class DisruptorAsyncSpanProcessorTest {
|
|||
IncrementSpanProcessor incrementSpanProcessor2 = new IncrementSpanProcessor(REQUIRED, REQUIRED);
|
||||
DisruptorAsyncSpanProcessor disruptorAsyncSpanProcessor =
|
||||
DisruptorAsyncSpanProcessor.builder(
|
||||
MultiSpanProcessor.create(
|
||||
SpanProcessor.composite(
|
||||
Arrays.asList(incrementSpanProcessor1, incrementSpanProcessor2)))
|
||||
.build();
|
||||
disruptorAsyncSpanProcessor.onStart(Context.root(), readWriteSpan);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class MultiSpanExporterBenchmark {
|
|||
public final void setup() {
|
||||
SpanExporter[] exporter = new SpanExporter[exporterCount];
|
||||
Arrays.fill(exporter, new NoopSpanExporter());
|
||||
this.exporter = MultiSpanExporter.create(Arrays.asList(exporter));
|
||||
this.exporter = SpanExporter.composite(Arrays.asList(exporter));
|
||||
|
||||
TestSpanData[] spans = new TestSpanData[spanCount];
|
||||
for (int i = 0; i < spans.length; i++) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/**
|
||||
* Implementation of the {@code SpanProcessor} that simply forwards all received events to a list of
|
||||
* {@code SpanProcessor}s.
|
||||
*
|
||||
* @deprecated Use {@link SpanProcessor#composite(SpanProcessor...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public final class MultiSpanProcessor implements SpanProcessor {
|
||||
private final List<SpanProcessor> spanProcessorsStart;
|
||||
private final List<SpanProcessor> spanProcessorsEnd;
|
||||
|
|
@ -28,7 +31,9 @@ public final class MultiSpanProcessor implements SpanProcessor {
|
|||
* @param spanProcessorList the {@code List} of {@code SpanProcessor}s.
|
||||
* @return a new {@code MultiSpanProcessor}.
|
||||
* @throws NullPointerException if the {@code spanProcessorList} is {@code null}.
|
||||
* @deprecated Use {@link SpanProcessor#composite(SpanProcessor...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static SpanProcessor create(List<SpanProcessor> spanProcessorList) {
|
||||
return new MultiSpanProcessor(
|
||||
new ArrayList<>(Objects.requireNonNull(spanProcessorList, "spanProcessorList")));
|
||||
|
|
|
|||
|
|
@ -8,12 +8,43 @@ package io.opentelemetry.sdk.trace;
|
|||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SpanProcessor is the interface {@code TracerSdk} uses to allow synchronous hooks for when a
|
||||
* {@code Span} is started or when a {@code Span} is ended.
|
||||
*/
|
||||
public interface SpanProcessor {
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanProcessor} which simply delegates all processing to the {@code processors}
|
||||
* in order.
|
||||
*/
|
||||
static SpanProcessor composite(SpanProcessor... processors) {
|
||||
return composite(Arrays.asList(processors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanProcessor} which simply delegates all processing to the {@code processors}
|
||||
* in order.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
static SpanProcessor composite(Iterable<SpanProcessor> processors) {
|
||||
List<SpanProcessor> processorsList = new ArrayList<>();
|
||||
for (SpanProcessor processor : processors) {
|
||||
processorsList.add(processor);
|
||||
}
|
||||
if (processorsList.isEmpty()) {
|
||||
return NoopSpanProcessor.getInstance();
|
||||
}
|
||||
if (processorsList.size() == 1) {
|
||||
return processorsList.get(0);
|
||||
}
|
||||
return MultiSpanProcessor.create(processorsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a {@link io.opentelemetry.api.trace.Span} is started, if the {@link
|
||||
* Span#isRecording()} returns true.
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ final class TracerSharedState {
|
|||
void addSpanProcessor(SpanProcessor spanProcessor) {
|
||||
synchronized (lock) {
|
||||
registeredSpanProcessors.add(spanProcessor);
|
||||
activeSpanProcessor = MultiSpanProcessor.create(registeredSpanProcessors);
|
||||
activeSpanProcessor = SpanProcessor.composite(registeredSpanProcessors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ import java.util.logging.Logger;
|
|||
*
|
||||
* <p>Can be used to export to multiple backends using the same {@code SpanProcessor} like a {@code
|
||||
* SimpleSampledSpansProcessor} or a {@code BatchSampledSpansProcessor}.
|
||||
*
|
||||
* @deprecated Use {@link SpanExporter#composite(SpanExporter...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public final class MultiSpanExporter implements SpanExporter {
|
||||
private static final Logger logger = Logger.getLogger(MultiSpanExporter.class.getName());
|
||||
|
||||
|
|
@ -30,9 +33,11 @@ public final class MultiSpanExporter implements SpanExporter {
|
|||
*
|
||||
* @param spanExporters the exporters spans should be sent to
|
||||
* @return the aggregate span exporter
|
||||
* @deprecated Use {@link SpanExporter#composite(SpanExporter...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static SpanExporter create(List<SpanExporter> spanExporters) {
|
||||
return new MultiSpanExporter(spanExporters);
|
||||
return new MultiSpanExporter(spanExporters.toArray(new SpanExporter[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -94,7 +99,7 @@ public final class MultiSpanExporter implements SpanExporter {
|
|||
return CompletableResultCode.ofAll(results);
|
||||
}
|
||||
|
||||
private MultiSpanExporter(List<SpanExporter> spanExporters) {
|
||||
this.spanExporters = spanExporters.toArray(new SpanExporter[0]);
|
||||
private MultiSpanExporter(SpanExporter[] spanExporters) {
|
||||
this.spanExporters = spanExporters;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.trace.export;
|
||||
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.Collection;
|
||||
|
||||
final class NoopSpanExporter implements SpanExporter {
|
||||
|
||||
private static final SpanExporter INSTANCE = new NoopSpanExporter();
|
||||
|
||||
static SpanExporter getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableResultCode export(Collection<SpanData> spans) {
|
||||
return CompletableResultCode.ofSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableResultCode flush() {
|
||||
return CompletableResultCode.ofSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableResultCode shutdown() {
|
||||
return CompletableResultCode.ofSuccess();
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,10 @@ package io.opentelemetry.sdk.trace.export;
|
|||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.trace.TracerSdkManagement;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An interface that allows different tracing services to export recorded data for sampled spans in
|
||||
|
|
@ -19,6 +22,39 @@ import java.util.Collection;
|
|||
*/
|
||||
public interface SpanExporter {
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanExporter} which simply delegates all exports to the {@code exporters} in
|
||||
* order.
|
||||
*
|
||||
* <p>Can be used to export to multiple backends using the same {@code SpanProcessor} like a
|
||||
* {@code SimpleSampledSpansProcessor} or a {@code BatchSampledSpansProcessor}.
|
||||
*/
|
||||
static SpanExporter composite(SpanExporter... exporters) {
|
||||
return composite(Arrays.asList(exporters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanExporter} which simply delegates all exports to the {@code exporters} in
|
||||
* order.
|
||||
*
|
||||
* <p>Can be used to export to multiple backends using the same {@code SpanProcessor} like a
|
||||
* {@code SimpleSampledSpansProcessor} or a {@code BatchSampledSpansProcessor}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
static SpanExporter composite(Iterable<SpanExporter> exporters) {
|
||||
List<SpanExporter> exportersList = new ArrayList<>();
|
||||
for (SpanExporter exporter : exporters) {
|
||||
exportersList.add(exporter);
|
||||
}
|
||||
if (exportersList.isEmpty()) {
|
||||
return NoopSpanExporter.getInstance();
|
||||
}
|
||||
if (exportersList.size() == 1) {
|
||||
return exportersList.get(0);
|
||||
}
|
||||
return MultiSpanExporter.create(exportersList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to export sampled {@code Span}s. Note that export operations can be performed
|
||||
* simultaneously depending on the type of span processor being used. However, the {@link
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import static org.mockito.ArgumentMatchers.any;
|
|||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
|
|
@ -43,7 +42,7 @@ class MultiSpanProcessorTest {
|
|||
|
||||
@Test
|
||||
void empty() {
|
||||
SpanProcessor multiSpanProcessor = MultiSpanProcessor.create(Collections.emptyList());
|
||||
SpanProcessor multiSpanProcessor = SpanProcessor.composite(Collections.emptyList());
|
||||
multiSpanProcessor.onStart(Context.root(), readWriteSpan);
|
||||
multiSpanProcessor.onEnd(readableSpan);
|
||||
multiSpanProcessor.shutdown();
|
||||
|
|
@ -52,50 +51,14 @@ class MultiSpanProcessorTest {
|
|||
@Test
|
||||
void oneSpanProcessor() {
|
||||
SpanProcessor multiSpanProcessor =
|
||||
MultiSpanProcessor.create(Collections.singletonList(spanProcessor1));
|
||||
multiSpanProcessor.onStart(Context.root(), readWriteSpan);
|
||||
verify(spanProcessor1).onStart(same(Context.root()), same(readWriteSpan));
|
||||
|
||||
multiSpanProcessor.onEnd(readableSpan);
|
||||
verify(spanProcessor1).onEnd(same(readableSpan));
|
||||
|
||||
multiSpanProcessor.forceFlush();
|
||||
verify(spanProcessor1).forceFlush();
|
||||
|
||||
multiSpanProcessor.shutdown();
|
||||
verify(spanProcessor1).shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneSpanProcessor_NoRequirements() {
|
||||
when(spanProcessor1.isStartRequired()).thenReturn(false);
|
||||
when(spanProcessor1.isEndRequired()).thenReturn(false);
|
||||
SpanProcessor multiSpanProcessor =
|
||||
MultiSpanProcessor.create(Collections.singletonList(spanProcessor1));
|
||||
|
||||
verify(spanProcessor1).isStartRequired();
|
||||
verify(spanProcessor1).isEndRequired();
|
||||
|
||||
assertThat(multiSpanProcessor.isStartRequired()).isFalse();
|
||||
assertThat(multiSpanProcessor.isEndRequired()).isFalse();
|
||||
|
||||
multiSpanProcessor.onStart(Context.root(), readWriteSpan);
|
||||
verifyNoMoreInteractions(spanProcessor1);
|
||||
|
||||
multiSpanProcessor.onEnd(readableSpan);
|
||||
verifyNoMoreInteractions(spanProcessor1);
|
||||
|
||||
multiSpanProcessor.forceFlush();
|
||||
verify(spanProcessor1).forceFlush();
|
||||
|
||||
multiSpanProcessor.shutdown();
|
||||
verify(spanProcessor1).shutdown();
|
||||
SpanProcessor.composite(Collections.singletonList(spanProcessor1));
|
||||
assertThat(multiSpanProcessor).isSameAs(spanProcessor1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void twoSpanProcessor() {
|
||||
SpanProcessor multiSpanProcessor =
|
||||
MultiSpanProcessor.create(Arrays.asList(spanProcessor1, spanProcessor2));
|
||||
SpanProcessor.composite(Arrays.asList(spanProcessor1, spanProcessor2));
|
||||
multiSpanProcessor.onStart(Context.root(), readWriteSpan);
|
||||
verify(spanProcessor1).onStart(same(Context.root()), same(readWriteSpan));
|
||||
verify(spanProcessor2).onStart(same(Context.root()), same(readWriteSpan));
|
||||
|
|
@ -118,7 +81,7 @@ class MultiSpanProcessorTest {
|
|||
when(spanProcessor1.isEndRequired()).thenReturn(false);
|
||||
when(spanProcessor2.isStartRequired()).thenReturn(false);
|
||||
SpanProcessor multiSpanProcessor =
|
||||
MultiSpanProcessor.create(Arrays.asList(spanProcessor1, spanProcessor2));
|
||||
SpanProcessor.composite(Arrays.asList(spanProcessor1, spanProcessor2));
|
||||
|
||||
assertThat(multiSpanProcessor.isStartRequired()).isTrue();
|
||||
assertThat(multiSpanProcessor.isEndRequired()).isTrue();
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ class BatchSpanProcessorTest {
|
|||
new WaitingSpanExporter(2, CompletableResultCode.ofSuccess());
|
||||
tracerSdkFactory.addSpanProcessor(
|
||||
BatchSpanProcessor.builder(
|
||||
MultiSpanExporter.create(Arrays.asList(waitingSpanExporter, waitingSpanExporter2)))
|
||||
SpanExporter.composite(Arrays.asList(waitingSpanExporter, waitingSpanExporter2)))
|
||||
.setScheduleDelayMillis(MAX_SCHEDULE_DELAY_MILLIS)
|
||||
.build());
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ class BatchSpanProcessorTest {
|
|||
new WaitingSpanExporter(maxQueuedSpans, CompletableResultCode.ofSuccess());
|
||||
BatchSpanProcessor batchSpanProcessor =
|
||||
BatchSpanProcessor.builder(
|
||||
MultiSpanExporter.create(Arrays.asList(blockingSpanExporter, waitingSpanExporter)))
|
||||
SpanExporter.composite(Arrays.asList(blockingSpanExporter, waitingSpanExporter)))
|
||||
.setScheduleDelayMillis(MAX_SCHEDULE_DELAY_MILLIS)
|
||||
.setMaxQueueSize(maxQueuedSpans)
|
||||
.setMaxExportBatchSize(maxQueuedSpans / 2)
|
||||
|
|
@ -296,7 +296,7 @@ class BatchSpanProcessorTest {
|
|||
.export(ArgumentMatchers.anyList());
|
||||
tracerSdkFactory.addSpanProcessor(
|
||||
BatchSpanProcessor.builder(
|
||||
MultiSpanExporter.create(Arrays.asList(mockServiceHandler, waitingSpanExporter)))
|
||||
SpanExporter.composite(Arrays.asList(mockServiceHandler, waitingSpanExporter)))
|
||||
.setScheduleDelayMillis(MAX_SCHEDULE_DELAY_MILLIS)
|
||||
.build());
|
||||
ReadableSpan span1 = createSampledEndedSpan(SPAN_NAME_1);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class MultiSpanExporterTest {
|
|||
|
||||
@Test
|
||||
void empty() {
|
||||
SpanExporter multiSpanExporter = MultiSpanExporter.create(Collections.emptyList());
|
||||
SpanExporter multiSpanExporter = SpanExporter.composite(Collections.emptyList());
|
||||
multiSpanExporter.export(SPAN_LIST);
|
||||
multiSpanExporter.shutdown();
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ class MultiSpanExporterTest {
|
|||
@Test
|
||||
void oneSpanExporter() {
|
||||
SpanExporter multiSpanExporter =
|
||||
MultiSpanExporter.create(Collections.singletonList(spanExporter1));
|
||||
SpanExporter.composite(Collections.singletonList(spanExporter1));
|
||||
|
||||
when(spanExporter1.export(same(SPAN_LIST))).thenReturn(CompletableResultCode.ofSuccess());
|
||||
assertThat(multiSpanExporter.export(SPAN_LIST).isSuccess()).isTrue();
|
||||
|
|
@ -58,7 +58,7 @@ class MultiSpanExporterTest {
|
|||
@Test
|
||||
void twoSpanExporter() {
|
||||
SpanExporter multiSpanExporter =
|
||||
MultiSpanExporter.create(Arrays.asList(spanExporter1, spanExporter2));
|
||||
SpanExporter.composite(Arrays.asList(spanExporter1, spanExporter2));
|
||||
|
||||
when(spanExporter1.export(same(SPAN_LIST))).thenReturn(CompletableResultCode.ofSuccess());
|
||||
when(spanExporter2.export(same(SPAN_LIST))).thenReturn(CompletableResultCode.ofSuccess());
|
||||
|
|
@ -82,7 +82,7 @@ class MultiSpanExporterTest {
|
|||
@Test
|
||||
void twoSpanExporter_OneReturnFailure() {
|
||||
SpanExporter multiSpanExporter =
|
||||
MultiSpanExporter.create(Arrays.asList(spanExporter1, spanExporter2));
|
||||
SpanExporter.composite(Arrays.asList(spanExporter1, spanExporter2));
|
||||
|
||||
when(spanExporter1.export(same(SPAN_LIST))).thenReturn(CompletableResultCode.ofSuccess());
|
||||
when(spanExporter2.export(same(SPAN_LIST))).thenReturn(CompletableResultCode.ofFailure());
|
||||
|
|
@ -106,7 +106,7 @@ class MultiSpanExporterTest {
|
|||
@Test
|
||||
void twoSpanExporter_FirstThrows() {
|
||||
SpanExporter multiSpanExporter =
|
||||
MultiSpanExporter.create(Arrays.asList(spanExporter1, spanExporter2));
|
||||
SpanExporter.composite(Arrays.asList(spanExporter1, spanExporter2));
|
||||
|
||||
Mockito.doThrow(new IllegalArgumentException("No export for you."))
|
||||
.when(spanExporter1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue