Skip to content

Commit 0cd6af7

Browse files
committed
moving the compression setter to lower level api and modifying the exporters as per feedback
1 parent f89edd9 commit 0cd6af7

12 files changed

Lines changed: 277 additions & 70 deletions

File tree

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package io.opentelemetry.exporter.internal.grpc;
77

8+
import static java.util.Objects.requireNonNull;
9+
810
import io.grpc.Channel;
911
import io.grpc.ManagedChannel;
1012
import io.opentelemetry.api.GlobalOpenTelemetry;
@@ -13,6 +15,7 @@
1315
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
1416
import io.opentelemetry.exporter.internal.TlsConfigHelper;
1517
import io.opentelemetry.exporter.internal.compression.Compressor;
18+
import io.opentelemetry.exporter.internal.compression.CompressorUtil;
1619
import io.opentelemetry.exporter.internal.marshal.Marshaler;
1720
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
1821
import io.opentelemetry.sdk.common.export.RetryPolicy;
@@ -115,6 +118,18 @@ public GrpcExporterBuilder<T> setCompression(@Nullable Compressor compressor) {
115118
return this;
116119
}
117120

121+
/**
122+
* Sets the method used to compress payloads. If unset, compression is disabled. Compression
123+
* method "gzip" and "none" are supported out of the box. Support for additional compression
124+
* methods is available by implementing {@link Compressor} and {@link CompressorProvider}.
125+
*/
126+
public GrpcExporterBuilder<T> setCompression(String compressionMethod) {
127+
requireNonNull(compressionMethod, "compressionMethod");
128+
Compressor compressor =
129+
CompressorUtil.validateAndResolveCompressor(compressionMethod, serviceClassLoader);
130+
return setCompression(compressor);
131+
}
132+
118133
public GrpcExporterBuilder<T> setTrustManagerFromCerts(byte[] trustedCertificatesPem) {
119134
tlsConfigHelper.setTrustManagerFromCerts(trustedCertificatesPem);
120135
return this;
@@ -158,8 +173,8 @@ public GrpcExporterBuilder<T> setInternalTelemetryVersion(
158173
return this;
159174
}
160175

161-
public GrpcExporterBuilder<T> setServiceClassLoader(ClassLoader servieClassLoader) {
162-
this.serviceClassLoader = servieClassLoader;
176+
public GrpcExporterBuilder<T> setServiceClassLoader(ClassLoader serviceClassLoader) {
177+
this.serviceClassLoader = serviceClassLoader;
163178
return this;
164179
}
165180

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
package io.opentelemetry.exporter.internal.http;
77

8+
import static java.util.Objects.requireNonNull;
9+
810
import io.opentelemetry.api.GlobalOpenTelemetry;
911
import io.opentelemetry.api.internal.ConfigUtil;
1012
import io.opentelemetry.api.metrics.MeterProvider;
1113
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
1214
import io.opentelemetry.exporter.internal.TlsConfigHelper;
1315
import io.opentelemetry.exporter.internal.compression.Compressor;
16+
import io.opentelemetry.exporter.internal.compression.CompressorUtil;
1417
import io.opentelemetry.exporter.internal.marshal.Marshaler;
1518
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
1619
import io.opentelemetry.sdk.common.export.ProxyOptions;
@@ -95,6 +98,18 @@ public HttpExporterBuilder<T> setCompression(@Nullable Compressor compressor) {
9598
return this;
9699
}
97100

101+
/**
102+
* Sets the method used to compress payloads. If unset, compression is disabled. Compression
103+
* method "gzip" and "none" are supported out of the box. Support for additional compression
104+
* methods is available by implementing {@link Compressor} and {@link CompressorProvider}.
105+
*/
106+
public HttpExporterBuilder<T> setCompression(String compressionMethod) {
107+
requireNonNull(compressionMethod, "compressionMethod");
108+
Compressor compressor =
109+
CompressorUtil.validateAndResolveCompressor(compressionMethod, serviceClassLoader);
110+
return setCompression(compressor);
111+
}
112+
98113
public HttpExporterBuilder<T> addConstantHeaders(String key, String value) {
99114
constantHeaders.put(key, value);
100115
return this;
@@ -143,8 +158,8 @@ public HttpExporterBuilder<T> setProxyOptions(ProxyOptions proxyOptions) {
143158
return this;
144159
}
145160

146-
public HttpExporterBuilder<T> setServiceClassLoader(ClassLoader servieClassLoader) {
147-
this.serviceClassLoader = servieClassLoader;
161+
public HttpExporterBuilder<T> setServiceClassLoader(ClassLoader serviceClassLoader) {
162+
this.serviceClassLoader = serviceClassLoader;
148163
return this;
149164
}
150165

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.internal.compression;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
11+
import java.net.URL;
12+
import java.net.URLClassLoader;
13+
import org.junit.jupiter.api.Test;
14+
15+
class CompressorUtilTest {
16+
17+
@Test
18+
void validateAndResolveCompressor_none() {
19+
assertThat(CompressorUtil.validateAndResolveCompressor("none")).isNull();
20+
}
21+
22+
@Test
23+
void validateAndResolveCompressor_gzip() {
24+
assertThat(CompressorUtil.validateAndResolveCompressor("gzip"))
25+
.isEqualTo(GzipCompressor.getInstance());
26+
}
27+
28+
@Test
29+
void validateAndResolveCompressor_invalid() {
30+
assertThatThrownBy(() -> CompressorUtil.validateAndResolveCompressor("invalid"))
31+
.isInstanceOf(IllegalArgumentException.class)
32+
.hasMessageContaining("Unsupported compressionMethod");
33+
}
34+
35+
@Test
36+
void validateAndResolveCompressor_withClassLoader_none() {
37+
ClassLoader classLoader = CompressorUtilTest.class.getClassLoader();
38+
assertThat(CompressorUtil.validateAndResolveCompressor("none", classLoader)).isNull();
39+
}
40+
41+
@Test
42+
void validateAndResolveCompressor_withClassLoader_gzip() {
43+
ClassLoader classLoader = CompressorUtilTest.class.getClassLoader();
44+
assertThat(CompressorUtil.validateAndResolveCompressor("gzip", classLoader))
45+
.isEqualTo(GzipCompressor.getInstance());
46+
}
47+
48+
@Test
49+
void validateAndResolveCompressor_withClassLoader_invalid() {
50+
ClassLoader classLoader = CompressorUtilTest.class.getClassLoader();
51+
assertThatThrownBy(() -> CompressorUtil.validateAndResolveCompressor("invalid", classLoader))
52+
.isInstanceOf(IllegalArgumentException.class)
53+
.hasMessageContaining("Unsupported compressionMethod");
54+
}
55+
56+
@Test
57+
void validateAndResolveCompressor_emptyClassLoader() {
58+
// Create a class loader that cannot load CompressorProvider services
59+
ClassLoader emptyClassLoader = new URLClassLoader(new URL[0], null);
60+
61+
// Gzip should still work because it's hardcoded
62+
assertThat(CompressorUtil.validateAndResolveCompressor("gzip", emptyClassLoader))
63+
.isEqualTo(GzipCompressor.getInstance());
64+
65+
// None should still work because it doesn't require loading services
66+
assertThat(CompressorUtil.validateAndResolveCompressor("none", emptyClassLoader)).isNull();
67+
68+
// Any SPI-based compressor should not be available
69+
assertThatThrownBy(
70+
() -> CompressorUtil.validateAndResolveCompressor("base64", emptyClassLoader))
71+
.isInstanceOf(IllegalArgumentException.class)
72+
.hasMessageContaining("Unsupported compressionMethod");
73+
}
74+
75+
@Test
76+
void validateAndResolveCompressor_delegatesCorrectly() {
77+
// Test that single-parameter method delegates to two-parameter method
78+
assertThat(CompressorUtil.validateAndResolveCompressor("gzip"))
79+
.isEqualTo(
80+
CompressorUtil.validateAndResolveCompressor(
81+
"gzip", CompressorUtil.class.getClassLoader()));
82+
83+
assertThat(CompressorUtil.validateAndResolveCompressor("none"))
84+
.isEqualTo(
85+
CompressorUtil.validateAndResolveCompressor(
86+
"none", CompressorUtil.class.getClassLoader()));
87+
}
88+
}

exporters/common/src/test/java/io/opentelemetry/exporter/internal/grpc/GrpcExporterBuilderTest.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
package io.opentelemetry.exporter.internal.grpc;
77

88
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
910

11+
import io.opentelemetry.exporter.internal.compression.Compressor;
1012
import io.opentelemetry.exporter.internal.compression.GzipCompressor;
1113
import io.opentelemetry.exporter.internal.marshal.Marshaler;
1214
import io.opentelemetry.sdk.internal.StandardComponentId;
1315
import java.net.URI;
16+
import java.net.URL;
17+
import java.net.URLClassLoader;
1418
import org.junit.jupiter.api.BeforeEach;
1519
import org.junit.jupiter.api.Test;
1620

@@ -36,7 +40,7 @@ void compressionDefault() {
3640

3741
@Test
3842
void compressionNone() {
39-
builder.setCompression(null);
43+
builder.setCompression((Compressor) null);
4044

4145
assertThat(builder).extracting("compressor").isNull();
4246
}
@@ -50,8 +54,44 @@ void compressionGzip() {
5054

5155
@Test
5256
void compressionEnabledAndDisabled() {
53-
builder.setCompression(GzipCompressor.getInstance()).setCompression(null);
57+
builder.setCompression(GzipCompressor.getInstance()).setCompression((Compressor) null);
5458

5559
assertThat(builder).extracting("compressor").isNull();
5660
}
61+
62+
@Test
63+
void compressionString_none() {
64+
builder.setCompression("none");
65+
66+
assertThat(builder).extracting("compressor").isNull();
67+
}
68+
69+
@Test
70+
void compressionString_gzip() {
71+
builder.setCompression("gzip");
72+
73+
assertThat(builder).extracting("compressor").isEqualTo(GzipCompressor.getInstance());
74+
}
75+
76+
@Test
77+
void compressionString_invalid() {
78+
assertThatThrownBy(() -> builder.setCompression("invalid-compression"))
79+
.isInstanceOf(IllegalArgumentException.class)
80+
.hasMessageContaining("Unsupported compressionMethod");
81+
}
82+
83+
@Test
84+
void compressionString_usesServiceClassLoader() {
85+
// Create a class loader that cannot load CompressorProvider services
86+
ClassLoader emptyClassLoader = new URLClassLoader(new URL[0], null);
87+
builder.setServiceClassLoader(emptyClassLoader);
88+
89+
// This should still work because gzip compressor is hardcoded
90+
builder.setCompression("gzip");
91+
assertThat(builder).extracting("compressor").isEqualTo(GzipCompressor.getInstance());
92+
93+
// This should still work because "none" doesn't require loading services
94+
builder.setCompression("none");
95+
assertThat(builder).extracting("compressor").isNull();
96+
}
5797
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.internal.http;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
11+
import io.opentelemetry.exporter.internal.compression.Compressor;
12+
import io.opentelemetry.exporter.internal.compression.GzipCompressor;
13+
import io.opentelemetry.exporter.internal.marshal.Marshaler;
14+
import io.opentelemetry.sdk.internal.StandardComponentId;
15+
import java.net.URL;
16+
import java.net.URLClassLoader;
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.Test;
19+
20+
class HttpExporterBuilderTest {
21+
22+
private HttpExporterBuilder<Marshaler> builder;
23+
24+
@BeforeEach
25+
void setUp() {
26+
builder =
27+
new HttpExporterBuilder<>(
28+
StandardComponentId.ExporterType.OTLP_HTTP_SPAN_EXPORTER, "http://localhost:4318");
29+
}
30+
31+
@Test
32+
void compressionDefault() {
33+
assertThat(builder).extracting("compressor").isNull();
34+
}
35+
36+
@Test
37+
void compressionNone() {
38+
builder.setCompression((Compressor) null);
39+
40+
assertThat(builder).extracting("compressor").isNull();
41+
}
42+
43+
@Test
44+
void compressionGzip() {
45+
builder.setCompression(GzipCompressor.getInstance());
46+
47+
assertThat(builder).extracting("compressor").isEqualTo(GzipCompressor.getInstance());
48+
}
49+
50+
@Test
51+
void compressionEnabledAndDisabled() {
52+
builder.setCompression(GzipCompressor.getInstance()).setCompression((Compressor) null);
53+
54+
assertThat(builder).extracting("compressor").isNull();
55+
}
56+
57+
@Test
58+
void compressionString_none() {
59+
builder.setCompression("none");
60+
61+
assertThat(builder).extracting("compressor").isNull();
62+
}
63+
64+
@Test
65+
void compressionString_gzip() {
66+
builder.setCompression("gzip");
67+
68+
assertThat(builder).extracting("compressor").isEqualTo(GzipCompressor.getInstance());
69+
}
70+
71+
@Test
72+
void compressionString_invalid() {
73+
assertThatThrownBy(() -> builder.setCompression("invalid-compression"))
74+
.isInstanceOf(IllegalArgumentException.class)
75+
.hasMessageContaining("Unsupported compressionMethod");
76+
}
77+
78+
@Test
79+
void compressionString_usesServiceClassLoader() {
80+
// Create a class loader that cannot load CompressorProvider services
81+
ClassLoader emptyClassLoader = new URLClassLoader(new URL[0], null);
82+
builder.setServiceClassLoader(emptyClassLoader);
83+
84+
// This should still work because gzip compressor is hardcoded
85+
builder.setCompression("gzip");
86+
assertThat(builder).extracting("compressor").isEqualTo(GzipCompressor.getInstance());
87+
88+
// This should still work because "none" doesn't require loading services
89+
builder.setCompression("none");
90+
assertThat(builder).extracting("compressor").isNull();
91+
}
92+
}

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
import io.opentelemetry.api.GlobalOpenTelemetry;
1212
import io.opentelemetry.api.metrics.MeterProvider;
1313
import io.opentelemetry.exporter.internal.compression.Compressor;
14-
import io.opentelemetry.exporter.internal.compression.CompressorProvider;
15-
import io.opentelemetry.exporter.internal.compression.CompressorUtil;
1614
import io.opentelemetry.exporter.internal.http.HttpExporterBuilder;
1715
import io.opentelemetry.exporter.internal.marshal.Marshaler;
1816
import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent;
@@ -42,7 +40,6 @@ public final class OtlpHttpLogRecordExporterBuilder {
4240

4341
private final HttpExporterBuilder<Marshaler> delegate;
4442
private MemoryMode memoryMode;
45-
private ClassLoader serviceClassLoader = OtlpHttpLogRecordExporterBuilder.class.getClassLoader();
4643

4744
OtlpHttpLogRecordExporterBuilder(HttpExporterBuilder<Marshaler> delegate, MemoryMode memoryMode) {
4845
this.delegate = delegate;
@@ -113,14 +110,11 @@ public OtlpHttpLogRecordExporterBuilder setEndpoint(String endpoint) {
113110

114111
/**
115112
* Sets the method used to compress payloads. If unset, compression is disabled. Compression
116-
* method "gzip" and "none" are supported out of the box. Support for additional compression
117-
* methods is available by implementing {@link Compressor} and {@link CompressorProvider}.
113+
* method "gzip" and "none" are supported out of the box. Additional compression methods can be
114+
* supported by providing custom {@link Compressor} implementations via the service loader.
118115
*/
119116
public OtlpHttpLogRecordExporterBuilder setCompression(String compressionMethod) {
120-
requireNonNull(compressionMethod, "compressionMethod");
121-
Compressor compressor =
122-
CompressorUtil.validateAndResolveCompressor(compressionMethod, serviceClassLoader);
123-
delegate.setCompression(compressor);
117+
delegate.setCompression(compressionMethod);
124118
return this;
125119
}
126120

@@ -253,7 +247,6 @@ public OtlpHttpLogRecordExporterBuilder setMemoryMode(MemoryMode memoryMode) {
253247
*/
254248
public OtlpHttpLogRecordExporterBuilder setServiceClassLoader(ClassLoader serviceClassLoader) {
255249
requireNonNull(serviceClassLoader, "serviceClassLoader");
256-
this.serviceClassLoader = serviceClassLoader;
257250
delegate.setServiceClassLoader(serviceClassLoader);
258251
return this;
259252
}

0 commit comments

Comments
 (0)