Skip to content

Commit 31869a3

Browse files
authored
Interpret timeout zero value as no limit (#7023)
1 parent 4eeef33 commit 31869a3

File tree

10 files changed

+131
-26
lines changed

10 files changed

+131
-26
lines changed

exporters/common/src/main/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public GrpcExporterBuilder<T> setChannel(ManagedChannel channel) {
8787
}
8888

8989
public GrpcExporterBuilder<T> setTimeout(long timeout, TimeUnit unit) {
90-
timeoutNanos = unit.toNanos(timeout);
90+
timeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
9191
return this;
9292
}
9393

@@ -96,7 +96,7 @@ public GrpcExporterBuilder<T> setTimeout(Duration timeout) {
9696
}
9797

9898
public GrpcExporterBuilder<T> setConnectTimeout(long timeout, TimeUnit unit) {
99-
connectTimeoutNanos = unit.toNanos(timeout);
99+
connectTimeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
100100
return this;
101101
}
102102

exporters/common/src/main/java/io/opentelemetry/exporter/internal/http/HttpExporterBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ public HttpExporterBuilder(String exporterName, String type, String defaultEndpo
6969
}
7070

7171
public HttpExporterBuilder<T> setTimeout(long timeout, TimeUnit unit) {
72-
timeoutNanos = unit.toNanos(timeout);
72+
timeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
7373
return this;
7474
}
7575

7676
public HttpExporterBuilder<T> setConnectTimeout(long timeout, TimeUnit unit) {
77-
connectTimeoutNanos = unit.toNanos(timeout);
77+
connectTimeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
7878
return this;
7979
}
8080

exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractGrpcTelemetryExporterTest.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -815,13 +815,39 @@ void overrideHost() {
815815
@Test
816816
@SuppressWarnings("PreferJavaTimeOverload")
817817
void validConfig() {
818-
assertThatCode(() -> exporterBuilder().setTimeout(0, TimeUnit.MILLISECONDS))
818+
// We must build exporters to test timeout settings, which intersect with underlying client
819+
// implementations and may convert between Duration, int, and long, which may be susceptible to
820+
// overflow exceptions.
821+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(0, TimeUnit.MILLISECONDS)))
819822
.doesNotThrowAnyException();
820-
assertThatCode(() -> exporterBuilder().setTimeout(Duration.ofMillis(0)))
823+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofMillis(0))))
821824
.doesNotThrowAnyException();
822-
assertThatCode(() -> exporterBuilder().setTimeout(10, TimeUnit.MILLISECONDS))
825+
assertThatCode(
826+
() ->
827+
buildAndShutdown(
828+
exporterBuilder().setTimeout(Long.MAX_VALUE, TimeUnit.NANOSECONDS)))
829+
.doesNotThrowAnyException();
830+
assertThatCode(
831+
() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofNanos(Long.MAX_VALUE))))
832+
.doesNotThrowAnyException();
833+
assertThatCode(
834+
() -> buildAndShutdown(exporterBuilder().setTimeout(Long.MAX_VALUE, TimeUnit.SECONDS)))
835+
.doesNotThrowAnyException();
836+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(10, TimeUnit.MILLISECONDS)))
837+
.doesNotThrowAnyException();
838+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofMillis(10))))
839+
.doesNotThrowAnyException();
840+
assertThatCode(
841+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(0, TimeUnit.MILLISECONDS)))
842+
.doesNotThrowAnyException();
843+
assertThatCode(
844+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(Duration.ofMillis(0))))
845+
.doesNotThrowAnyException();
846+
assertThatCode(
847+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(10, TimeUnit.MILLISECONDS)))
823848
.doesNotThrowAnyException();
824-
assertThatCode(() -> exporterBuilder().setTimeout(Duration.ofMillis(10)))
849+
assertThatCode(
850+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(Duration.ofMillis(10))))
825851
.doesNotThrowAnyException();
826852

827853
assertThatCode(() -> exporterBuilder().setEndpoint("http://localhost:4317"))
@@ -846,6 +872,11 @@ void validConfig() {
846872
.doesNotThrowAnyException();
847873
}
848874

