Skip to content

Commit e47c318

Browse files
committed
Preserve OTLP resource attribute types
1 parent 325a854 commit e47c318

5 files changed

Lines changed: 65 additions & 68 deletions

File tree

‎dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpResourceAttributes.java‎

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import datadog.trace.api.Config;
77
import datadog.trace.api.ProcessTags;
8+
import java.util.Collections;
89
import java.util.HashSet;
910
import java.util.LinkedHashMap;
1011
import java.util.List;
@@ -36,43 +37,46 @@ private OtlpResourceAttributes() {}
3637
"telemetry.sdk.version",
3738
"telemetry.sdk.language"));
3839

39-
/**
40-
* {@code value} is a {@link String}, except {@code datadog.process_tags}: a {@code List<String>}.
41-
*/
4240
static void visitResourceAttributes(
43-
Config config, Map<String, Object> extraAttributes, BiConsumer<String, Object> visitor) {
41+
Config config,
42+
ExtraAttributes extraAttributes,
43+
BiConsumer<String, String> stringVisitor,
44+
BiConsumer<String, List<String>> stringArrayVisitor) {
4445
String serviceName = config.getServiceName();
4546
String env = config.getEnv();
4647
String version = config.getVersion();
4748

48-
visitor.accept("service.name", serviceName);
49+
stringVisitor.accept("service.name", serviceName);
4950
if (!env.isEmpty()) {
50-
visitor.accept("deployment.environment.name", env);
51+
stringVisitor.accept("deployment.environment.name", env);
5152
}
5253
if (!version.isEmpty()) {
53-
visitor.accept("service.version", version);
54+
stringVisitor.accept("service.version", version);
5455
}
5556
if (config.isReportHostName()) {
5657
String hostName = config.getHostName();
5758
if (hostName != null && !hostName.isEmpty()) {
58-
visitor.accept("host.name", hostName);
59+
stringVisitor.accept("host.name", hostName);
5960
}
6061
}
61-
visitor.accept("telemetry.sdk.name", "datadog");
62-
visitor.accept("telemetry.sdk.version", TRACER_VERSION);
63-
visitor.accept("telemetry.sdk.language", "java");
62+
stringVisitor.accept("telemetry.sdk.name", "datadog");
63+
stringVisitor.accept("telemetry.sdk.version", TRACER_VERSION);
64+
stringVisitor.accept("telemetry.sdk.language", "java");
6465

6566
config
6667
.getGlobalTags()
6768
.forEach(
6869
(key, value) -> {
6970
// ignore datadog tags and their otel equivalents that we map above
7071
if (!IGNORED_GLOBAL_TAGS.contains(key.toLowerCase(Locale.ROOT))) {
71-
visitor.accept(key, value);
72+
stringVisitor.accept(key, value);
7273
}
7374
});
7475

75-
extraAttributes.forEach(visitor);
76+
extraAttributes.stringAttributes.forEach(stringVisitor);
77+
if (!extraAttributes.processTags.isEmpty()) {
78+
stringArrayVisitor.accept(PROCESS_TAGS_KEY, extraAttributes.processTags);
79+
}
7680
}
7781

