Skip to content

Commit da7796b

Browse files
authored
Use minimal fallback managed channel when none is specified (#6110)
1 parent b4ed532 commit da7796b

File tree

5 files changed

+75
-10
lines changed

5 files changed

+75
-10
lines changed

exporters/otlp/all/src/jmh/java/io/opentelemetry/exporter/otlp/trace/OltpExporterBenchmark.java

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public void setUp() {
8585
"span",
8686
new UpstreamGrpcSender<>(
8787
MarshalerTraceServiceGrpc.newFutureStub(defaultGrpcChannel, null),
88+
/* shutdownChannel= */ false,
8889
10,
8990
Collections::emptyMap),
9091
MeterProvider::noop);

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

+21
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package io.opentelemetry.exporter.otlp.testing.internal;
77

8+
import static org.assertj.core.api.Assertions.as;
89
import static org.assertj.core.api.Assertions.assertThat;
910
import static org.assertj.core.api.Assertions.assertThatCode;
1011
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -23,8 +24,10 @@
2324
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
2425
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
2526
import io.github.netmikey.logunit.api.LogCapturer;
27+
import io.grpc.ManagedChannel;
2628
import io.opentelemetry.exporter.internal.TlsUtil;
2729
import io.opentelemetry.exporter.internal.grpc.GrpcExporter;
30+
import io.opentelemetry.exporter.internal.grpc.MarshalerServiceStub;
2831
import io.opentelemetry.exporter.internal.marshal.Marshaler;
2932
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
3033
import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest;
@@ -61,6 +64,7 @@
6164
import javax.net.ssl.TrustManager;
6265
import javax.net.ssl.X509KeyManager;
6366
import javax.net.ssl.X509TrustManager;
67+
import org.assertj.core.api.InstanceOfAssertFactories;
6468
import org.assertj.core.api.iterable.ThrowingExtractor;
6569
import org.junit.jupiter.api.AfterAll;
6670
import org.junit.jupiter.api.AfterEach;
@@ -215,6 +219,23 @@ void reset() {
215219
httpRequests.clear();
216220
}
217221

222+
@Test
223+
void minimalChannel() {
224+
// Test that UpstreamGrpcSender uses minimal fallback managed channel, so skip for
225+
// OkHttpGrpcSender
226+
assumeThat(exporter.unwrap())
227+
.extracting("delegate.grpcSender")
228+
.matches(sender -> sender.getClass().getSimpleName().equals("UpstreamGrpcSender"));
229+
// When no channel is explicitly set, should fall back to a minimally configured managed channel
230+
TelemetryExporter<?> exporter = exporterBuilder().build();
231+
assertThat(exporter.shutdown().join(10, TimeUnit.SECONDS).isSuccess()).isTrue();
232+
assertThat(exporter.unwrap())
233+
.extracting(
234+
"delegate.grpcSender.stub",
235+
as(InstanceOfAssertFactories.type(MarshalerServiceStub.class)))
236+
.satisfies(stub -> assertThat(((ManagedChannel) stub.getChannel()).isShutdown()).isTrue());
237+
}
238+
218239
@Test
219240
void export() {
220241
List<T> telemetry = Collections.singletonList(generateFakeTelemetry());

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

+13-8
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,21 @@ public TelemetryExporterBuilder<T> setChannel(Object channel) {
158158

159159
@Override
160160
public TelemetryExporter<T> build() {
161-
requireNonNull(channelBuilder, "channel");
161+
Runnable shutdownCallback;
162+
if (channelBuilder != null) {
163+
try {
164+
setSslContext(channelBuilder, tlsConfigHelper);
165+
} catch (SSLException e) {
166+
throw new IllegalStateException(e);
167+
}
162168

163-
try {
164-
setSslContext(channelBuilder, tlsConfigHelper);
165-
} catch (SSLException e) {
166-
throw new IllegalStateException(e);
169+
ManagedChannel channel = channelBuilder.build();
170+
delegate.setChannel(channel);
171+
shutdownCallback = channel::shutdownNow;
172+
} else {
173+
shutdownCallback = () -> {};
167174
}
168175

169-
ManagedChannel channel = channelBuilder.build();
170-
delegate.setChannel(channel);
171176
TelemetryExporter<T> delegateExporter = delegate.build();
172177
return new TelemetryExporter<T>() {
173178
@Override
@@ -182,7 +187,7 @@ public CompletableResultCode export(Collection<T> items) {
182187

183188
@Override
184189
public CompletableResultCode shutdown() {
185-
channel.shutdownNow();
190+
shutdownCallback.run();
186191
return delegateExporter.shutdown();
187192
}
188193
};

exporters/sender/grpc-managed-channel/src/main/java/io/opentelemetry/exporter/sender/grpc/managedchannel/internal/UpstreamGrpcSender.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.google.common.util.concurrent.FutureCallback;
99
import com.google.common.util.concurrent.Futures;
1010
import com.google.common.util.concurrent.MoreExecutors;
11+
import io.grpc.ManagedChannel;
1112
import io.grpc.Metadata;
1213
import io.grpc.Status;
1314
import io.grpc.stub.MetadataUtils;
@@ -32,16 +33,19 @@
3233
public final class UpstreamGrpcSender<T extends Marshaler> implements GrpcSender<T> {
3334

3435
private final MarshalerServiceStub<T, ?, ?> stub;
36+
private final boolean shutdownChannel;
3537
private final long timeoutNanos;
3638
private final Supplier<Map<String, List<String>>> headersSupplier;
3739

3840
/** Creates a new {@link UpstreamGrpcSender}. */
3941
public UpstreamGrpcSender(
4042
MarshalerServiceStub<T, ?, ?> stub,
43+
boolean shutdownChannel,
4144
long timeoutNanos,
4245
Supplier<Map<String, List<String>>> headersSupplier) {
43-
this.timeoutNanos = timeoutNanos;
4446
this.stub = stub;
47+
this.shutdownChannel = shutdownChannel;
48+
this.timeoutNanos = timeoutNanos;
4549
this.headersSupplier = headersSupplier;
4650
}
4751

@@ -82,6 +86,10 @@ public void onFailure(Throwable t) {
8286

8387
@Override
8488
public CompletableResultCode shutdown() {
89+
if (shutdownChannel) {
90+
ManagedChannel channel = (ManagedChannel) stub.getChannel();
91+
channel.shutdownNow();
92+
}
8593
return CompletableResultCode.ofSuccess();
8694
}
8795
}

exporters/sender/grpc-managed-channel/src/main/java/io/opentelemetry/exporter/sender/grpc/managedchannel/internal/UpstreamGrpcSenderProvider.java

+31-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import io.grpc.Channel;
99
import io.grpc.Codec;
10+
import io.grpc.ManagedChannel;
11+
import io.grpc.ManagedChannelBuilder;
1012
import io.opentelemetry.exporter.internal.grpc.GrpcSender;
1113
import io.opentelemetry.exporter.internal.grpc.GrpcSenderProvider;
1214
import io.opentelemetry.exporter.internal.grpc.MarshalerServiceStub;
@@ -41,6 +43,13 @@ public <T extends Marshaler> GrpcSender<T> createSender(
4143
@Nullable RetryPolicy retryPolicy,
4244
@Nullable SSLContext sslContext,
4345
@Nullable X509TrustManager trustManager) {
46+
boolean shutdownChannel = false;
47+
if (managedChannel == null) {
48+
// Shutdown the channel as part of the exporter shutdown sequence if
49+
shutdownChannel = true;
50+
managedChannel = minimalFallbackManagedChannel(endpoint);
51+
}
52+
4453
String authorityOverride = null;
4554
Map<String, List<String>> headers = headersSupplier.get();
4655
if (headers != null) {
@@ -58,6 +67,27 @@ public <T extends Marshaler> GrpcSender<T> createSender(
5867
.apply((Channel) managedChannel, authorityOverride)
5968
.withCompression(codec.getMessageEncoding());
6069

61-
return new UpstreamGrpcSender<>(stub, timeoutNanos, headersSupplier);
70+
return new UpstreamGrpcSender<>(stub, shutdownChannel, timeoutNanos, headersSupplier);
71+
}
72+
73+
/**
74+
* If {@link ManagedChannel} is not explicitly set, provide a minimally configured fallback
75+
* channel to avoid failing initialization.
76+
*
77+
* <p>This is required to accommodate autoconfigure with {@code
78+
* opentelemetry-exporter-sender-grpc-managed-channel} which will always fail to initialize
79+
* without a fallback channel since there isn't an opportunity to explicitly set the channel.
80+
*
81+
* <p>This only incorporates the target address, port, and whether to use plain text. All
82+
* additional settings are intentionally ignored and must be configured with an explicitly set
83+
* {@link ManagedChannel}.
84+
*/
85+
private static ManagedChannel minimalFallbackManagedChannel(URI endpoint) {
86+
ManagedChannelBuilder<?> channelBuilder =
87+
ManagedChannelBuilder.forAddress(endpoint.getHost(), endpoint.getPort());
88+
if (!endpoint.getScheme().equals("https")) {
89+
channelBuilder.usePlaintext();
90+
}
91+
return channelBuilder.build();
6292
}
6393
}

0 commit comments

Comments
 (0)