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 |