Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'dart:async'; | |
| 6 import 'dart:io'; | |
| 7 | |
| 8 import 'package:http/http.dart' as http; | |
| 9 import 'package:stack_trace/stack_trace.dart'; | |
| 10 import 'package:usage/usage.dart'; | |
| 11 | |
| 12 /// Tells crash backend that this is a Dart error as opposed to, say, Java. | |
| 13 const String _dartTypeId = 'DartError'; | |
| 14 | |
| 15 /// Crash backend host. | |
| 16 const String _crashServerHost = 'clients2.google.com'; | |
| 17 | |
| 18 /// Path to the crash servlet. | |
| 19 const String _crashEndpointPath = '/cr/report'; // or, staging_report | |
| 20 | |
| 21 /// The field corresponding to the multipart/form-data file attachment where | |
| 22 /// crash backend expects to find the Dart stack trace. | |
| 23 const String _stackTraceFileField = 'DartError'; | |
| 24 | |
| 25 /// The name of the file attached as [stackTraceFileField]. | |
| 26 /// | |
| 27 /// The precise value is not important. It is ignored by the crash back end, but | |
| 28 /// it must be supplied in the request. | |
| 29 const String _stackTraceFilename = 'stacktrace_file'; | |
| 30 | |
| 31 /// 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.
| |
| 32 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
| |
| 33 static final Uri _baseUri = new Uri( | |
| 34 scheme: 'https', | |
| 35 host: _crashServerHost, | |
| 36 port: 443, | |
|
kevmoo
2017/06/23 21:01:04
A bit redundant w/ https?
devoncarew
2017/06/26 15:53:46
removed
| |
| 37 path: _crashEndpointPath); | |
| 38 | |
| 39 final Analytics analytics; | |
| 40 | |
| 41 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
| |
| 42 | |
| 43 /// Create a new [CrashReportSender], using the data from the given | |
| 44 /// [Analytics] instance. | |
| 45 CrashReportSender(this.analytics, {http.Client httpClient}) { | |
| 46 _httpClient = httpClient ?? new http.Client(); | |
| 47 } | |
| 48 | |
| 49 /// Sends one crash report. | |
| 50 /// | |
| 51 /// The report is populated from data in [error] and [stackTrace]. | |
| 52 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.
| |
| 53 if (!analytics.enabled) { | |
| 54 return; | |
| 55 } | |
| 56 | |
| 57 try { | |
| 58 final Uri uri = _baseUri.replace( | |
| 59 queryParameters: <String, String>{ | |
| 60 'product': analytics.trackingId, | |
| 61 'version': analytics.applicationVersion, | |
| 62 }, | |
| 63 ); | |
| 64 | |
| 65 final http.MultipartRequest req = new http.MultipartRequest('POST', uri); | |
| 66 req.fields['uuid'] = analytics.clientId; | |
| 67 req.fields['product'] = analytics.trackingId; | |
| 68 req.fields['version'] = analytics.applicationVersion; | |
| 69 req.fields['osName'] = Platform.operatingSystem; | |
| 70 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
| |
| 71 req.fields['type'] = _dartTypeId; | |
| 72 req.fields['error_runtime_type'] = '${error.runtimeType}'; | |
| 73 | |
| 74 final Chain chain = new Chain.parse(stackTrace.toString()); | |
| 75 req.files.add(new http.MultipartFile.fromString( | |
| 76 _stackTraceFileField, chain.terse.toString(), | |
| 77 filename: _stackTraceFilename)); | |
| 78 | |
| 79 final http.StreamedResponse resp = await _httpClient.send(req); | |
| 80 | |
| 81 if (resp.statusCode != 200) { | |
| 82 throw 'server responded with HTTP status code ${resp.statusCode}'; | |
| 83 } | |
| 84 } 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.
| |
| 85 if (sendError is SocketException) { | |
| 86 throw 'network error while sending crash report: $sendError'; | |
| 87 } else { | |
| 88 // If the sender itself crashes, just print. | |
| 89 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.
| |
| 90 } | |
| 91 } | |
| 92 } | |
| 93 } | |
| OLD | NEW |