77import static datadog .trace .api .config .CrashTrackingConfig .CRASH_TRACKING_UPLOAD_TIMEOUT ;
88import static datadog .trace .api .config .CrashTrackingConfig .CRASH_TRACKING_UPLOAD_TIMEOUT_DEFAULT ;
99
10+ import com .datadog .crashtracking .dto .CrashLog ;
1011import com .squareup .moshi .JsonWriter ;
1112import datadog .common .container .ContainerInfo ;
1213import datadog .common .version .VersionInfo ;
1617import datadog .trace .bootstrap .config .provider .ConfigProvider ;
1718import datadog .trace .util .PidHelper ;
1819import de .thetaphi .forbiddenapis .SuppressForbidden ;
19- import java .io .IOException ;
20- import java .io .InputStream ;
21- import java .io .InputStreamReader ;
22- import java .io .PrintStream ;
20+ import java .io .*;
21+ import java .nio .charset .Charset ;
2322import java .nio .charset .StandardCharsets ;
23+ import java .nio .file .Files ;
24+ import java .nio .file .Path ;
2425import java .time .Instant ;
25- import java .util .ArrayList ;
2626import java .util .Arrays ;
2727import java .util .HashMap ;
2828import java .util .List ;
@@ -54,7 +54,7 @@ public final class CrashUploader {
5454 static final String JAVA_TRACING_LIBRARY = "dd-trace-java" ;
5555 static final String HEADER_DD_EVP_ORIGIN_VERSION = "DD-EVP-ORIGIN-VERSION" ;
5656 static final String HEADER_DD_TELEMETRY_API_VERSION = "DD-Telemetry-API-Version" ;
57- static final String TELEMETRY_API_VERSION = "v1 " ;
57+ static final String TELEMETRY_API_VERSION = "v2 " ;
5858 static final String HEADER_DD_TELEMETRY_REQUEST_TYPE = "DD-Telemetry-Request-Type" ;
5959 static final String TELEMETRY_REQUEST_TYPE = "logs" ;
6060
@@ -114,43 +114,44 @@ private String tagsToString(final Map<String, String> tags) {
114114 .collect (Collectors .joining ("," ));
115115 }
116116
117- public void upload (@ Nonnull List <InputStream > files ) throws IOException {
118- List < String > filesContent = new ArrayList <>( files . size ());
119- for ( InputStream file : files ) {
120- filesContent . add ( readContent ( file ) );
117+ public void upload (@ Nonnull List <Path > files ) throws IOException {
118+ for ( Path file : files ) {
119+ uploadToLogs ( file );
120+ uploadToTelemetry ( file );
121121 }
122- uploadToLogs (filesContent );
123- uploadToTelemetry (filesContent );
124122 }
125123
126- void uploadToLogs (@ Nonnull List <String > filesContent ) throws IOException {
127- uploadToLogs (filesContent , System .out );
124+ boolean uploadToLogs (@ Nonnull Path file ) {
125+ try {
126+ uploadToLogs (new String (Files .readAllBytes (file ), StandardCharsets .UTF_8 ), System .out );
127+ } catch (IOException e ) {
128+ log .error ("Failed to upload crash file: {}" , file , e );
129+ return false ;
130+ }
131+ return true ;
128132 }
129133
130- void uploadToLogs (@ Nonnull List <String > filesContent , @ Nonnull PrintStream out )
131- throws IOException {
134+ void uploadToLogs (@ Nonnull String message , @ Nonnull PrintStream out ) throws IOException {
132135 // print on the output, and the application/container/host log will pick it up
133- for (String message : filesContent ) {
134- try (Buffer buf = new Buffer ()) {
135- try (JsonWriter writer = JsonWriter .of (buf )) {
136- writer .beginObject ();
137- writer .name ("ddsource" ).value ("crashtracker" );
138- writer .name ("ddtags" ).value (tags );
139- writer .name ("hostname" ).value (config .getHostName ());
140- writer .name ("service" ).value (config .getServiceName ());
141- writer .name ("message" ).value (message );
142- writer .name ("level" ).value ("ERROR" );
143- writer .name ("error" );
144- writer .beginObject ();
145- writer .name ("kind" ).value (extractErrorKind (message ));
146- writer .name ("message" ).value (extractErrorMessage (message ));
147- writer .name ("stack" ).value (extractErrorStackTrace (message , false ));
148- writer .endObject ();
149- writer .endObject ();
150- }
151-
152- out .println (buf .readByteString ().utf8 ());
136+ try (Buffer buf = new Buffer ()) {
137+ try (JsonWriter writer = JsonWriter .of (buf )) {
138+ writer .beginObject ();
139+ writer .name ("ddsource" ).value ("crashtracker" );
140+ writer .name ("ddtags" ).value (tags );
141+ writer .name ("hostname" ).value (config .getHostName ());
142+ writer .name ("service" ).value (config .getServiceName ());
143+ writer .name ("message" ).value (message );
144+ writer .name ("level" ).value ("ERROR" );
145+ writer .name ("error" );
146+ writer .beginObject ();
147+ writer .name ("kind" ).value (extractErrorKind (message ));
148+ writer .name ("message" ).value (extractErrorMessage (message ));
149+ writer .name ("stack" ).value (extractErrorStackTrace (message , false ));
150+ writer .endObject ();
151+ writer .endObject ();
153152 }
153+
154+ out .println (buf .readByteString ().utf8 ());
154155 }
155156 }
156157
@@ -235,16 +236,26 @@ private String extractErrorStackTrace(String fileContent) {
235236 return extractErrorStackTrace (fileContent , true );
236237 }
237238
238- void uploadToTelemetry (@ Nonnull List <String > filesContent ) throws IOException {
239- handleCall (makeTelemetryRequest (filesContent ));
239+ boolean uploadToTelemetry (@ Nonnull Path file ) {
240+ try {
241+ String content = new String (Files .readAllBytes (file ), Charset .defaultCharset ());
242+ handleCall (makeTelemetryRequest (content ));
243+ } catch (IOException e ) {
244+ log .error ("Failed to upload crash file: {}" , file , e );
245+ return false ;
246+ }
247+ return true ;
240248 }
241249
242- private Call makeTelemetryRequest (@ Nonnull List < String > filesContent ) throws IOException {
243- final RequestBody requestBody = makeTelemetryRequestBody (filesContent );
250+ private Call makeTelemetryRequest (@ Nonnull String content ) throws IOException {
251+ final RequestBody requestBody = makeTelemetryRequestBody (content );
244252
245253 final Map <String , String > headers = new HashMap <>();
246254 // Set chunked transfer
247- headers .put ("Content-Type" , requestBody .contentType ().toString ());
255+ MediaType contentType = requestBody .contentType ();
256+ if (contentType != null ) {
257+ headers .put ("Content-Type" , contentType .toString ());
258+ }
248259 headers .put ("Content-Length" , Long .toString (requestBody .contentLength ()));
249260 headers .put ("Transfer-Encoding" , "chunked" );
250261 headers .put (HEADER_DD_EVP_ORIGIN , JAVA_TRACING_LIBRARY );
@@ -258,8 +269,11 @@ private Call makeTelemetryRequest(@Nonnull List<String> filesContent) throws IOE
258269 .build ());
259270 }
260271
261- private RequestBody makeTelemetryRequestBody (@ Nonnull List <String > filesContent )
262- throws IOException {
272+ private RequestBody makeTelemetryRequestBody (@ Nonnull String content ) throws IOException {
273+ CrashLog crashLog = CrashLogParser .fromHotspotCrashLog (content );
274+ if (crashLog == null ) {
275+ throw new IOException ("Failed to parse crash log" );
276+ }
263277 try (Buffer buf = new Buffer ()) {
264278 try (JsonWriter writer = JsonWriter .of (buf )) {
265279 writer .beginObject ();
@@ -275,13 +289,11 @@ private RequestBody makeTelemetryRequestBody(@Nonnull List<String> filesContent)
275289 writer .name ("debug" ).value (true );
276290 writer .name ("payload" );
277291 writer .beginArray ();
278- for (String message : filesContent ) {
279- writer .beginObject ();
280- writer .name ("message" ).value (extractErrorStackTrace (message ));
281- writer .name ("level" ).value ("ERROR" );
282- writer .name ("tags" ).value ("severity:crash" );
283- writer .endObject ();
284- }
292+ writer .beginObject ();
293+ writer .name ("message" ).value (crashLog .toJson ());
294+ writer .name ("level" ).value ("ERROR" );
295+ writer .name ("tags" ).value ("severity:crash" );
296+ writer .endObject ();
285297 writer .endArray ();
286298 writer .name ("application" );
287299 writer .beginObject ();
0 commit comments