Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Unified Diff: pkg/telemetry/lib/crash_reporting.dart

Issue 2954733002: Add initial version of analytics and crash reporting package. (Closed)
Patch Set: update readme Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/telemetry/lib/crash_reporting.dart
diff --git a/pkg/telemetry/lib/crash_reporting.dart b/pkg/telemetry/lib/crash_reporting.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d892a17286a0aca2b85d99d546f6c50442315e1f
--- /dev/null
+++ b/pkg/telemetry/lib/crash_reporting.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:http/http.dart' as http;
+import 'package:stack_trace/stack_trace.dart';
+import 'package:usage/usage.dart';
+
+/// Tells crash backend that this is a Dart error as opposed to, say, Java.
+const String _dartTypeId = 'DartError';
+
+/// Crash backend host.
+const String _crashServerHost = 'clients2.google.com';
+
+/// Path to the crash servlet.
+const String _crashEndpointPath = '/cr/report'; // or, staging_report
+
+/// The field corresponding to the multipart/form-data file attachment where
+/// crash backend expects to find the Dart stack trace.
+const String _stackTraceFileField = 'DartError';
+
+/// The name of the file attached as [stackTraceFileField].
+///
+/// The precise value is not important. It is ignored by the crash back end, but
+/// it must be supplied in the request.
+const String _stackTraceFilename = 'stacktrace_file';
+
+/// Sends crash reports to Google.
Brian Wilkerson 2017/06/23 21:41:09 If we might publish this as a package someday, con
devoncarew 2017/06/26 15:53:46 Done.
+class CrashReportSender {
kevmoo 2017/06/23 21:01:04 Should likely have a way to close/dispose this – a
devoncarew 2017/06/26 15:53:46 Good point! Added a dispose() method, doc'd it, an
+ static final Uri _baseUri = new Uri(
+ scheme: 'https',
+ host: _crashServerHost,
+ port: 443,
kevmoo 2017/06/23 21:01:04 A bit redundant w/ https?
devoncarew 2017/06/26 15:53:46 removed
+ path: _crashEndpointPath);
+
+ final Analytics analytics;
+
+ http.Client _httpClient;
kevmoo 2017/06/23 21:01:05 make final?
Brian Wilkerson 2017/06/23 21:41:09 It can't be because of the assignment on line 46.
kevmoo 2017/06/23 21:43:31 That can be done in the initializer. No worries.
devoncarew 2017/06/26 15:53:46 refactored to allow final
+
+ /// Create a new [CrashReportSender], using the data from the given
+ /// [Analytics] instance.
+ CrashReportSender(this.analytics, {http.Client httpClient}) {
+ _httpClient = httpClient ?? new http.Client();
+ }
+
+ /// Sends one crash report.
+ ///
+ /// The report is populated from data in [error] and [stackTrace].
+ Future sendReport(dynamic error, [StackTrace stackTrace]) async {
Brian Wilkerson 2017/06/23 21:41:09 Consider making stackTrace a named parameter. Addi
devoncarew 2017/06/26 15:53:46 Makes sense, will do.
+ if (!analytics.enabled) {
+ return;
+ }
+
+ try {
+ final Uri uri = _baseUri.replace(
+ queryParameters: <String, String>{
+ 'product': analytics.trackingId,
+ 'version': analytics.applicationVersion,
+ },
+ );
+
+ final http.MultipartRequest req = new http.MultipartRequest('POST', uri);
+ req.fields['uuid'] = analytics.clientId;
+ req.fields['product'] = analytics.trackingId;
+ req.fields['version'] = analytics.applicationVersion;
+ req.fields['osName'] = Platform.operatingSystem;
+ req.fields['osVersion'] = Platform.operatingSystem; // includes the vesion
Brian Wilkerson 2017/06/23 21:41:09 "vesion" --> "version" Should we parse out the na
devoncarew 2017/06/26 15:53:45 On investigation, this field does not contain the
+ req.fields['type'] = _dartTypeId;
+ req.fields['error_runtime_type'] = '${error.runtimeType}';
+
+ final Chain chain = new Chain.parse(stackTrace.toString());
+ req.files.add(new http.MultipartFile.fromString(
+ _stackTraceFileField, chain.terse.toString(),
+ filename: _stackTraceFilename));
+
+ final http.StreamedResponse resp = await _httpClient.send(req);
+
+ if (resp.statusCode != 200) {
+ throw 'server responded with HTTP status code ${resp.statusCode}';
+ }
+ } catch (sendError, sendStackTrace) {
kevmoo 2017/06/23 21:01:04 A tiny more conventional to use `on SocketExceptio
devoncarew 2017/06/26 15:53:45 Done.
+ if (sendError is SocketException) {
+ throw 'network error while sending crash report: $sendError';
+ } else {
+ // If the sender itself crashes, just print.
+ throw 'exception while sending crash report: $sendError\n$sendStackTrace';
kevmoo 2017/06/23 21:01:05 long line
devoncarew 2017/06/26 15:53:46 Done.
+ }
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698