blob: 133f58b6cbeb86675b515d5062b4e8d4f2ff5ff0 [file] [log] [blame]
// 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";