| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016, 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 library fasta.errors; |
| 6 |
| 7 import 'dart:async' show |
| 8 Future; |
| 9 |
| 10 import 'dart:convert' show |
| 11 JSON; |
| 12 |
| 13 import 'dart:io' show |
| 14 ContentType, |
| 15 HttpClient, |
| 16 HttpClientRequest, |
| 17 SocketException, |
| 18 stderr; |
| 19 |
| 20 import 'colors.dart' show |
| 21 red; |
| 22 |
| 23 const String defaultServerAddress = "http://127.0.0.1:59410/"; |
| 24 |
| 25 /// Tracks if there has been a crash reported through [reportCrash]. Should be |
| 26 /// reset between each compilation by calling [resetCrashReporting]. |
| 27 bool hasCrashed = false; |
| 28 |
| 29 /// Tracks the first source URI that has been read and is used as a fall-back |
| 30 /// for [reportCrash]. Should be reset between each compilation by calling |
| 31 /// [resetCrashReporting]. |
| 32 Uri firstSourceUri; |
| 33 |
| 34 dynamic internalError(Object error) { |
| 35 throw error; |
| 36 } |
| 37 |
| 38 dynamic inputError(Uri uri, int charOffset, Object error) { |
| 39 throw new InputError(uri, charOffset, error); |
| 40 } |
| 41 |
| 42 class InputError { |
| 43 final Uri uri; |
| 44 |
| 45 final int charOffset; |
| 46 |
| 47 final Object error; |
| 48 |
| 49 InputError(this.uri, int charOffset, this.error) |
| 50 : this.charOffset = charOffset ?? -1; |
| 51 |
| 52 toString() => "InputError: $error"; |
| 53 |
| 54 String format() { |
| 55 // TODO(ahe): Colors need to be optional. Doesn't work well in Emacs or on |
| 56 // Windows. |
| 57 String message = red("Error: ${safeToString(error)}"); |
| 58 if (uri != null) { |
| 59 String position = charOffset == -1 ? "" : "$charOffset:"; |
| 60 return "${uri}:$position $message"; |
| 61 } else { |
| 62 return message; |
| 63 } |
| 64 } |
| 65 } |
| 66 |
| 67 class Crash { |
| 68 final Uri uri; |
| 69 |
| 70 final int charOffset; |
| 71 |
| 72 final Object error; |
| 73 |
| 74 final StackTrace trace; |
| 75 |
| 76 Crash(this.uri, this.charOffset, this.error, this.trace); |
| 77 |
| 78 String toString() { |
| 79 return """ |
| 80 Crash when compiling $uri, |
| 81 at character offset $charOffset: |
| 82 $error${trace == null ? '' : '\n$trace'} |
| 83 """; |
| 84 } |
| 85 } |
| 86 |
| 87 void resetCrashReporting() { |
| 88 firstSourceUri = null; |
| 89 hasCrashed = false; |
| 90 } |
| 91 |
| 92 Future reportCrash(error, StackTrace trace, [Uri uri, int charOffset]) async { |
| 93 note(String note) async { |
| 94 stderr.write(note); |
| 95 await stderr.flush(); |
| 96 } |
| 97 if (hasCrashed) return new Future.error(error, trace); |
| 98 if (error is Crash) { |
| 99 trace = error.trace ?? trace; |
| 100 uri = error.uri ?? uri; |
| 101 charOffset = error.charOffset ?? charOffset; |
| 102 error = error.error; |
| 103 } |
| 104 uri ??= firstSourceUri; |
| 105 hasCrashed = true; |
| 106 Map<String, dynamic> data = <String, dynamic>{}; |
| 107 data["type"] = "crash"; |
| 108 data["client"] = "package:fasta"; |
| 109 if (uri != null) data["uri"] = "$uri"; |
| 110 if (charOffset != null) data["offset"] = charOffset; |
| 111 data["error"] = safeToString(error); |
| 112 data["trace"] = "$trace"; |
| 113 String json = JSON.encode(data); |
| 114 HttpClient client = new HttpClient(); |
| 115 try { |
| 116 Uri uri = Uri.parse(defaultServerAddress); |
| 117 HttpClientRequest request; |
| 118 try { |
| 119 request = await client.postUrl(uri); |
| 120 } on SocketException { |
| 121 // Assume the crash logger isn't running. |
| 122 await client.close(force: true); |
| 123 return new Future.error(error, trace); |
| 124 } |
| 125 if (request != null) { |
| 126 await note("\nSending crash report data"); |
| 127 request.persistentConnection = false; |
| 128 request.bufferOutput = false; |
| 129 String host = request?.connectionInfo?.remoteAddress?.host; |
| 130 int port = request?.connectionInfo?.remotePort; |
| 131 await note(" to $host:$port"); |
| 132 await request |
| 133 ..headers.contentType = ContentType.JSON |
| 134 ..write(json); |
| 135 await request.close(); |
| 136 await note("."); |
| 137 } |
| 138 } catch (e, s) { |
| 139 await note("\n${safeToString(e)}\n$s\n"); |
| 140 await note("\n\n\nFE::ERROR::$json\n\n\n"); |
| 141 } |
| 142 await client.close(force: true); |
| 143 await note("\n"); |
| 144 return new Future.error(error, trace); |
| 145 } |
| 146 |
| 147 String safeToString(Object object) { |
| 148 try { |
| 149 return "$object"; |
| 150 } catch (e) { |
| 151 return "Error when converting ${object.runtimeType} to string."; |
| 152 } |
| 153 } |
| OLD | NEW |