Skip to content

Commit fd7c278

Browse files
authored
Add v0.4 trace decoder (DataDog#3309)
1 parent 181b51f commit fd7c278

8 files changed

Lines changed: 427 additions & 8 deletions

File tree

dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ abstract class AbstractSmokeTest extends ProcessManager {
3232
prefix("/v0.4/traces") {
3333
def countString = request.getHeader("X-Datadog-Trace-Count")
3434
int count = countString != null ? Integer.parseInt(countString) : 0
35+
def body = request.getBody()
36+
if (body.length && decode) {
37+
try {
38+
DecodedMessage message = Decoder.decodeV04(body)
39+
assert message.getTraces().size() == count
40+
def traces = message.traces
41+
decode(traces)
42+
decodeTraces.addAll(traces)
43+
} catch (Throwable t) {
44+
println("=== Failure during message v0.4 decoding ===")
45+
t.printStackTrace(System.out)
46+
throw t
47+
}
48+
}
3549
traceCount.addAndGet(count)
3650
println("Received v0.4 traces: " + countString)
3751
response.status(200).send()
@@ -48,7 +62,7 @@ abstract class AbstractSmokeTest extends ProcessManager {
4862
decode(traces)
4963
decodeTraces.addAll(traces)
5064
} catch (Throwable t) {
51-
println("=== Failure during message decoding ===")
65+
println("=== Failure during message v0.5 decoding ===")
5266
t.printStackTrace(System.out)
5367
throw t
5468
}

utils/test-agent-utils/decoder/decoder.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ targetCompatibility = JavaVersion.VERSION_1_7
55

66
ext {
77
minimumInstructionCoverage = 0.7
8-
excludedClassesCoverage = ['datadog.trace.test.agent.decoder.v05.raw.*',]
8+
excludedClassesCoverage = ['datadog.trace.test.agent.decoder.v04.raw.*', 'datadog.trace.test.agent.decoder.v05.raw.*',]
99
}
1010

1111
dependencies {

utils/test-agent-utils/decoder/src/main/java/datadog/trace/test/agent/decoder/Decoder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.trace.test.agent.decoder;
22

3+
import datadog.trace.test.agent.decoder.v04.raw.MessageV04;
34
import datadog.trace.test.agent.decoder.v05.raw.MessageV05;
45
import java.nio.ByteBuffer;
56
import java.util.Arrays;
@@ -16,6 +17,10 @@ public static DecodedMessage decode(byte[] buffer) {
1617
return MessageV05.unpack(buffer);
1718
}
1819

20+
public static DecodedMessage decodeV04(byte[] buffer) {
21+
return MessageV04.unpack(buffer);
22+
}
23+
1924
public static List<DecodedSpan> sortByStart(Collection<DecodedSpan> spans) {
2025
DecodedSpan[] spanArray = new DecodedSpan[spans.size()];
2126
spanArray = spans.toArray(spanArray);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package datadog.trace.test.agent.decoder.v04.raw;
2+
3+
import datadog.trace.test.agent.decoder.DecodedMessage;
4+
import datadog.trace.test.agent.decoder.DecodedTrace;
5+
import java.nio.ByteBuffer;
6+
import java.util.Arrays;
7+
import java.util.Collections;
8+
import java.util.List;
9+
import org.msgpack.core.MessagePack;
10+
import org.msgpack.core.MessageUnpacker;
11+
12+
public class MessageV04 implements DecodedMessage {
13+
public static MessageV04 unpack(ByteBuffer buffer) {
14+
return unpack(MessagePack.DEFAULT_UNPACKER_CONFIG.newUnpacker(buffer));
15+
}
16+
17+
public static MessageV04 unpack(byte[] buffer) {
18+
return unpack(MessagePack.DEFAULT_UNPACKER_CONFIG.newUnpacker(buffer));
19+
}
20+
21+
static MessageV04 unpack(MessageUnpacker unpacker) {
22+
try {
23+
DecodedTrace[] traces = TraceV04.unpackTraces(unpacker);
24+
return new MessageV04(traces);
25+
} catch (Throwable t) {
26+
if (t instanceof RuntimeException) {
27+
throw (RuntimeException) t;
28+
} else {
29+
throw new IllegalArgumentException(t);
30+
}
31+
}
32+
}
33+
34+
private final DecodedTrace[] traces;
35+
36+
private MessageV04(DecodedTrace[] traces) {
37+
this.traces = traces;
38+
}
39+
40+
@Override
41+
public List<DecodedTrace> getTraces() {
42+
if (traces.length == 0) {
43+
return Collections.emptyList();
44+
}
45+
return Collections.unmodifiableList(Arrays.asList(traces));
46+
}
47+
}
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
package datadog.trace.test.agent.decoder.v04.raw;
2+
3+
import datadog.trace.test.agent.decoder.DecodedSpan;
4+
import java.io.IOException;
5+
import java.util.Collections;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import org.msgpack.core.MessageIntegerOverflowException;
9+
import org.msgpack.core.MessageUnpacker;
10+
import org.msgpack.value.ValueType;
11+
12+
public class SpanV04 implements DecodedSpan {
13+
static DecodedSpan[] unpackSpans(MessageUnpacker unpacker) {
14+
try {
15+
int size = unpacker.unpackArrayHeader();
16+
if (size < 0) {
17+
throw new IllegalArgumentException("Negative span array size " + size);
18+
}
19+
DecodedSpan[] spans = new DecodedSpan[size];
20+
for (int i = 0; i < size; i++) {
21+
spans[i] = unpack(unpacker);
22+
}
23+
return spans;
24+
} catch (Throwable t) {
25+
if (t instanceof RuntimeException) {
26+
throw (RuntimeException) t;
27+
} else {
28+
throw new IllegalArgumentException(t);
29+
}
30+
}
31+
}
32+
33+
static SpanV04 unpack(MessageUnpacker unpacker) {
34+
try {
35+
int size = unpacker.unpackMapHeader();
36+
if (size != 12) {
37+
throw new IllegalArgumentException(
38+
"Wrong span element map size " + size + ". Expected 12.");
39+
}
40+
41+
String service = unpackString("service", unpacker);
42+
String name = unpackString("name", unpacker);
43+
String resource = unpackString("resource", unpacker);
44+
long traceId = unpackLong("trace_id", unpacker);
45+
long spanId = unpackLong("span_id", unpacker);
46+
long parentId = unpackLong("parent_id", unpacker);
47+
long start = unpackLong("start", unpacker);
48+
long duration = unpackLong("duration", unpacker);
49+
String type = unpackString("type", unpacker);
50+
int error = unpackInt("error", unpacker);
51+
52+
unpackKey("metrics", unpacker);
53+
Map<String, Number> metrics = unpackMetrics(unpacker, spanId);
54+
55+
unpackKey("meta", unpacker);
56+
Map<String, String> meta = unpackMeta(unpacker, spanId);
57+
58+
return new SpanV04(
59+
service, name, resource, traceId, spanId, parentId, start, duration, error, type, metrics,
60+
meta);
61+
} catch (Throwable t) {
62+
if (t instanceof RuntimeException) {
63+
throw (RuntimeException) t;
64+
} else {
65+
throw new IllegalArgumentException(t);
66+
}
67+
}
68+
}
69+
70+
private static Map<String, Number> unpackMetrics(MessageUnpacker unpacker, long spanId)
71+
throws IOException {
72+
int metricsSize = unpacker.unpackMapHeader();
73+
if (metricsSize < 0) {
74+
throw new IllegalArgumentException(
75+
"Negative meta map size " + metricsSize + " for span " + spanId);
76+
}
77+
Map<String, Number> metrics = new HashMap<>(metricsSize);
78+
for (int i = 0; i < metricsSize; i++) {
79+
metrics.put(unpacker.unpackString(), unpackNumber(unpacker));
80+
}
81+
return metrics;
82+
}
83+
84+
private static Map<String, String> unpackMeta(MessageUnpacker unpacker, long spanId)
85+
throws IOException {
86+
int metaSize = unpacker.unpackMapHeader();
87+
if (metaSize < 0) {
88+
throw new IllegalArgumentException(
89+
"Negative meta map size " + metaSize + " for span " + spanId);
90+
}
91+
Map<String, String> meta = new HashMap<>(metaSize);
92+
for (int i = 0; i < metaSize; i++) {
93+
meta.put(unpacker.unpackString(), unpacker.unpackString());
94+
}
95+
return meta;
96+
}
97+
98+
private static String unpackString(String expectedKey, MessageUnpacker unpacker)
99+
throws IOException {
100+
unpackKey(expectedKey, unpacker);
101+
return unpacker.unpackString();
102+
}
103+
104+
private static long unpackLong(String expectedKey, MessageUnpacker unpacker) throws IOException {
105+
unpackKey(expectedKey, unpacker);
106+
return unpacker.unpackLong();
107+
}
108+
109+
private static int unpackInt(String expectedKey, MessageUnpacker unpacker) throws IOException {
110+
unpackKey(expectedKey, unpacker);
111+
return unpacker.unpackInt();
112+
}
113+
114+
private static void unpackKey(String expectedKey, MessageUnpacker unpacker) throws IOException {
115+
assert expectedKey.equals(unpacker.unpackString());
116+
}
117+
118+
static Number unpackNumber(MessageUnpacker unpacker) {
119+
Number result = null;
120+
try {
121+
ValueType valueType = unpacker.getNextFormat().getValueType();
122+
switch (valueType) {
123+
case INTEGER:
124+
try {
125+
result = unpacker.unpackInt();
126+
} catch (MessageIntegerOverflowException e) {
127+
result = unpacker.unpackLong();
128+
}
129+
break;
130+
case FLOAT:
131+
result = unpacker.unpackDouble();
132+
break;
133+
default:
134+
throw new IllegalArgumentException(
135+
"Failed to decode number. Unexpected value type " + valueType);
136+
}
137+
} catch (IOException e) {
138+
throw new IllegalArgumentException("Failed to decode number.", e);
139+
}
140+
return result;
141+
}
142+
143+
private final String service;
144+
private final String name;
145+
private final String resource;
146+
private final long traceId;
147+
private final long spanId;
148+
private final long parentId;
149+
private final long start;
150+
private final long duration;
151+
private final int error;
152+
private final Map<String, String> meta;
153+
private final Map<String, Number> metrics;
154+
private final String type;
155+
156+
public SpanV04(
157+
String service,
158+
String name,
159+
String resource,
160+
long traceId,
161+
long spanId,
162+
long parentId,
163+
long start,
164+
long duration,
165+
int error,
166+
String type,
167+
Map<String, Number> metrics,
168+
Map<String, String> meta) {
169+
this.service = service;
170+
this.name = name;
171+
this.resource = resource;
172+
this.traceId = traceId;
173+
this.spanId = spanId;
174+
this.parentId = parentId;
175+
this.start = start;
176+
this.duration = duration;
177+
this.error = error;
178+
this.meta = Collections.unmodifiableMap(meta);
179+
this.metrics = Collections.unmodifiableMap(metrics);
180+
this.type = type;
181+
}
182+
183+
public String getService() {
184+
return service;
185+
}
186+
187+
public String getName() {
188+
return name;
189+
}
190+
191+
public String getResource() {
192+
return resource;
193+
}
194+
195+
public long getTraceId() {
196+
return traceId;
197+
}
198+
199+
public long getSpanId() {
200+
return spanId;
201+
}
202+
203+
public long getParentId() {
204+
return parentId;
205+
}
206+
207+
public long getStart() {
208+
return start;
209+
}
210+
211+
public long getDuration() {
212+
return duration;
213+
}
214+
215+
public int getError() {
216+
return error;
217+
}
218+
219+
public Map<String, String> getMeta() {
220+
return meta;
221+
}
222+
223+
public Map<String, Number> getMetrics() {
224+
return metrics;
225+
}
226+
227+
public String getType() {
228+
return type;
229+
}
230+
231+
@Override
232+
public String toString() {
233+
return "SpanV04{"
234+
+ "service='"
235+
+ service
236+
+ '\''
237+
+ ", name='"
238+
+ name
239+
+ '\''
240+
+ ", resource='"
241+
+ resource
242+
+ '\''
243+
+ ", traceId="
244+
+ traceId
245+
+ ", spanId="
246+
+ spanId
247+
+ ", parentId="
248+
+ parentId
249+
+ ", start="
250+
+ start
251+
+ ", duration="
252+
+ duration
253+
+ ", error="
254+
+ error
255+
+ ", meta="
256+
+ meta
257+
+ ", metrics="
258+
+ metrics
259+
+ ", type='"
260+
+ type
261+
+ '\''
262+
+ '}';
263+
}
264+
}

0 commit comments

Comments
 (0)