875+
private void buildAndShutdown(TelemetryExporterBuilder<T> builder) {
876+
TelemetryExporter<T> build = builder.build();
877+
build.shutdown().join(10, TimeUnit.MILLISECONDS);
878+
}
879+
849880
@Test
850881
@SuppressWarnings({"PreferJavaTimeOverload", "NullAway"})
851882
void invalidConfig() {
@@ -858,6 +889,25 @@ void invalidConfig() {
858889
assertThatThrownBy(() -> exporterBuilder().setTimeout(null))
859890
.isInstanceOf(NullPointerException.class)
860891
.hasMessage("timeout");
892+
assertThatThrownBy(
893+
() ->
894+
buildAndShutdown(exporterBuilder().setTimeout(Duration.ofSeconds(Long.MAX_VALUE))))
895+
.isInstanceOf(ArithmeticException.class);
896+
897+
assertThatThrownBy(() -> exporterBuilder().setConnectTimeout(-1, TimeUnit.MILLISECONDS))
898+
.isInstanceOf(IllegalArgumentException.class)
899+
.hasMessage("timeout must be non-negative");
900+
assertThatThrownBy(() -> exporterBuilder().setConnectTimeout(1, null))
901+
.isInstanceOf(NullPointerException.class)
902+
.hasMessage("unit");
903+
assertThatThrownBy(() -> exporterBuilder().setConnectTimeout(null))
904+
.isInstanceOf(NullPointerException.class)
905+
.hasMessage("timeout");
906+
assertThatThrownBy(
907+
() ->
908+
buildAndShutdown(
909+
exporterBuilder().setConnectTimeout(Duration.ofSeconds(Long.MAX_VALUE))))
910+
.isInstanceOf(ArithmeticException.class);
861911

862912
assertThatThrownBy(() -> exporterBuilder().setEndpoint(null))
863913
.isInstanceOf(NullPointerException.class)

exporters/otlp/testing-internal/src/main/java/io/opentelemetry/exporter/otlp/testing/internal/AbstractHttpTelemetryExporterTest.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -698,22 +698,39 @@ void proxy() {
698698
@Test
699699
@SuppressWarnings("PreferJavaTimeOverload")
700700
void validConfig() {
701-
assertThatCode(() -> exporterBuilder().setTimeout(0, TimeUnit.MILLISECONDS))
701+
// We must build exporters to test timeout settings, which intersect with underlying client
702+
// implementations and may convert between Duration, int, and long, which may be susceptible to
703+
// overflow exceptions.
704+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(0, TimeUnit.MILLISECONDS)))
702705
.doesNotThrowAnyException();
703-
assertThatCode(() -> exporterBuilder().setTimeout(Duration.ofMillis(0)))
706+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofMillis(0))))
704707
.doesNotThrowAnyException();
705-
assertThatCode(() -> exporterBuilder().setTimeout(10, TimeUnit.MILLISECONDS))
708+
assertThatCode(
709+
() ->
710+
buildAndShutdown(
711+
exporterBuilder().setTimeout(Long.MAX_VALUE, TimeUnit.NANOSECONDS)))
706712
.doesNotThrowAnyException();
707-
assertThatCode(() -> exporterBuilder().setTimeout(Duration.ofMillis(10)))
713+
assertThatCode(
714+
() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofNanos(Long.MAX_VALUE))))
708715
.doesNotThrowAnyException();
709-
710-
assertThatCode(() -> exporterBuilder().setConnectTimeout(0, TimeUnit.MILLISECONDS))
716+
assertThatCode(
717+
() -> buildAndShutdown(exporterBuilder().setTimeout(Long.MAX_VALUE, TimeUnit.SECONDS)))
718+
.doesNotThrowAnyException();
719+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(10, TimeUnit.MILLISECONDS)))
720+
.doesNotThrowAnyException();
721+
assertThatCode(() -> buildAndShutdown(exporterBuilder().setTimeout(Duration.ofMillis(10))))
722+
.doesNotThrowAnyException();
723+
assertThatCode(
724+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(0, TimeUnit.MILLISECONDS)))
711725
.doesNotThrowAnyException();
712-
assertThatCode(() -> exporterBuilder().setConnectTimeout(Duration.ofMillis(0)))
726+
assertThatCode(
727+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(Duration.ofMillis(0))))
713728
.doesNotThrowAnyException();
714-
assertThatCode(() -> exporterBuilder().setConnectTimeout(10, TimeUnit.MILLISECONDS))
729+
assertThatCode(
730+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(10, TimeUnit.MILLISECONDS)))
715731
.doesNotThrowAnyException();
716-
assertThatCode(() -> exporterBuilder().setConnectTimeout(Duration.ofMillis(10)))
732+
assertThatCode(
733+
() -> buildAndShutdown(exporterBuilder().setConnectTimeout(Duration.ofMillis(10))))
717734
.doesNotThrowAnyException();
718735

