Skip to content

Commit 7d20566

Browse files
Move JSON generation to sender thread to improve startup time. (#9197)
1 parent eb6dda2 commit 7d20566

File tree

2 files changed

+127
-117
lines changed

2 files changed

+127
-117
lines changed

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

Lines changed: 88 additions & 58 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.Collections;
1012
import java.util.LinkedHashMap;
1113
import java.util.List;
1214
import java.util.Map;
@@ -51,14 +53,14 @@ public static BootstrapInitializationTelemetry createFromForwarderPath(String fo
5153
*/
5254
public abstract void onError(Throwable t);
5355

56+
public abstract void onError(String reasonCode);
57+
5458
/**
5559
* Indicates an exception that occurred during the bootstrapping process that left initialization
5660
* incomplete. Equivalent to calling {@link #onError(Throwable)} and {@link #markIncomplete()}
5761
*/
5862
public abstract void onFatalError(Throwable t);
5963

60-
public abstract void onError(String reasonCode);
61-
6264
public abstract void markIncomplete();
6365

6466
public abstract void finish();
@@ -78,10 +80,10 @@ public void onAbort(String reasonCode) {}
7880
public void onError(String reasonCode) {}
7981

8082
@Override
81-
public void onFatalError(Throwable t) {}
83+
public void onError(Throwable t) {}
8284

8385
@Override
84-
public void onError(Throwable t) {}
86+
public void onFatalError(Throwable t) {}
8587

8688
@Override
8789
public void markIncomplete() {}
@@ -93,38 +95,31 @@ public void finish() {}
9395
public static final class JsonBased extends BootstrapInitializationTelemetry {
9496
private final JsonSender sender;
9597

96-
private final List<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;
101-
private volatile boolean error = false;
102102

103103
JsonBased(JsonSender sender) {
104104
this.sender = sender;
105-
this.meta = new ArrayList<>();
106-
this.points = new LinkedHashMap<>();
105+
this.telemetry = new Telemetry();
107106
}
108107

109108
@Override
110109
public void initMetaInfo(String attr, String value) {
111-
synchronized (this.meta) {
112-
this.meta.add(attr);
113-
this.meta.add(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-
error = true;
127-
setMetaInfo("error", "internal_error", t.getMessage());
122+
setResultMeta("error", "internal_error", t.getMessage());
128123

129124
List<String> causes = new ArrayList<>();
130125

@@ -145,6 +140,12 @@ public void onError(Throwable t) {
145140
onPoint("library_entrypoint.error", causes);
146141
}
147142

143+
@Override
144+
public void onError(String reasonCode) {
145+
onPoint("library_entrypoint.error", singletonList("error_type:" + reasonCode));
146+
setResultMeta("error", mapResultClass(reasonCode), reasonCode);
147+
}
148+
148149
private int maxTags() {
149150
String maxTags = EnvironmentVariables.get("DD_TELEMETRY_FORWARDER_MAX_TAGS");
150151

@@ -165,14 +166,7 @@ public void onFatalError(Throwable t) {
165166
markIncomplete();
166167
}
167168

168-
@Override
169-
public void onError(String reasonCode) {
170-
error = true;
171-
onPoint("library_entrypoint.error", "error_type:" + reasonCode);
172-
setMetaInfo("error", mapResultClass(reasonCode), reasonCode);
173-
}
174-
175-
private void setMetaInfo(String result, String resultClass, String resultReason) {
169+
private void setResultMeta(String result, String resultClass, String resultReason) {
176170
initMetaInfo("result", result);
177171
initMetaInfo("result_class", resultClass);
178172
initMetaInfo("result_reason", resultReason);
@@ -195,14 +189,8 @@ private String mapResultClass(String reasonCode) {
195189
}
196190
}
197191

198-
private void onPoint(String name, String tag) {
199-
onPoint(name, Collections.singletonList(tag));
200-
}
201-
202192
private void onPoint(String name, List<String> tags) {
203-
synchronized (this.points) {
204-
this.points.put(name, tags);
205-
}
193+
telemetry.addPoint(name, tags);
206194
}
207195

208196
@Override
@@ -212,51 +200,91 @@ public void markIncomplete() {
212200

213201
@Override
214202
public void finish() {
215-
if (!this.incomplete && !this.error) {
216-
setMetaInfo("success", "success", "Successfully configured ddtrace package");
203+
if (!this.incomplete) {
204+
onPoint("library_entrypoint.complete", emptyList());
205+
}
206+
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);
217225
}
226+
}
218227

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+
@Override
243+
public String toString() {
219244
try (JsonWriter writer = new JsonWriter()) {
220245
writer.beginObject();
221246
writer.name("metadata").beginObject();
222-
synchronized (this.meta) {
223-
for (int i = 0; i + 1 < this.meta.size(); i = i + 2) {
224-
writer.name(this.meta.get(i));
225-
writer.value(this.meta.get(i + 1));
247+
synchronized (metadata) {
248+
for (Map.Entry<String, String> entry : metadata.entrySet()) {
249+
writer.name(entry.getKey());
250+
writer.value(entry.getValue());
226251
}
252+
253+
metadata.clear();
227254
}
228255
writer.endObject();
229256

230257
writer.name("points").beginArray();
231-
synchronized (this.points) {
258+
synchronized (points) {
232259
for (Map.Entry<String, List<String>> entry : points.entrySet()) {
233260
writer.beginObject();
234261
writer.name("name").value(entry.getKey());
235-
writer.name("tags").beginArray();
236-
for (String tag : entry.getValue()) {
237-
writer.value(tag);
262+
if (!entry.getValue().isEmpty()) {
263+
writer.name("tags").beginArray();
264+
for (String tag : entry.getValue()) {
265+
writer.value(tag);
266+
}
267+
writer.endArray();
238268
}
239-
writer.endArray();
240269
writer.endObject();
241270
}
242-
this.points.clear();
243-
}
244-
if (!this.incomplete) {
245-
writer.beginObject().name("name").value("library_entrypoint.complete").endObject();
271+
272+
points.clear();
246273
}
247274
writer.endArray();
248275
writer.endObject();
249276

250-
this.sender.send(writer.toByteArray());
251-
} catch (Throwable t) {
252-
// Since this is the reporting mechanism, there's little recourse here
253-
// Decided to simply ignore - arguably might want to write to stderr
277+
return writer.toString();
254278
}
255279
}
256280
}
257281

282+
/**
283+
* Declare telemetry as {@code Object} to avoid issue with double class loading from different
284+
* classloaders.
285+
*/
258286
public interface JsonSender {
259-
void send(byte[] payload);
287+
void send(Object telemetry);
260288
}
261289

262290
public static final class ForwarderJsonSender implements JsonSender {
@@ -267,21 +295,21 @@ public static final class ForwarderJsonSender implements JsonSender {
267295
}
268296

269297
@Override
270-
public void send(byte[] payload) {
271-
ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, payload);
298+
public void send(Object telemetry) {
299+
ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, telemetry);
272300
t.setDaemon(true);
273301
t.start();
274302
}
275303
}
276304

277305
public static final class ForwarderJsonSenderThread extends Thread {
278306
private final String forwarderPath;
279-
private final byte[] payload;
307+
private final Object telemetry;
280308

281-
public ForwarderJsonSenderThread(String forwarderPath, byte[] payload) {
309+
public ForwarderJsonSenderThread(String forwarderPath, Object telemetry) {
282310
super("dd-forwarder-json-sender");
283311
this.forwarderPath = forwarderPath;
284-
this.payload = payload;
312+
this.telemetry = telemetry;
285313
}
286314

287315
@SuppressForbidden
@@ -291,6 +319,8 @@ public void run() {
291319

292320
// Run forwarder and mute tracing for subprocesses executed in by dd-java-agent.
293321
try (final Closeable ignored = muteTracing()) {
322+
byte[] payload = telemetry.toString().getBytes();
323+
294324
Process process = builder.start();
295325
try (OutputStream out = process.getOutputStream()) {
296326
out.write(payload);

0 commit comments

Comments
 (0)