Skip to content

Commit cc4720d

Browse files
authored
Add the option to configure the zipkin exporter timeout. (open-telemetry#3203)
1 parent af629a6 commit cc4720d

File tree

5 files changed

+85
-1
lines changed

5 files changed

+85
-1
lines changed

exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterBuilder.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
package io.opentelemetry.exporter.zipkin;
77

8+
import static io.opentelemetry.api.internal.Utils.checkArgument;
9+
import static java.util.Objects.requireNonNull;
10+
11+
import java.time.Duration;
12+
import java.util.concurrent.TimeUnit;
813
import zipkin2.Span;
914
import zipkin2.codec.BytesEncoder;
1015
import zipkin2.codec.SpanBytesEncoder;
@@ -16,6 +21,7 @@ public final class ZipkinSpanExporterBuilder {
1621
private BytesEncoder<Span> encoder = SpanBytesEncoder.JSON_V2;
1722
private Sender sender;
1823
private String endpoint = ZipkinSpanExporter.DEFAULT_ENDPOINT;
24+
private long readTimeoutMillis = TimeUnit.SECONDS.toMillis(10);
1925

2026
/**
2127
* Sets the Zipkin sender. Implements the client side of the span transport. A {@link
@@ -27,6 +33,7 @@ public final class ZipkinSpanExporterBuilder {
2733
* @return this.
2834
*/
2935
public ZipkinSpanExporterBuilder setSender(Sender sender) {
36+
requireNonNull(sender, "sender");
3037
this.sender = sender;
3138
return this;
3239
}
@@ -40,6 +47,7 @@ public ZipkinSpanExporterBuilder setSender(Sender sender) {
4047
* @see SpanBytesEncoder
4148
*/
4249
public ZipkinSpanExporterBuilder setEncoder(BytesEncoder<Span> encoder) {
50+
requireNonNull(encoder, "encoder");
4351
this.encoder = encoder;
4452
return this;
4553
}
@@ -53,18 +61,43 @@ public ZipkinSpanExporterBuilder setEncoder(BytesEncoder<Span> encoder) {
5361
* @see OkHttpSender
5462
*/
5563
public ZipkinSpanExporterBuilder setEndpoint(String endpoint) {
64+
requireNonNull(endpoint, "endpoint");
5665
this.endpoint = endpoint;
5766
return this;
5867
}
5968

69+
/**
70+
* Sets the maximum time to wait for the export of a batch of spans. If unset, defaults to 10s.
71+
*
72+
* @return this.
73+
*/
74+
public ZipkinSpanExporterBuilder setReadTimeout(long timeout, TimeUnit unit) {
75+
requireNonNull(unit, "unit");
76+
checkArgument(timeout >= 0, "timeout must be non-negative");
77+
this.readTimeoutMillis = unit.toMillis(timeout);
78+
return this;
79+
}
80+
81+
/**
82+
* Sets the maximum time to wait for the export of a batch of spans. If unset, defaults to 10s.
83+
*
84+
* @return this.
85+
*/
86+
public ZipkinSpanExporterBuilder setReadTimeout(Duration timeout) {
87+
requireNonNull(timeout, "timeout");
88+
setReadTimeout(timeout.toMillis(), TimeUnit.MILLISECONDS);
89+
return this;
90+
}
91+
6092
/**
6193
* Builds a {@link ZipkinSpanExporter}.
6294
*
6395
* @return a {@code ZipkinSpanExporter}.
6496
*/
6597
public ZipkinSpanExporter build() {
6698
if (sender == null) {
67-
sender = OkHttpSender.create(endpoint);
99+
sender =
100+
OkHttpSender.newBuilder().endpoint(endpoint).readTimeout((int) readTimeoutMillis).build();
68101
}
69102
return new ZipkinSpanExporter(this.encoder, this.sender);
70103
}

exporters/zipkin/src/test/java/io/opentelemetry/exporter/zipkin/ZipkinSpanExporterTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
1515
import static io.opentelemetry.api.common.AttributeKey.stringKey;
1616
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1718
import static org.mockito.ArgumentMatchers.any;
1819
import static org.mockito.Mockito.doAnswer;
1920
import static org.mockito.Mockito.verify;
@@ -38,6 +39,7 @@
3839
import java.util.Arrays;
3940
import java.util.Collections;
4041
import java.util.List;
42+
import java.util.concurrent.TimeUnit;
4143
import org.junit.jupiter.api.Test;
4244
import org.junit.jupiter.api.extension.ExtendWith;
4345
import org.mockito.Mock;
@@ -423,4 +425,32 @@ private Span.Builder standardZipkinSpanBuilder(Span.Kind kind) {
423425
.addAnnotation(1505855799000000L + 433901068L / 1000, "RECEIVED")
424426
.addAnnotation(1505855799000000L + 459486280L / 1000, "SENT");
425427
}
428+
429+
@Test
430+
@SuppressWarnings("PreferJavaTimeOverload")
431+
void invalidConfig() {
432+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setReadTimeout(-1, TimeUnit.MILLISECONDS))
433+
.isInstanceOf(IllegalArgumentException.class)
434+
.hasMessage("timeout must be non-negative");
435+
436+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setReadTimeout(1, null))
437+
.isInstanceOf(NullPointerException.class)
438+
.hasMessage("unit");
439+
440+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setReadTimeout(null))
441+
.isInstanceOf(NullPointerException.class)
442+
.hasMessage("timeout");
443+
444+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setEndpoint(null))
445+
.isInstanceOf(NullPointerException.class)
446+
.hasMessage("endpoint");
447+
448+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setSender(null))
449+
.isInstanceOf(NullPointerException.class)
450+
.hasMessage("sender");
451+
452+
assertThatThrownBy(() -> ZipkinSpanExporter.builder().setEncoder(null))
453+
.isInstanceOf(NullPointerException.class)
454+
.hasMessage("encoder");
455+
}
426456
}

sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ private static SpanExporter configureZipkin(ConfigProperties config) {
135135
builder.setEndpoint(endpoint);
136136
}
137137

138+
Duration timeout = config.getDuration("otel.exporter.zipkin.timeout");
139+
if (timeout != null) {
140+
builder.setReadTimeout(timeout);
141+
}
142+
138143
return builder.build();
139144
}
140145

sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/SpanExporterConfigurationTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,19 @@ void configureJaegerTimeout() {
5757
exporter.shutdown();
5858
}
5959
}
60+
61+
// Timeout difficult to test using real exports so just check that things don't blow up.
62+
@Test
63+
void configureZipkinTimeout() {
64+
SpanExporter exporter =
65+
SpanExporterConfiguration.configureExporter(
66+
"zipkin",
67+
ConfigProperties.createForTest(
68+
Collections.singletonMap("otel.exporter.zipkin.timeout", "5s")));
69+
try {
70+
assertThat(exporter).isNotNull();
71+
} finally {
72+
exporter.shutdown();
73+
}
74+
}
6075
}

sdk-extensions/autoconfigure/src/testZipkin/java/io/opentelemetry/sdk/autoconfigure/ZipkinConfigTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void configures() {
5252
String endpoint = "localhost:" + server.httpPort();
5353

5454
System.setProperty("otel.exporter.zipkin.endpoint", "http://" + endpoint + "/api/v2/spans");
55+
System.setProperty("otel.exporter.zipkin.timeout", "5s");
5556

5657
OpenTelemetrySdkAutoConfiguration.initialize();
5758

0 commit comments

Comments
 (0)