719736
assertThatCode(() -> exporterBuilder().setEndpoint("http://localhost:4318"))
@@ -738,6 +755,11 @@ void validConfig() {
738755
.doesNotThrowAnyException();
739756
}
740757

758+
private void buildAndShutdown(TelemetryExporterBuilder<T> builder) {
759+
TelemetryExporter<T> build = builder.build();
760+
build.shutdown().join(10, TimeUnit.MILLISECONDS);
761+
}
762+
741763
@Test
742764
@SuppressWarnings({"PreferJavaTimeOverload", "NullAway"})
743765
void invalidConfig() {
@@ -750,6 +772,10 @@ void invalidConfig() {
750772
assertThatThrownBy(() -> exporterBuilder().setTimeout(null))
751773
.isInstanceOf(NullPointerException.class)
752774
.hasMessage("timeout");
775+
assertThatThrownBy(
776+
() ->
777+
buildAndShutdown(exporterBuilder().setTimeout(Duration.ofSeconds(Long.MAX_VALUE))))
778+
.isInstanceOf(ArithmeticException.class);
753779

754780
assertThatThrownBy(() -> exporterBuilder().setConnectTimeout(-1, TimeUnit.MILLISECONDS))
755781
.isInstanceOf(IllegalArgumentException.class)
@@ -760,6 +786,11 @@ void invalidConfig() {
760786
assertThatThrownBy(() -> exporterBuilder().setConnectTimeout(null))
761787
.isInstanceOf(NullPointerException.class)
762788
.hasMessage("timeout");
789+
assertThatThrownBy(
790+
() ->
791+
buildAndShutdown(
792+
exporterBuilder().setConnectTimeout(Duration.ofSeconds(Long.MAX_VALUE))))
793+
.isInstanceOf(ArithmeticException.class);
763794

764795
assertThatThrownBy(() -> exporterBuilder().setEndpoint(null))
765796
.isInstanceOf(NullPointerException.class)

exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpGrpcSender.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,15 @@ public OkHttpGrpcSender(
8181
@Nullable RetryPolicy retryPolicy,
8282
@Nullable SSLContext sslContext,
8383
@Nullable X509TrustManager trustManager) {
84+
int callTimeoutMillis =
85+
(int) Math.min(Duration.ofNanos(timeoutNanos).toMillis(), Integer.MAX_VALUE);
86+
int connectTimeoutMillis =
87+
(int) Math.min(Duration.ofNanos(connectTimeoutNanos).toMillis(), Integer.MAX_VALUE);
8488
OkHttpClient.Builder clientBuilder =
8589
new OkHttpClient.Builder()
8690
.dispatcher(OkHttpUtil.newDispatcher())
87-
.callTimeout(Duration.ofNanos(timeoutNanos))
88-
.connectTimeout(Duration.ofNanos(connectTimeoutNanos));
91+
.callTimeout(Duration.ofMillis(callTimeoutMillis))
92+
.connectTimeout(Duration.ofMillis(connectTimeoutMillis));
8993
if (retryPolicy != null) {
9094
clientBuilder.addInterceptor(
9195
new RetryInterceptor(retryPolicy, OkHttpGrpcSender::isRetryable));

exporters/sender/okhttp/src/main/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpHttpSender.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,15 @@ public OkHttpHttpSender(
6464
@Nullable RetryPolicy retryPolicy,
6565
@Nullable SSLContext sslContext,
6666
@Nullable X509TrustManager trustManager) {
67+
int callTimeoutMillis =
68+
(int) Math.min(Duration.ofNanos(timeoutNanos).toMillis(), Integer.MAX_VALUE);
69+
int connectTimeoutMillis =
70+
(int) Math.min(Duration.ofNanos(connectionTimeoutNanos).toMillis(), Integer.MAX_VALUE);
6771
OkHttpClient.Builder builder =
6872
new OkHttpClient.Builder()
6973
.dispatcher(OkHttpUtil.newDispatcher())
70-
.connectTimeout(Duration.ofNanos(connectionTimeoutNanos))
71-
.callTimeout(Duration.ofNanos(timeoutNanos));
74+
.connectTimeout(Duration.ofMillis(connectTimeoutMillis))
75+
.callTimeout(Duration.ofMillis(callTimeoutMillis));
7276

7377
if (proxyOptions != null) {
7478
builder.proxySelector(proxyOptions.getProxySelector());

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public final class ZipkinSpanExporterBuilder {
3131
// compression is enabled by default, because this is the default of OkHttpSender,
3232
// which is created when no custom sender is set (see OkHttpSender.Builder)
3333
private boolean compressionEnabled = true;
34-
private long readTimeoutMillis = TimeUnit.SECONDS.toMillis(10);
34+
private int readTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(10);
3535
private Supplier<MeterProvider> meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
3636

3737
/**
@@ -156,7 +156,8 @@ public ZipkinSpanExporterBuilder setCompression(String compressionMethod) {
156156
public ZipkinSpanExporterBuilder setReadTimeout(long timeout, TimeUnit unit) {
157157
requireNonNull(unit, "unit");
158158
checkArgument(timeout >= 0, "timeout must be non-negative");
159-
this.readTimeoutMillis = unit.toMillis(timeout);
159+
long timeoutMillis = timeout == 0 ? Long.MAX_VALUE : unit.toMillis(timeout);
160+
this.readTimeoutMillis = (int) Math.min(timeoutMillis, Integer.MAX_VALUE);
160161
return this;
161162
}
162163

@@ -212,7 +213,7 @@ public ZipkinSpanExporter build() {
212213
OkHttpSender.newBuilder()
213214
.endpoint(endpoint)
214215
.compressionEnabled(compressionEnabled)
215-
.readTimeout((int) readTimeoutMillis)
216+
.readTimeout(readTimeoutMillis)
216217
.build();
217218
}
218219
OtelToZipkinSpanTransformer transformer =

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ void compressionEnabledAndDisabled() {
231231
}
232232
}
233233

234+
@Test
235+
@SuppressWarnings("PreferJavaTimeOverload")
236+
void readTimeout_Zero() {
237+
ZipkinSpanExporter exporter =
238+
ZipkinSpanExporter.builder().setReadTimeout(0, TimeUnit.SECONDS).build();
239+
240+
try {
241+
assertThat(exporter)
242+
.extracting("sender.delegate.client.readTimeoutMillis")
243+
.isEqualTo(Integer.MAX_VALUE);
244+
} finally {
245+
exporter.shutdown();
246+
}
247+
}
248+
234249
@Test
235250
void stringRepresentation() {
236251
try (ZipkinSpanExporter exporter = ZipkinSpanExporter.builder().build()) {

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/BatchLogRecordProcessorBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ long getScheduleDelayNanos() {
7171
public BatchLogRecordProcessorBuilder setExporterTimeout(long timeout, TimeUnit unit) {
7272
requireNonNull(unit, "unit");
7373
checkArgument(timeout >= 0, "timeout must be non-negative");
74-
exporterTimeoutNanos = unit.toNanos(timeout);
74+
exporterTimeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
7575
return this;
7676
}
7777

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/export/BatchSpanProcessorBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ long getScheduleDelayNanos() {
7979
public BatchSpanProcessorBuilder setExporterTimeout(long timeout, TimeUnit unit) {
8080
requireNonNull(unit, "unit");
8181
checkArgument(timeout >= 0, "timeout must be non-negative");
82-
exporterTimeoutNanos = unit.toNanos(timeout);
82+
exporterTimeoutNanos = timeout == 0 ? Long.MAX_VALUE : unit.toNanos(timeout);
8383
return this;
8484
}
8585

0 commit comments

Comments
 (0)