11package datadog .trace .bootstrap ;
22
3+ import static java .util .Collections .emptyList ;
4+ import static java .util .Collections .singletonList ;
5+
36import datadog .json .JsonWriter ;
47import datadog .trace .bootstrap .environment .EnvironmentVariables ;
58import de .thetaphi .forbiddenapis .SuppressForbidden ;
69import java .io .Closeable ;
710import java .io .OutputStream ;
811import java .util .ArrayList ;
9- import java .util .Collections ;
1012import java .util .LinkedHashMap ;
1113import java .util .List ;
1214import 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