7
7
import static datadog .trace .api .config .CrashTrackingConfig .CRASH_TRACKING_UPLOAD_TIMEOUT ;
8
8
import static datadog .trace .api .config .CrashTrackingConfig .CRASH_TRACKING_UPLOAD_TIMEOUT_DEFAULT ;
9
9
10
+ import com .datadog .crashtracking .dto .CrashLog ;
10
11
import com .squareup .moshi .JsonWriter ;
11
12
import datadog .common .container .ContainerInfo ;
12
13
import datadog .common .version .VersionInfo ;
16
17
import datadog .trace .bootstrap .config .provider .ConfigProvider ;
17
18
import datadog .trace .util .PidHelper ;
18
19
import 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 ;
23
22
import java .nio .charset .StandardCharsets ;
23
+ import java .nio .file .Files ;
24
+ import java .nio .file .Path ;
24
25
import java .time .Instant ;
25
- import java .util .ArrayList ;
26
26
import java .util .Arrays ;
27
27
import java .util .HashMap ;
28
28
import java .util .List ;
@@ -54,7 +54,7 @@ public final class CrashUploader {
54
54
static final String JAVA_TRACING_LIBRARY = "dd-trace-java" ;
55
55
static final String HEADER_DD_EVP_ORIGIN_VERSION = "DD-EVP-ORIGIN-VERSION" ;
56
56
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 " ;
58
58
static final String HEADER_DD_TELEMETRY_REQUEST_TYPE = "DD-Telemetry-Request-Type" ;
59
59
static final String TELEMETRY_REQUEST_TYPE = "logs" ;
60
60
@@ -114,43 +114,44 @@ private String tagsToString(final Map<String, String> tags) {
114
114
.collect (Collectors .joining ("," ));
115
115
}
116
116
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 );
121
121
}
122
- uploadToLogs (filesContent );
123
- uploadToTelemetry (filesContent );
124
122
}
125
123
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 ;
128
132
}
129
133
130
- void uploadToLogs (@ Nonnull List <String > filesContent , @ Nonnull PrintStream out )
131
- throws IOException {
134
+ void uploadToLogs (@ Nonnull String message , @ Nonnull PrintStream out ) throws IOException {
132
135
// 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 ();
153
152
}
153
+
154
+ out .println (buf .readByteString ().utf8 ());
154
155
}
155
156
}
156
157
@@ -235,16 +236,26 @@ private String extractErrorStackTrace(String fileContent) {
235
236
return extractErrorStackTrace (fileContent , true );
236
237
}
237
238
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 ;
240
248
}
241
249
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 );
244
252
245
253
final Map <String , String > headers = new HashMap <>();
246
254
// 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
+ }
248
259
headers .put ("Content-Length" , Long .toString (requestBody .contentLength ()));
249
260
headers .put ("Transfer-Encoding" , "chunked" );
250
261
headers .put (HEADER_DD_EVP_ORIGIN , JAVA_TRACING_LIBRARY );
@@ -258,8 +269,11 @@ private Call makeTelemetryRequest(@Nonnull List<String> filesContent) throws IOE
258
269
.build ());
259
270
}
260
271
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
+ }
263
277
try (Buffer buf = new Buffer ()) {
264
278
try (JsonWriter writer = JsonWriter .of (buf )) {
265
279
writer .beginObject ();
@@ -275,13 +289,11 @@ private RequestBody makeTelemetryRequestBody(@Nonnull List<String> filesContent)
275
289
writer .name ("debug" ).value (true );
276
290
writer .name ("payload" );
277
291
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 ();
285
297
writer .endArray ();
286
298
writer .name ("application" );
287
299
writer .beginObject ();
0 commit comments