7882
private static final String PROCESS_TAGS_KEY = DATADOG_PREFIX + "process_tags";
@@ -82,25 +86,38 @@ static void visitResourceAttributes(
8286
* marker when the SDK is computing OTLP span metrics, so a downstream Agent does not recompute
8387
* them from the exported spans.
8488
*/
85-
static Map<String, Object> traceResourceAttributes(Config config) {
86-
Map<String, Object> attributes = new LinkedHashMap<>();
89+
static ExtraAttributes traceResourceAttributes(Config config) {
90+
Map<String, String> attributes = new LinkedHashMap<>();
8791
if (config.isOtelTracesSpanMetricsEnabled()) {
8892
attributes.put(STATS_COMPUTED_KEY, "true");
8993
}
90-
return attributes;
94+
return new ExtraAttributes(attributes, Collections.emptyList());
9195
}
9296

93-
static Map<String, Object> datadogResourceAttributes(Config config) {
94-
Map<String, Object> attributes = new LinkedHashMap<>();
97+
static ExtraAttributes datadogResourceAttributes(Config config) {
98+
Map<String, String> attributes = new LinkedHashMap<>();
9599
String runtimeId = config.getRuntimeId();
96100
if (runtimeId != null && !runtimeId.isEmpty()) {
97101
attributes.put(DATADOG_PREFIX + "runtime_id", runtimeId);
98102
}
99103
// Mirrors SerializingMetricWriter's v0.6 ProcessTags shape; keep both in sync if that changes.
100104
List<String> processTags = ProcessTags.getTagsAsStringList();
101105
if (processTags != null && !processTags.isEmpty()) {
102-
attributes.put(PROCESS_TAGS_KEY, processTags);
106+
return new ExtraAttributes(attributes, processTags);
107+
}
108+
return new ExtraAttributes(attributes, Collections.emptyList());
109+
}
110+
111+
static final class ExtraAttributes {
112+
static final ExtraAttributes EMPTY =
113+
new ExtraAttributes(Collections.emptyMap(), Collections.emptyList());
114+
115+
private final Map<String, String> stringAttributes;
116+
private final List<String> processTags;
117+
118+
private ExtraAttributes(Map<String, String> stringAttributes, List<String> processTags) {
119+
this.stringAttributes = stringAttributes;
120+
this.processTags = processTags;
103121
}
104-
return attributes;
105122
}
106123
}

‎dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpResourceJson.java‎

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,21 @@
33
import static datadog.trace.bootstrap.otlp.common.OtlpAttributeVisitor.STRING_ARRAY_ATTRIBUTE;
44
import static datadog.trace.bootstrap.otlp.common.OtlpAttributeVisitor.STRING_ATTRIBUTE;
55
import static datadog.trace.core.otlp.common.OtlpCommonJson.writeAttribute;
6+
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes.EMPTY;
67
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.datadogResourceAttributes;
78
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.traceResourceAttributes;
89
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.visitResourceAttributes;
910

1011
import datadog.json.JsonWriter;
1112
import datadog.trace.api.Config;
12-
import java.util.Collections;
13-
import java.util.List;
14-
import java.util.Map;
13+
import datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes;
1514

1615
/** Provides a canned JSON fragment for OpenTelemetry's "resource.proto" JSON encoding. */
1716
public final class OtlpResourceJson {
1817
private OtlpResourceJson() {}
1918

2019
/** Vendor-neutral resource (no {@code datadog.*}). Used by the OTLP metric export. */
21-
public static final String RESOURCE_FRAGMENT =
22-
buildResourceFragment(Config.get(), Collections.emptyMap());
20+
public static final String RESOURCE_FRAGMENT = buildResourceFragment(Config.get(), EMPTY);
2321

2422
/**
2523
* Resource that additionally carries {@code datadog.runtime_id} and process tags (each prefixed
@@ -37,29 +35,20 @@ private OtlpResourceJson() {}
3735
public static final String TRACE_RESOURCE_FRAGMENT =
3836
buildResourceFragment(Config.get(), traceResourceAttributes(Config.get()));
3937

40-
static String buildResourceFragment(Config config, Map<String, Object> extraAttributes) {
38+
static String buildResourceFragment(Config config, ExtraAttributes extraAttributes) {
4139
try (JsonWriter writer = new JsonWriter()) {
4240
writer.beginObject();
4341
writer.name("attributes").beginArray();
4442

4543
visitResourceAttributes(
46-
config, extraAttributes, (key, value) -> writeResourceAttribute(writer, key, value));
44+
config,
45+
extraAttributes,
46+
(key, value) -> writeAttribute(writer, STRING_ATTRIBUTE, key, value),
47+
(key, value) -> writeAttribute(writer, STRING_ARRAY_ATTRIBUTE, key, value));
4748

4849
writer.endArray();
4950
writer.endObject();
5051
return writer.toString();
5152
}
5253
}
53-
54-
/**
55-
* {@code value} is a {@link String}, except {@code datadog.process_tags}: a {@code List<String>}.
56-
*/
57-
@SuppressWarnings("unchecked")
58-
private static void writeResourceAttribute(JsonWriter writer, String key, Object value) {
59-
if (value instanceof List) {
60-
writeAttribute(writer, STRING_ARRAY_ATTRIBUTE, key, (List<String>) value);
61-
} else {
62-
writeAttribute(writer, STRING_ATTRIBUTE, key, value);
63-
}
64-
}
6554
}

‎dd-trace-core/src/main/java/datadog/trace/core/otlp/common/OtlpResourceProto.java‎

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,21 @@
55
import static datadog.trace.core.otlp.common.OtlpCommonProto.LEN_WIRE_TYPE;
66
import static datadog.trace.core.otlp.common.OtlpCommonProto.writeAttribute;
77
import static datadog.trace.core.otlp.common.OtlpCommonProto.writeTag;
8+
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes.EMPTY;
89
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.datadogResourceAttributes;
910
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.traceResourceAttributes;
1011
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.visitResourceAttributes;
1112

1213
import datadog.communication.serialization.GrowableBuffer;
13-
import datadog.communication.serialization.StreamingBuffer;
1414
import datadog.trace.api.Config;
15-
import java.util.Collections;
16-
import java.util.List;
17-
import java.util.Map;
15+
import datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes;
1816

1917
/** Provides a canned message for OpenTelemetry's "resource.proto" wire protocol. */
2018
public final class OtlpResourceProto {
2119
private OtlpResourceProto() {}
2220

2321
/** Vendor-neutral resource (no {@code datadog.*}). Used by the OTLP metric export. */
24-
public static final byte[] RESOURCE_MESSAGE =
25-
buildResourceMessage(Config.get(), Collections.emptyMap());
22+
public static final byte[] RESOURCE_MESSAGE = buildResourceMessage(Config.get(), EMPTY);
2623

2724
/**
2825
* Resource that additionally carries {@code datadog.runtime_id} and process tags (each prefixed
@@ -40,11 +37,20 @@ private OtlpResourceProto() {}
4037
public static final byte[] TRACE_RESOURCE_MESSAGE =
4138
buildResourceMessage(Config.get(), traceResourceAttributes(Config.get()));
4239

43-
static byte[] buildResourceMessage(Config config, Map<String, Object> extraAttributes) {
40+
static byte[] buildResourceMessage(Config config, ExtraAttributes extraAttributes) {
4441
GrowableBuffer buf = new GrowableBuffer(512);
4542

4643
visitResourceAttributes(
47-
config, extraAttributes, (key, value) -> writeResourceAttribute(buf, key, value));
44+
config,
45+
extraAttributes,
46+
(key, value) -> {
47+
writeTag(buf, 1, LEN_WIRE_TYPE);
48+
writeAttribute(buf, STRING_ATTRIBUTE, key, value);
49+
},
50+
(key, value) -> {
51+
writeTag(buf, 1, LEN_WIRE_TYPE);
52+
writeAttribute(buf, STRING_ARRAY_ATTRIBUTE, key, value);
53+
});
4854

4955
OtlpProtoBuffer protobuf = new OtlpProtoBuffer(buf.capacity());
5056
int numBytes = protobuf.recordMessage(buf, 1);
@@ -53,17 +59,4 @@ static byte[] buildResourceMessage(Config config, Map<String, Object> extraAttri
5359

5460
return resourceMessage;
5561
}
56-
57-
/**
58-
* {@code value} is a {@link String}, except {@code datadog.process_tags}: a {@code List<String>}.
59-
*/
60-
@SuppressWarnings("unchecked")
61-
private static void writeResourceAttribute(StreamingBuffer buf, String key, Object value) {
62-
writeTag(buf, 1, LEN_WIRE_TYPE);
63-
if (value instanceof List) {
64-
writeAttribute(buf, STRING_ARRAY_ATTRIBUTE, key, (List<String>) value);
65-
} else {
66-
writeAttribute(buf, STRING_ATTRIBUTE, key, value);
67-
}
68-
}
6962
}

‎dd-trace-core/src/test/java/datadog/trace/core/otlp/common/OtlpResourceJsonTest.java‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static datadog.trace.api.config.GeneralConfig.VERSION;
99
import static datadog.trace.api.config.OtlpConfig.OTEL_TRACES_SPAN_METRICS_ENABLED;
1010
import static datadog.trace.api.config.TracerConfig.TRACE_REPORT_HOSTNAME;
11+
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes.EMPTY;
1112
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.datadogResourceAttributes;
1213
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.traceResourceAttributes;
1314
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -19,7 +20,6 @@
1920
import datadog.trace.api.ProcessTags;
2021
import java.io.IOException;
2122
import java.util.ArrayList;
22-
import java.util.Collections;
2323
import java.util.LinkedHashMap;
2424
import java.util.List;
2525
import java.util.Map;
@@ -141,7 +141,7 @@ void testBuildResourceFragment(
141141
String caseName, Properties properties, Map<String, Object> expectedAttributes)
142142
throws IOException {
143143
Config config = Config.get(properties);
144-
String fragment = OtlpResourceJson.buildResourceFragment(config, Collections.emptyMap());
144+
String fragment = OtlpResourceJson.buildResourceFragment(config, EMPTY);
145145

146146
Map<String, Object> actualAttributes = parseResourceAttributes(fragment);
147147
assertEquals(expectedAttributes, actualAttributes, "For case: " + caseName);
@@ -156,8 +156,7 @@ void datadogResourceAttributesVariantCarriesRuntimeId() throws IOException {
156156
parseResourceAttributes(
157157
OtlpResourceJson.buildResourceFragment(config, datadogResourceAttributes(config)));
158158
Map<String, Object> plain =
159-
parseResourceAttributes(
160-
OtlpResourceJson.buildResourceFragment(config, Collections.emptyMap()));
159+
parseResourceAttributes(OtlpResourceJson.buildResourceFragment(config, EMPTY));
161160

162161
assertTrue(
163162
withDatadog.containsKey("datadog.runtime_id"),

‎dd-trace-core/src/test/java/datadog/trace/core/otlp/common/OtlpResourceProtoTest.java‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static datadog.trace.api.config.GeneralConfig.VERSION;
99
import static datadog.trace.api.config.OtlpConfig.OTEL_TRACES_SPAN_METRICS_ENABLED;
1010
import static datadog.trace.api.config.TracerConfig.TRACE_REPORT_HOSTNAME;
11+
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.ExtraAttributes.EMPTY;
1112
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.datadogResourceAttributes;
1213
import static datadog.trace.core.otlp.common.OtlpResourceAttributes.traceResourceAttributes;
1314
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -20,7 +21,6 @@
2021
import datadog.trace.api.ProcessTags;
2122
import java.io.IOException;
2223
import java.util.ArrayList;
23-
import java.util.Collections;
2424
import java.util.LinkedHashMap;
2525
import java.util.List;
2626
import java.util.Map;
@@ -163,7 +163,7 @@ void testBuildResourceMessage(
163163
String caseName, Properties properties, Map<String, Object> expectedAttributes)
164164
throws IOException {
165165
Config config = Config.get(properties);
166-
byte[] bytes = OtlpResourceProto.buildResourceMessage(config, Collections.emptyMap());
166+
byte[] bytes = OtlpResourceProto.buildResourceMessage(config, EMPTY);
167167

168168
Map<String, Object> actualAttributes = parseResourceAttributes(bytes);
169169
assertEquals(expectedAttributes, actualAttributes, "For case: " + caseName);
@@ -181,8 +181,7 @@ void datadogResourceAttributesVariantCarriesRuntimeId() throws IOException {
181181
parseResourceAttributes(
182182
OtlpResourceProto.buildResourceMessage(config, datadogResourceAttributes(config)));
183183
Map<String, Object> plain =
184-
parseResourceAttributes(
185-
OtlpResourceProto.buildResourceMessage(config, Collections.emptyMap()));
184+
parseResourceAttributes(OtlpResourceProto.buildResourceMessage(config, EMPTY));
186185

187186
assertTrue(
188187
withDatadog.containsKey("datadog.runtime_id"),

0 commit comments

Comments
 (0)