Skip to content

Commit dc46ccd

Browse files
authored
Add support for setting OTLP exporter service class loader (#7150)
1 parent d1ce438 commit dc46ccd

19 files changed

+196
-5
lines changed
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,19 @@
11
Comparing source compatibility of opentelemetry-exporter-otlp-1.48.0-SNAPSHOT.jar against opentelemetry-exporter-otlp-1.47.0.jar
2-
No changes.
2+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder (not serializable)
3+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
4+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder setServiceClassLoader(java.lang.ClassLoader)
5+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder (not serializable)
6+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
7+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder setServiceClassLoader(java.lang.ClassLoader)
8+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder (not serializable)
9+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
10+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder setServiceClassLoader(java.lang.ClassLoader)
11+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder (not serializable)
12+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
13+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder setServiceClassLoader(java.lang.ClassLoader)
14+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder (not serializable)
15+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
16+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder setServiceClassLoader(java.lang.ClassLoader)
17+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder (not serializable)
18+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
19+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder setServiceClassLoader(java.lang.ClassLoader)

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class GrpcExporterBuilder<T extends Marshaler> {
6262
private TlsConfigHelper tlsConfigHelper = new TlsConfigHelper();
6363
@Nullable private RetryPolicy retryPolicy = RetryPolicy.getDefault();
6464
private Supplier<MeterProvider> meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
65+
private ClassLoader serviceClassLoader = GrpcExporterBuilder.class.getClassLoader();
6566

6667
// Use Object type since gRPC may not be on the classpath.
6768
@Nullable private Object grpcChannel;
@@ -147,6 +148,11 @@ public GrpcExporterBuilder<T> setMeterProvider(Supplier<MeterProvider> meterProv
147148
return this;
148149
}
149150

151+
public GrpcExporterBuilder<T> setServiceClassLoader(ClassLoader servieClassLoader) {
152+
this.serviceClassLoader = servieClassLoader;
153+
return this;
154+
}
155+
150156
@SuppressWarnings("BuilderReturnThis")
151157
public GrpcExporterBuilder<T> copy() {
152158
GrpcExporterBuilder<T> copy =
@@ -242,6 +248,7 @@ public String toString(boolean includePrefixAndSuffix) {
242248
if (grpcChannel != null) {
243249
joiner.add("grpcChannel=" + grpcChannel);
244250
}
251+
joiner.add("serviceClassLoader=" + serviceClassLoader);
245252
// Note: omit tlsConfigHelper because we can't log the configuration in any readable way
246253
// Note: omit meterProviderSupplier because we can't log the configuration in any readable way
247254
return joiner.toString();
@@ -268,10 +275,10 @@ public String toString() {
268275
* matching provider. If none match, throw {@link IllegalStateException}.
269276
* </ul>
270277
*/
271-
private static GrpcSenderProvider resolveGrpcSenderProvider() {
278+
private GrpcSenderProvider resolveGrpcSenderProvider() {
272279
Map<String, GrpcSenderProvider> grpcSenderProviders = new HashMap<>();
273280
for (GrpcSenderProvider spi :
274-
ServiceLoader.load(GrpcSenderProvider.class, GrpcExporterBuilder.class.getClassLoader())) {
281+
ServiceLoader.load(GrpcSenderProvider.class, serviceClassLoader)) {
275282
grpcSenderProviders.put(spi.getClass().getName(), spi);
276283
}
277284

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public final class HttpExporterBuilder<T extends Marshaler> {
6060
private TlsConfigHelper tlsConfigHelper = new TlsConfigHelper();
6161
@Nullable private RetryPolicy retryPolicy = RetryPolicy.getDefault();
6262
private Supplier<MeterProvider> meterProviderSupplier = GlobalOpenTelemetry::getMeterProvider;
63+
private ClassLoader serviceClassLoader = HttpExporterBuilder.class.getClassLoader();
6364

6465
public HttpExporterBuilder(String exporterName, String type, String defaultEndpoint) {
6566
this.exporterName = exporterName;
@@ -131,6 +132,11 @@ public HttpExporterBuilder<T> setProxyOptions(ProxyOptions proxyOptions) {
131132
return this;
132133
}
133134

135+
public HttpExporterBuilder<T> setServiceClassLoader(ClassLoader servieClassLoader) {
136+
this.serviceClassLoader = servieClassLoader;
137+
return this;
138+
}
139+
134140
public HttpExporterBuilder<T> exportAsJson() {
135141
this.exportAsJson = true;
136142
return this;
@@ -222,6 +228,7 @@ public String toString(boolean includePrefixAndSuffix) {
222228
if (retryPolicy != null) {
223229
joiner.add("retryPolicy=" + retryPolicy);
224230
}
231+
joiner.add("serviceClassLoader=" + serviceClassLoader);
225232
// Note: omit tlsConfigHelper because we can't log the configuration in any readable way
226233
// Note: omit meterProviderSupplier because we can't log the configuration in any readable way
227234
return joiner.toString();
@@ -248,10 +255,10 @@ public String toString() {
248255
* matching provider. If none match, throw {@link IllegalStateException}.
249256
* </ul>
250257
*/
251-
private static HttpSenderProvider resolveHttpSenderProvider() {
258+
private HttpSenderProvider resolveHttpSenderProvider() {
252259
Map<String, HttpSenderProvider> httpSenderProviders = new HashMap<>();
253260
for (HttpSenderProvider spi :
254-
ServiceLoader.load(HttpSenderProvider.class, HttpExporterBuilder.class.getClassLoader())) {
261+
ServiceLoader.load(HttpSenderProvider.class, serviceClassLoader)) {
255262
httpSenderProviders.put(spi.getClass().getName(), spi);
256263
}
257264

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ public OtlpHttpLogRecordExporterBuilder setMemoryMode(MemoryMode memoryMode) {
225225
return this;
226226
}
227227

228+
/** Set the {@link ClassLoader} used to load the sender API. */
229+
public OtlpHttpLogRecordExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
230+
requireNonNull(serviceClassLoader, "serviceClassLoader");
231+
delegate.setServiceClassLoader(serviceClassLoader);
232+
return this;
233+
}
234+
228235
/**
229236
* Constructs a new instance of the exporter based on the builder's values.
230237
*

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ public OtlpHttpMetricExporterBuilder setMemoryMode(MemoryMode memoryMode) {
253253
return this;
254254
}
255255

256+
/** Set the {@link ClassLoader} used to load the sender API. */
257+
public OtlpHttpMetricExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
258+
requireNonNull(serviceClassLoader, "serviceClassLoader");
259+
delegate.setServiceClassLoader(serviceClassLoader);
260+
return this;
261+
}
262+
256263
OtlpHttpMetricExporterBuilder exportAsJson() {
257264
delegate.exportAsJson();
258265
return this;

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ public OtlpHttpSpanExporterBuilder setMemoryMode(MemoryMode memoryMode) {
226226
return this;
227227
}
228228

229+
/** Set the {@link ClassLoader} used to load the sender API. */
230+
public OtlpHttpSpanExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
231+
requireNonNull(serviceClassLoader, "serviceClassLoader");
232+
delegate.setServiceClassLoader(serviceClassLoader);
233+
return this;
234+
}
235+
229236
/**
230237
* Constructs a new instance of the exporter based on the builder's values.
231238
*

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ public OtlpGrpcLogRecordExporterBuilder setMemoryMode(MemoryMode memoryMode) {
258258
return this;
259259
}
260260

261+
/** Set the {@link ClassLoader} used to load the sender API. */
262+
public OtlpGrpcLogRecordExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
263+
requireNonNull(serviceClassLoader, "serviceClassLoader");
264+
delegate.setServiceClassLoader(serviceClassLoader);
265+
return this;
266+
}
267+
261268
/**
262269
* Constructs a new instance of the exporter based on the builder's values.
263270
*

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,13 @@ public OtlpGrpcMetricExporterBuilder setMemoryMode(MemoryMode memoryMode) {
286286
return this;
287287
}
288288

289+
/** Set the {@link ClassLoader} used to load the sender API. */
290+
public OtlpGrpcMetricExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
291+
requireNonNull(serviceClassLoader, "serviceClassLoader");
292+
delegate.setServiceClassLoader(serviceClassLoader);
293+
return this;
294+
}
295+
289296
/**
290297
* Constructs a new instance of the exporter based on the builder's values.
291298
*

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporterBuilder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ public OtlpGrpcSpanExporterBuilder setMemoryMode(MemoryMode memoryMode) {
255255
return this;
256256
}
257257

258+
/** Set the {@link ClassLoader} used to load the sender API. */
259+
public OtlpGrpcSpanExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
260+
requireNonNull(serviceClassLoader, "serviceClassLoader");
261+
delegate.setServiceClassLoader(serviceClassLoader);
262+
return this;
263+
}
264+
258265
/**
259266
* Constructs a new instance of the exporter based on the builder's values.
260267
*

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@
4747
import java.io.IOException;
4848
import java.io.UncheckedIOException;
4949
import java.lang.reflect.Field;
50+
import java.net.URL;
5051
import java.nio.charset.StandardCharsets;
5152
import java.nio.file.Files;
5253
import java.security.cert.CertificateEncodingException;
5354
import java.time.Duration;
5455
import java.util.ArrayList;
5556
import java.util.Arrays;
5657
import java.util.Collections;
58+
import java.util.Enumeration;
5759
import java.util.List;
5860
import java.util.concurrent.CompletableFuture;
5961
import java.util.concurrent.CompletionStage;
@@ -872,6 +874,39 @@ void validConfig() {
872874
.doesNotThrowAnyException();
873875
}
874876

877+
@Test
878+
void customServiceClassLoader() {
879+
ClassLoaderSpy classLoaderSpy =
880+
new ClassLoaderSpy(AbstractHttpTelemetryExporterTest.class.getClassLoader());
881+
882+
TelemetryExporter<T> exporter =
883+
exporterBuilder()
884+
.setServiceClassLoader(classLoaderSpy)
885+
.setEndpoint(server.httpUri().toString())
886+
.build();
887+
888+
assertThat(classLoaderSpy.getResourcesNames)
889+
.isEqualTo(
890+
Collections.singletonList(
891+
"META-INF/services/io.opentelemetry.exporter.internal.grpc.GrpcSenderProvider"));
892+
893+
exporter.shutdown();
894+
}
895+
896+
private static class ClassLoaderSpy extends ClassLoader {
897+
private final List<String> getResourcesNames = new ArrayList<>();
898+
899+
private ClassLoaderSpy(ClassLoader delegate) {
900+
super(delegate);
901+
}
902+
903+
@Override
904+
public Enumeration<URL> getResources(String name) throws IOException {
905+
getResourcesNames.add(name);
906+
return super.getResources(name);
907+
}
908+
}
909+
875910
private void buildAndShutdown(TelemetryExporterBuilder<T> builder) {
876911
TelemetryExporter<T> build = builder.build();
877912
build.shutdown().join(10, TimeUnit.MILLISECONDS);

0 commit comments

Comments
 (0)