Skip to content

Commit e8fa456

Browse files
Refactored telemetry into separate class. Fixed review comments.
1 parent 324c8f6 commit e8fa456

File tree

2 files changed

+124
-97
lines changed

2 files changed

+124
-97
lines changed

dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java

Lines changed: 94 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package datadog.trace.bootstrap;
22

3+
import static java.util.Collections.emptyList;
4+
import static java.util.Collections.singletonList;
5+
36
import datadog.json.JsonWriter;
47
import datadog.trace.bootstrap.environment.EnvironmentVariables;
58
import de.thetaphi.forbiddenapis.SuppressForbidden;
69
import java.io.Closeable;
710
import java.io.OutputStream;
811
import java.util.ArrayList;
9-
import java.util.Arrays;
1012
import java.util.LinkedHashMap;
1113
import java.util.List;
1214
import java.util.Map;
@@ -93,37 +95,31 @@ public void finish() {}
9395
public static final class JsonBased extends BootstrapInitializationTelemetry {
9496
private final JsonSender sender;
9597

96-
private final Map<String, String> meta;
97-
private final Map<String, List<String>> points;
98+
private final Telemetry telemetry;
9899

99100
// one way false to true
100101
private volatile boolean incomplete = false;
101102

102103
JsonBased(JsonSender sender) {
103104
this.sender = sender;
104-
this.meta = new LinkedHashMap<>();
105-
this.points = new LinkedHashMap<>();
106-
107-
setMetaInfo("success", "success", "Successfully configured ddtrace package");
105+
this.telemetry = new Telemetry();
108106
}
109107

110108
@Override
111109
public void initMetaInfo(String attr, String value) {
112-
synchronized (this.meta) {
113-
this.meta.put(attr, value);
114-
}
110+
telemetry.setMetadata(attr, value);
115111
}
116112

117113
@Override
118114
public void onAbort(String reasonCode) {
119-
onPoint("library_entrypoint.abort", "reason:" + reasonCode);
115+
onPoint("library_entrypoint.abort", singletonList("reason:" + reasonCode));
120116
markIncomplete();
121-
setMetaInfo("abort", mapResultClass(reasonCode), reasonCode);
117+
setResultMeta("abort", mapResultClass(reasonCode), reasonCode);
122118
}
123119

124120
@Override
125121
public void onError(Throwable t) {
126-
setMetaInfo("error", "internal_error", t.getMessage());
122+
setResultMeta("error", "internal_error", t.getMessage());
127123

128124
List<String> causes = new ArrayList<>();
129125

@@ -141,13 +137,13 @@ public void onError(Throwable t) {
141137
causes = causes.subList(numCauses - maxTags, numCauses);
142138
}
143139

144-
onPoint("library_entrypoint.error", causes.toArray(new String[0]));
140+
onPoint("library_entrypoint.error", causes);
145141
}
146142

147143
@Override
148144
public void onError(String reasonCode) {
149-
onPoint("library_entrypoint.error", "error_type:" + reasonCode);
150-
setMetaInfo("error", mapResultClass(reasonCode), reasonCode);
145+
onPoint("library_entrypoint.error", singletonList("error_type:" + reasonCode));
146+
setResultMeta("error", mapResultClass(reasonCode), reasonCode);
151147
}
152148

153149
private int maxTags() {
@@ -170,7 +166,7 @@ public void onFatalError(Throwable t) {
170166
markIncomplete();
171167
}
172168

173-
private void setMetaInfo(String result, String resultClass, String resultReason) {
169+
private void setResultMeta(String result, String resultClass, String resultReason) {
174170
initMetaInfo("result", result);
175171
initMetaInfo("result_class", resultClass);
176172
initMetaInfo("result_reason", resultReason);
@@ -193,10 +189,8 @@ private String mapResultClass(String reasonCode) {
193189
}
194190
}
195191

196-
private void onPoint(String name, String... tags) {
197-
synchronized (this.points) {
198-
this.points.put(name, Arrays.asList(tags));
199-
}
192+
private void onPoint(String name, List<String> tags) {
193+
telemetry.addPoint(name, tags);
200194
}
201195

202196
@Override
@@ -207,15 +201,85 @@ public void markIncomplete() {
207201
@Override
208202
public void finish() {
209203
if (!this.incomplete) {
210-
onPoint("library_entrypoint.complete");
204+
onPoint("library_entrypoint.complete", emptyList());
211205
}
212206

213-
this.sender.send(meta, points);
207+
this.sender.send(telemetry);
208+
}
209+
}
210+
211+
public static class Telemetry {
212+
private final Map<String, String> metadata;
213+
private final Map<String, List<String>> points;
214+
215+
public Telemetry() {
216+
metadata = new LinkedHashMap<>();
217+
points = new LinkedHashMap<>();
218+
219+
setResults("success", "success", "Successfully configured ddtrace package");
220+
}
221+
222+
public void setMetadata(String name, String value) {
223+
synchronized (metadata) {
224+
metadata.put(name, value);
225+
}
226+
}
227+
228+
public void setResults(String result, String resultClass, String resultReason) {
229+
synchronized (metadata) {
230+
metadata.put("result", result);
231+
metadata.put("result_class", resultClass);
232+
metadata.put("result_reason", resultReason);
233+
}
234+
}
235+
236+
public void addPoint(String name, List<String> tags) {
237+
synchronized (points) {
238+
points.put(name, tags);
239+
}
240+
}
241+
242+
public byte[] json() {
243+
try (JsonWriter writer = new JsonWriter()) {
244+
writer.beginObject();
245+
writer.name("metadata").beginObject();
246+
synchronized (metadata) {
247+
for (Map.Entry<String, String> entry : metadata.entrySet()) {
248+
writer.name(entry.getKey());
249+
writer.value(entry.getValue());
250+
}
251+
252+
metadata.clear();
253+
}
254+
writer.endObject();
255+
256+
writer.name("points").beginArray();
257+
synchronized (points) {
258+
for (Map.Entry<String, List<String>> entry : points.entrySet()) {
259+
writer.beginObject();
260+
writer.name("name").value(entry.getKey());
261+
if (!entry.getValue().isEmpty()) {
262+
writer.name("tags").beginArray();
263+
for (String tag : entry.getValue()) {
264+
writer.value(tag);
265+
}
266+
writer.endArray();
267+
}
268+
writer.endObject();
269+
}
270+
271+
points.clear();
272+
}
273+
writer.endArray();
274+
writer.endObject();
275+
276+
return writer.toByteArray();
277+
}
214278
}
215279
}
216280

217281
public interface JsonSender {
218-
void send(Map<String, String> meta, Map<String, List<String>> points);
282+
void send(Telemetry telemetry);
219283
}
220284

221285
public static final class ForwarderJsonSender implements JsonSender {
@@ -226,24 +290,21 @@ public static final class ForwarderJsonSender implements JsonSender {
226290
}
227291

228292
@Override
229-
public void send(Map<String, String> meta, Map<String, List<String>> points) {
230-
ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, meta, points);
293+
public void send(Telemetry telemetry) {
294+
ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, telemetry);
231295
t.setDaemon(true);
232296
t.start();
233297
}
234298
}
235299

236300
public static final class ForwarderJsonSenderThread extends Thread {
237301
private final String forwarderPath;
238-
private final Map<String, String> meta;
239-
private final Map<String, List<String>> points;
302+
private final Telemetry telemetry;
240303

241-
public ForwarderJsonSenderThread(
242-
String forwarderPath, Map<String, String> meta, Map<String, List<String>> points) {
304+
public ForwarderJsonSenderThread(String forwarderPath, Telemetry telemetry) {
243305
super("dd-forwarder-json-sender");
244306
this.forwarderPath = forwarderPath;
245-
this.meta = meta;
246-
this.points = points;
307+
this.telemetry = telemetry;
247308
}
248309

249310
@SuppressForbidden
@@ -253,7 +314,7 @@ public void run() {
253314

254315
// Run forwarder and mute tracing for subprocesses executed in by dd-java-agent.
255316
try (final Closeable ignored = muteTracing()) {
256-
byte[] payload = json();
317+
byte[] payload = telemetry.json();
257318

258319
Process process = builder.start();
259320
try (OutputStream out = process.getOutputStream()) {
@@ -265,39 +326,6 @@ public void run() {
265326
}
266327
}
267328

268-
private byte[] json() {
269-
try (JsonWriter writer = new JsonWriter()) {
270-
writer.beginObject();
271-
writer.name("metadata").beginObject();
272-
synchronized (this.meta) {
273-
for (Map.Entry<String, String> entry : meta.entrySet()) {
274-
writer.name(entry.getKey());
275-
writer.value(entry.getValue());
276-
}
277-
}
278-
writer.endObject();
279-
280-
writer.name("points").beginArray();
281-
synchronized (this.points) {
282-
for (Map.Entry<String, List<String>> entry : points.entrySet()) {
283-
writer.beginObject();
284-
writer.name("name").value(entry.getKey());
285-
writer.name("tags").beginArray();
286-
for (String tag : entry.getValue()) {
287-
writer.value(tag);
288-
}
289-
writer.endArray();
290-
writer.endObject();
291-
}
292-
this.points.clear();
293-
}
294-
writer.endArray();
295-
writer.endObject();
296-
297-
return writer.toByteArray();
298-
}
299-
}
300-
301329
@SuppressForbidden
302330
private Closeable muteTracing() {
303331
try {

dd-java-agent/src/test/groovy/datadog/trace/bootstrap/BootstrapInitializationTelemetryTest.groovy

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package datadog.trace.bootstrap
22

3+
import datadog.trace.bootstrap.BootstrapInitializationTelemetry.Telemetry
4+
import groovy.json.JsonBuilder
35
import spock.lang.Specification
46

7+
import static java.nio.charset.StandardCharsets.UTF_8
8+
59
class BootstrapInitializationTelemetryTest extends Specification {
610
Capture capture
711
def initTelemetry
@@ -29,8 +33,7 @@ class BootstrapInitializationTelemetryTest extends Specification {
2933
initTelemetry.finish()
3034

3135
then:
32-
assertMeta("success", "success", "Successfully configured ddtrace package")
33-
assertPoints(true, "library_entrypoint.complete", [])
36+
assertJson("success", "success", "Successfully configured ddtrace package", [[name: "library_entrypoint.complete"]])
3437
}
3538

3639
def "test non fatal error as text"() {
@@ -39,8 +42,10 @@ class BootstrapInitializationTelemetryTest extends Specification {
3942
initTelemetry.finish()
4043

4144
then:
42-
assertMeta("error", "unknown", "some reason")
43-
assertPoints(true, "library_entrypoint.error", ["error_type:some reason"])
45+
assertJson("error", "unknown", "some reason", [
46+
[name: "library_entrypoint.error", tags: ["error_type:some reason"]],
47+
[name: "library_entrypoint.complete"]
48+
])
4449
}
4550

4651
def "test non fatal error as exception"() {
@@ -49,8 +54,10 @@ class BootstrapInitializationTelemetryTest extends Specification {
4954
initTelemetry.finish()
5055

5156
then:
52-
assertMeta("error", "internal_error", "non fatal error")
53-
assertPoints(true, "library_entrypoint.error", ["error_type:java.lang.Exception"])
57+
assertJson("error", "internal_error", "non fatal error", [
58+
[name: "library_entrypoint.error", tags: ["error_type:java.lang.Exception"]],
59+
[name: "library_entrypoint.complete"]
60+
])
5461
}
5562

5663
def "test abort"() {
@@ -59,8 +66,7 @@ class BootstrapInitializationTelemetryTest extends Specification {
5966
initTelemetry.finish()
6067

6168
then:
62-
assertMeta("abort", resultClass, reasonCode)
63-
assertPoints(false, "library_entrypoint.abort", ["reason:${reasonCode}"])
69+
assertJson("abort", resultClass, reasonCode, [[name: "library_entrypoint.abort", tags: ["reason:${reasonCode}"]]])
6470

6571
where:
6672
reasonCode | resultClass
@@ -76,8 +82,7 @@ class BootstrapInitializationTelemetryTest extends Specification {
7682
initTelemetry.finish()
7783

7884
then:
79-
assertMeta("error", "internal_error", "fatal error")
80-
assertPoints(false, "library_entrypoint.error", ["error_type:java.lang.Exception"])
85+
assertJson("error", "internal_error", "fatal error", [[name: "library_entrypoint.error", tags: ["error_type:java.lang.Exception"]]])
8186
}
8287

8388
def "test unwind root cause"() {
@@ -86,36 +91,30 @@ class BootstrapInitializationTelemetryTest extends Specification {
8691
initTelemetry.finish()
8792

8893
then:
89-
assertMeta("error", "internal_error", "top cause")
90-
assertPoints(true, "library_entrypoint.error", ["error_type:java.io.FileNotFoundException", "error_type:java.lang.Exception"])
91-
}
92-
93-
def assertMeta(String result, String resultClass, String resultReason) {
94-
def meta = capture.meta
95-
96-
assert meta.get("result") == result
97-
assert meta.get("result_class") == resultClass
98-
assert meta.get("result_reason") == resultReason
99-
100-
return true
94+
assertJson("error", "internal_error", "top cause", [
95+
[name: "library_entrypoint.error", tags: ["error_type:java.io.FileNotFoundException", "error_type:java.lang.Exception"]],
96+
[name: "library_entrypoint.complete"]
97+
])
10198
}
10299

103-
def assertPoints(boolean complete, String point, List<String> tags) {
104-
def points = capture.points
100+
private boolean assertJson(String result, String resultClass, String resultReason, List points) {
101+
def expectedJson = """{"metadata":{"result":"${result}","result_class":"${resultClass}","result_reason":"${resultReason}"},"points":${new JsonBuilder(points)}}"""
102+
def actualJson = capture.json()
105103

106-
assert points.containsKey("library_entrypoint.complete") == complete
107-
assert points.get(point) == tags
104+
assert expectedJson == actualJson
108105

109106
return true
110107
}
111108

112109
static class Capture implements BootstrapInitializationTelemetry.JsonSender {
113-
Map<String, String> meta
114-
Map<String, List<String>> points
110+
Telemetry telemetry
111+
112+
void send(Telemetry telemetry) {
113+
this.telemetry = telemetry
114+
}
115115

116-
void send(Map<String, String> meta, Map<String, List<String>> points) {
117-
this.meta = meta
118-
this.points = points
116+
String json() {
117+
return new String(telemetry.json(), UTF_8)
119118
}
120119
}
121120
}

0 commit comments

Comments
 (0)