| // Copyright (c) 2015, 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. |
| |
| /// Interact with developer tools such as the debugger and inspector. |
| /// |
| /// The dart:developer library is _unstable_ and its API might change slightly |
| /// as a result of developer feedback. This library is platform dependent and |
| /// therefore it has implementations for both dart2js and the Dart VM. Both are |
| /// under development and may not support all operations yet. |
| /// |
| /// To use this library in your code: |
| /// |
| /// import 'dart:developer'; |
| /// |
| library dart.developer; |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:isolate' show Isolate, RawReceivePort, SendPort; |
| import 'dart:isolate'; |
| import 'dart:_internal' hide Symbol; |
| |
| part 'extension.dart'; |
| part 'profiler.dart'; |
| part 'timeline.dart'; |
| part 'service.dart'; |
| |
| /// If [when] is true, stop the program as if a breakpoint were hit at the |
| /// following statement. |
| /// |
| /// Returns the value of [when]. Some debuggers may display [message]. |
| /// |
| /// NOTE: When invoked, the isolate will not return until a debugger |
| /// continues execution. When running in the Dart VM the behaviour is the same |
| /// regardless of whether or not a debugger is connected. When compiled to |
| /// JavaScript, this uses the "debugger" statement, and behaves exactly as |
| /// that does. |
| bool debugger({bool when: true, String message}) native "Developer_debugger"; |
| |
| /// Send a reference to [object] to any attached debuggers. |
| /// |
| /// Debuggers may open an inspector on the object. Returns the argument. |
| Object inspect(Object object) native "Developer_inspect"; |
| |
| /// Emit a log event. |
| /// [message] is the log message. |
| /// [time] (optional) is the timestamp. |
| /// [sequenceNumber] (optional) is a monotonically increasing sequence number. |
| /// [level] (optional) is the severity level (value between 0 and 2000). |
| /// [name] (optional) is the name of the source of the log message. |
| /// [zone] (optional) the zone where the log was emitted |
| /// [error] (optional) an error object associated with this log event. |
| /// [stackTrace] (optional) a stack trace associated with this log event. |
| void log(String message, |
| {DateTime time, |
| int sequenceNumber, |
| int level: 0, |
| String name: '', |
| Zone zone, |
| Object error, |
| StackTrace stackTrace}) { |
| if (message is! String) { |
| throw new ArgumentError.value(message, "message", "Must be a String"); |
| } |
| if (time == null) { |
| time = new DateTime.now(); |
| } |
| if (time is! DateTime) { |
| throw new ArgumentError.value(time, "time", "Must be a DateTime"); |
| } |
| if (sequenceNumber == null) { |
| sequenceNumber = _nextSequenceNumber++; |
| } else { |
| _nextSequenceNumber = sequenceNumber + 1; |
| } |
| _log(message, time.millisecondsSinceEpoch, sequenceNumber, level, name, zone, |
| error, stackTrace); |
| } |
| |
| int _nextSequenceNumber = 0; |
| _log(String message, int timestamp, int sequenceNumber, int level, String name, |
| Zone zone, Object error, StackTrace stackTrace) native "Developer_log"; |
| _runExtension( |
| ServiceExtensionHandler handler, |
| String method, |
| List<String> parameterKeys, |
| List<String> parameterValues, |
| SendPort replyPort, |
| Object id, |
| bool trace_service) { |
| var parameters = {}; |
| for (var i = 0; i < parameterKeys.length; i++) { |
| parameters[parameterKeys[i]] = parameterValues[i]; |
| } |
| var response; |
| try { |
| response = handler(method, parameters); |
| } catch (e, st) { |
| var errorDetails = (st == null) ? '$e' : '$e\n$st'; |
| response = new ServiceExtensionResponse.error( |
| ServiceExtensionResponse.kExtensionError, errorDetails); |
| _postResponse(replyPort, id, response, trace_service); |
| return; |
| } |
| if (response is! Future) { |
| response = new ServiceExtensionResponse.error( |
| ServiceExtensionResponse.kExtensionError, |
| "Extension handler must return a Future"); |
| _postResponse(replyPort, id, response, trace_service); |
| return; |
| } |
| response.catchError((e, st) { |
| // Catch any errors eagerly and wrap them in a ServiceExtensionResponse. |
| var errorDetails = (st == null) ? '$e' : '$e\n$st'; |
| return new ServiceExtensionResponse.error( |
| ServiceExtensionResponse.kExtensionError, errorDetails); |
| }).then((response) { |
| // Post the valid response or the wrapped error after verifying that |
| // the response is a ServiceExtensionResponse. |
| if (response is! ServiceExtensionResponse) { |
| response = new ServiceExtensionResponse.error( |
| ServiceExtensionResponse.kExtensionError, |
| "Extension handler must complete to a ServiceExtensionResponse"); |
| } |
| _postResponse(replyPort, id, response, trace_service); |
| }).catchError((e, st) { |
| // We do not expect any errors to occur in the .then or .catchError blocks |
| // but, suppress them just in case. |
| }); |
| } |
| _postResponse(SendPort replyPort, Object id, ServiceExtensionResponse response, |
| bool trace_service) { |
| assert(replyPort != null); |
| if (id == null) { |
| if (trace_service) { |
| print("vm-service: posting no response for request"); |
| } |
| // No id -> no response. |
| replyPort.send(null); |
| return; |
| } |
| assert(id != null); |
| StringBuffer sb = new StringBuffer(); |
| sb.write('{"jsonrpc":"2.0",'); |
| if (response._isError()) { |
| if (trace_service) { |
| print("vm-service: posting error response for request $id"); |
| } |
| sb.write('"error":'); |
| } else { |
| if (trace_service) { |
| print("vm-service: posting response for request $id"); |
| } |
| sb.write('"result":'); |
| } |
| sb.write('${response._toString()},'); |
| if (id is String) { |
| sb.write('"id":"$id"}'); |
| } else { |
| sb.write('"id":$id}'); |
| } |
| replyPort.send(sb.toString()); |
| } |
| class _UserTag implements UserTag { |
| factory _UserTag(String label) native "UserTag_new"; |
| String get label native "UserTag_label"; |
| UserTag makeCurrent() native "UserTag_makeCurrent"; |
| } |
| UserTag _getCurrentTag() native "Profiler_getCurrentTag"; |
| UserTag _getDefaultTag() native "UserTag_defaultTag"; |