Skip to content

Commit 2dbb8de

Browse files
authored
Update to opentelemetry-configuration v0.3.0 (#6733)
1 parent 697b4e0 commit 2dbb8de

File tree

26 files changed

+890
-438
lines changed

26 files changed

+890
-438
lines changed

dependencyManagement/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ val DEPENDENCIES = listOf(
6666
"eu.rekawek.toxiproxy:toxiproxy-java:2.1.7",
6767
"io.github.netmikey.logunit:logunit-jul:2.0.0",
6868
"io.jaegertracing:jaeger-client:1.8.1",
69-
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.29.0-alpha",
69+
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.39.0-alpha",
7070
"io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.27.0-alpha",
7171
"io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha",
7272
"io.opentracing:opentracing-api:0.33.0",

exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpConfigUtil.java

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
1111
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
1212
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
13+
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
1314
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
1415
import io.opentelemetry.sdk.common.export.MemoryMode;
1516
import io.opentelemetry.sdk.common.export.RetryPolicy;
@@ -27,6 +28,8 @@
2728
import java.net.URLDecoder;
2829
import java.nio.charset.StandardCharsets;
2930
import java.time.Duration;
31+
import java.util.Collections;
32+
import java.util.List;
3033
import java.util.Locale;
3134
import java.util.Map;
3235
import java.util.function.BiConsumer;
@@ -97,21 +100,7 @@ public static void configureOtlpExporterBuilder(
97100
setEndpoint.accept(endpoint.toString());
98101
}
99102

100-
Map<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
101-
if (headers.isEmpty()) {
102-
headers = config.getMap("otel.exporter.otlp.headers");
103-
}
104-
for (Map.Entry<String, String> entry : headers.entrySet()) {
105-
String key = entry.getKey();
106-
String value = entry.getValue();
107-
try {
108-
// headers are encoded as URL - see
109-
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables
110-
addHeader.accept(key, URLDecoder.decode(value, StandardCharsets.UTF_8.displayName()));
111-
} catch (Exception e) {
112-
throw new ConfigurationException("Cannot decode header value: " + value, e);
113-
}
114-
}
103+
configureOtlpHeaders(config, dataType, addHeader);
115104

116105
String compression = config.getString("otel.exporter.otlp." + dataType + ".compression");
117106
if (compression == null) {
@@ -190,29 +179,28 @@ public static void configureOtlpExporterBuilder(
190179
String protocol = getStructuredConfigOtlpProtocol(config);
191180
boolean isHttpProtobuf = protocol.equals(PROTOCOL_HTTP_PROTOBUF);
192181
URL endpoint = validateEndpoint(config.getString("endpoint"), isHttpProtobuf);
193-
if (endpoint != null && isHttpProtobuf) {
194-
String path = endpoint.getPath();
195-
if (!path.endsWith("/")) {
196-
path += "/";
197-
}
198-
path += signalPath(dataType);
199-
endpoint = createUrl(endpoint, path);
200-
}
201182
if (endpoint != null) {
202183
setEndpoint.accept(endpoint.toString());
203184
}
204185

205-
StructuredConfigProperties headers = config.getStructured("headers");
186+
String headerList = config.getString("headers_list");
187+
if (headerList != null) {
188+
ConfigProperties headersListConfig =
189+
DefaultConfigProperties.createFromMap(
190+
Collections.singletonMap("otel.exporter.otlp.headers", headerList));
191+
configureOtlpHeaders(headersListConfig, dataType, addHeader);
192+
}
193+
194+
List<StructuredConfigProperties> headers = config.getStructuredList("headers");
206195
if (headers != null) {
207-
headers
208-
.getPropertyKeys()
209-
.forEach(
210-
header -> {
211-
String value = headers.getString(header);
212-
if (value != null) {
213-
addHeader.accept(header, value);
214-
}
215-
});
196+
headers.forEach(
197+
header -> {
198+
String name = header.getString("name");
199+
String value = header.getString("value");
200+
if (name != null && value != null) {
201+
addHeader.accept(name, value);
202+
}
203+
});
216204
}
217205

218206
String compression = config.getString("compression");
@@ -249,6 +237,25 @@ public static void configureOtlpExporterBuilder(
249237
ExporterBuilderUtil.configureExporterMemoryMode(config, setMemoryMode);
250238
}
251239

240+
private static void configureOtlpHeaders(
241+
ConfigProperties config, String dataType, BiConsumer<String, String> addHeader) {
242+
Map<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
243+
if (headers.isEmpty()) {
244+
headers = config.getMap("otel.exporter.otlp.headers");
245+
}
246+
for (Map.Entry<String, String> entry : headers.entrySet()) {
247+
String key = entry.getKey();
248+
String value = entry.getValue();
249+
try {
250+
// headers are encoded as URL - see
251+
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables
252+
addHeader.accept(key, URLDecoder.decode(value, StandardCharsets.UTF_8.displayName()));
253+
} catch (Exception e) {
254+
throw new ConfigurationException("Cannot decode header value: " + value, e);
255+
}
256+
}
257+
}
258+
252259
/**
253260
* Invoke the {@code aggregationTemporalitySelectorConsumer} with the configured {@link
254261
* AggregationTemporality}.

sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/FileConfigurationTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ void configFile(@TempDir Path tempDir) throws IOException {
3434
"file_format: \"0.1\"\n"
3535
+ "resource:\n"
3636
+ " attributes:\n"
37-
+ " service.name: test\n"
37+
+ " - name: service.name\n"
38+
+ " value: test\n"
3839
+ "tracer_provider:\n"
3940
+ " processors:\n"
4041
+ " - simple:\n"

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ void setup() throws IOException {
5858
"file_format: \"0.1\"\n"
5959
+ "resource:\n"
6060
+ " attributes:\n"
61-
+ " service.name: test\n"
61+
+ " - name: service.name\n"
62+
+ " value: test\n"
6263
+ "tracer_provider:\n"
6364
+ " processors:\n"
6465
+ " - simple:\n"
@@ -162,7 +163,8 @@ void configFile_Error(@TempDir Path tempDir) throws IOException {
162163
"file_format: \"0.1\"\n"
163164
+ "resource:\n"
164165
+ " attributes:\n"
165-
+ " service.name: test\n"
166+
+ " - name: service.name\n"
167+
+ " value: test\n"
166168
+ "tracer_provider:\n"
167169
+ " processors:\n"
168170
+ " - simple:\n"

sdk-extensions/incubator/build.gradle.kts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,14 @@ dependencies {
4949
// The sequence of tasks is:
5050
// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration
5151
// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/
52-
// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
53-
// 4. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation
54-
// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
55-
// 6. deleteJs2pTmp - delete tmp directory
52+
// 3. deleteTypeDescriptions - delete type_descriptions.yaml $buildDir/configuration/schema, which is not part of core schema and causes problems resolving type refs
53+
// 4. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
54+
// 5. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation
55+
// 6. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
56+
// 7. deleteJs2pTmp - delete tmp directory
5657
// ... proceed with normal sourcesJar, compileJava, etc
5758

58-
val configurationTag = "0.1.0"
59+
val configurationTag = "0.3.0"
5960
val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit
6061
val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip"
6162
val buildDirectory = layout.buildDirectory.asFile.get()
@@ -78,6 +79,11 @@ val unzipConfigurationSchema by tasks.registering(Copy::class) {
7879
into("$buildDirectory/configuration/")
7980
}
8081

82+
val deleteTypeDescriptions by tasks.registering(Delete::class) {
83+
dependsOn(unzipConfigurationSchema)
84+
delete("$buildDirectory/configuration/schema/type_descriptions.yaml")
85+
}
86+
8187
jsonSchema2Pojo {
8288
sourceFiles = setOf(file("$buildDirectory/configuration/schema"))
8389
targetDirectory = file("$buildDirectory/generated/sources/js2p/java/main")
@@ -106,7 +112,7 @@ jsonSchema2Pojo {
106112
}
107113

108114
val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo")
109-
generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema)
115+
generateJsonSchema2Pojo.dependsOn(deleteTypeDescriptions)
110116

111117
val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) {
112118
dependsOn(generateJsonSchema2Pojo)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.extension.incubator.fileconfig;
7+
8+
import static java.util.stream.Collectors.toList;
9+
10+
import io.opentelemetry.api.common.AttributeKey;
11+
import io.opentelemetry.api.common.AttributesBuilder;
12+
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
13+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
14+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
15+
import java.io.Closeable;
16+
import java.util.List;
17+
import javax.annotation.Nullable;
18+
19+
final class AttributeListFactory
20+
implements Factory<List<AttributeNameValueModel>, io.opentelemetry.api.common.Attributes> {
21+
22+
private static final AttributeListFactory INSTANCE = new AttributeListFactory();
23+
24+
private AttributeListFactory() {}
25+
26+
static AttributeListFactory getInstance() {
27+
return INSTANCE;
28+
}
29+
30+
@Override
31+
public io.opentelemetry.api.common.Attributes create(
32+
List<AttributeNameValueModel> model, SpiHelper spiHelper, List<Closeable> closeables) {
33+
AttributesBuilder builder = io.opentelemetry.api.common.Attributes.builder();
34+
35+
for (AttributeNameValueModel nameValueModel : model) {
36+
addToBuilder(nameValueModel, builder);
37+
}
38+
39+
return builder.build();
40+
}
41+
42+
private static void addToBuilder(
43+
AttributeNameValueModel nameValueModel, AttributesBuilder builder) {
44+
String name = FileConfigUtil.requireNonNull(nameValueModel.getName(), "attribute name");
45+
Object value = FileConfigUtil.requireNonNull(nameValueModel.getValue(), "attribute value");
46+
AttributeNameValueModel.Type type = nameValueModel.getType();
47+
if (type == null) {
48+
type = AttributeNameValueModel.Type.STRING;
49+
}
50+
switch (type) {
51+
case STRING:
52+
if (value instanceof String) {
53+
builder.put(name, (String) value);
54+
return;
55+
}
56+
break;
57+
case BOOL:
58+
if (value instanceof Boolean) {
59+
builder.put(name, (boolean) value);
60+
return;
61+
}
62+
break;
63+
case INT:
64+
if ((value instanceof Integer) || (value instanceof Long)) {
65+
builder.put(name, ((Number) value).longValue());
66+
return;
67+
}
68+
break;
69+
case DOUBLE:
70+
if (value instanceof Number) {
71+
builder.put(name, ((Number) value).doubleValue());
72+
return;
73+
}
74+
break;
75+
case STRING_ARRAY:
76+
List<String> stringList = checkListOfType(value, String.class);
77+
if (stringList != null) {
78+
builder.put(AttributeKey.stringArrayKey(name), stringList);
79+
return;
80+
}
81+
break;
82+
case BOOL_ARRAY:
83+
List<Boolean> boolList = checkListOfType(value, Boolean.class);
84+
if (boolList != null) {
85+
builder.put(AttributeKey.booleanArrayKey(name), boolList);
86+
return;
87+
}
88+
break;
89+
case INT_ARRAY:
90+
List<Long> longList = checkListOfType(value, Long.class);
91+
if (longList != null) {
92+
builder.put(AttributeKey.longArrayKey(name), longList);
93+
return;
94+
}
95+
List<Integer> intList = checkListOfType(value, Integer.class);
96+
if (intList != null) {
97+
builder.put(
98+
AttributeKey.longArrayKey(name),
99+
intList.stream().map(i -> (long) i).collect(toList()));
100+
return;
101+
}
102+
break;
103+
case DOUBLE_ARRAY:
104+
List<Double> doubleList = checkListOfType(value, Double.class);
105+
if (doubleList != null) {
106+
builder.put(AttributeKey.doubleArrayKey(name), doubleList);
107+
return;
108+
}
109+
List<Float> floatList = checkListOfType(value, Float.class);
110+
if (floatList != null) {
111+
builder.put(
112+
AttributeKey.doubleArrayKey(name),
113+
floatList.stream().map(i -> (double) i).collect(toList()));
114+
return;
115+
}
116+
break;
117+
}
118+
throw new ConfigurationException(
119+
"Error processing attribute with name \""
120+
+ name
121+
+ "\": value did not match type "
122+
+ type.name());
123+
}
124+
125+
@SuppressWarnings("unchecked")
126+
@Nullable
127+
private static <T> List<T> checkListOfType(Object value, Class<T> expectedType) {
128+
if (!(value instanceof List)) {
129+
return null;
130+
}
131+
List<?> list = (List<?>) value;
132+
if (list.isEmpty()) {
133+
return null;
134+
}
135+
if (!list.stream().allMatch(entry -> expectedType.isAssignableFrom(entry.getClass()))) {
136+
return null;
137+
}
138+
return (List<T>) value;
139+
}
140+
}

0 commit comments

Comments
 (0)