Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library debugger_page_element; | 5 library debugger_page_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'observatory_element.dart'; | 9 import 'observatory_element.dart'; |
| 10 import 'package:observatory/cli.dart'; | 10 import 'package:observatory/cli.dart'; |
| 11 import 'package:observatory/debugger.dart'; | 11 import 'package:observatory/debugger.dart'; |
| 12 import 'package:observatory/service.dart'; | 12 import 'package:observatory/service.dart'; |
| 13 import 'package:logging/logging.dart'; | |
| 13 import 'package:polymer/polymer.dart'; | 14 import 'package:polymer/polymer.dart'; |
| 14 | 15 |
| 15 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. | 16 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. |
| 16 abstract class DebuggerCommand extends Command { | 17 abstract class DebuggerCommand extends Command { |
| 17 ObservatoryDebugger debugger; | 18 ObservatoryDebugger debugger; |
| 18 | 19 |
| 19 DebuggerCommand(this.debugger, name, children) | 20 DebuggerCommand(this.debugger, name, children) |
| 20 : super(name, children); | 21 : super(name, children); |
| 21 | 22 |
| 22 String get helpShort; | 23 String get helpShort; |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 String helpShort = | 343 String helpShort = |
| 343 'Continue running the isolate until it reaches the next source location'; | 344 'Continue running the isolate until it reaches the next source location'; |
| 344 | 345 |
| 345 String helpLong = | 346 String helpLong = |
| 346 'Continue running the isolate until it reaches the next source ' | 347 'Continue running the isolate until it reaches the next source ' |
| 347 'location.\n' | 348 'location.\n' |
| 348 '\n' | 349 '\n' |
| 349 'Syntax: step\n'; | 350 'Syntax: step\n'; |
| 350 } | 351 } |
| 351 | 352 |
| 353 class LogCommand extends DebuggerCommand { | |
| 354 LogCommand(Debugger debugger) : super(debugger, 'log', []) { | |
| 355 | |
|
turnidge
2015/08/03 18:16:22
Remove extra blank line here?
Cutch
2015/08/03 19:29:56
Done.
| |
| 356 } | |
| 357 | |
| 358 Future run(List<String> args) async { | |
| 359 if (args.length == 0) { | |
| 360 debugger.console.print( | |
| 361 'Current log level: ' | |
| 362 '${debugger._stdioPrinter._minimumLogLevel.name}'); | |
| 363 return new Future.value(null); | |
| 364 } | |
| 365 if (args.length > 1) { | |
| 366 debugger.console.print('Not implemented.'); | |
|
turnidge
2015/08/03 18:16:22
Different message here for consistency w/ other co
Cutch
2015/08/03 19:29:56
Done.
| |
| 367 return new Future.value(null); | |
| 368 } | |
| 369 var level = _findLevel(args[0]); | |
| 370 if (level == null) { | |
| 371 debugger.console.print('No such log level: ${args[0]}'); | |
| 372 return new Future.value(null); | |
| 373 } | |
| 374 debugger._stdioPrinter._minimumLogLevel = level; | |
| 375 debugger.console.print('Set log level to: ${level.name}'); | |
| 376 return new Future.value(null); | |
| 377 } | |
| 378 | |
| 379 Level _findLevel(String levelName) { | |
| 380 for (var level in Level.LEVELS) { | |
| 381 if (level.name == levelName) { | |
|
turnidge
2015/08/03 18:16:22
Consider adding a case-insensitive match so we can
Cutch
2015/08/03 19:29:56
Done.
| |
| 382 return level; | |
| 383 } | |
| 384 } | |
| 385 return null; | |
| 386 } | |
| 387 | |
| 388 Future<List<String>> complete(List<String> args) { | |
| 389 if (args.length != 1) { | |
| 390 return new Future.value([args.join('')]); | |
| 391 } | |
| 392 var prefix = args[0]; | |
| 393 var result = <String>[]; | |
| 394 for (var level in Level.LEVELS) { | |
| 395 if (level.name.startsWith(prefix)) { | |
|
turnidge
2015/08/03 18:16:22
Consider either
- completing against lowercase ve
Cutch
2015/08/03 19:29:56
case-insensitive prefix match.
| |
| 396 result.add(level.name); | |
| 397 } | |
| 398 } | |
| 399 return new Future.value(result); | |
| 400 } | |
| 401 | |
| 402 String helpShort = | |
| 403 'Control which log messages are displayed'; | |
| 404 | |
| 405 String helpLong = | |
| 406 'Get or set the minimum log level that should be displayed.\n' | |
| 407 '\n' | |
| 408 'Log levels (in ascending order): ALL, FINEST, FINER, FINE, CONFIG, ' | |
| 409 'INFO, WARNING, SEVERE, SHOUT, OFF\n' | |
| 410 '\n' | |
| 411 'Default: OFF\n' | |
| 412 '\n' | |
| 413 'Syntax: log\n' | |
| 414 '- Display the current minimum log level.\n' | |
| 415 ' log <level>\n' | |
| 416 '- Set the minimum log level to <level>.\n' | |
| 417 ' log OFF\n' | |
| 418 '- Display no log messages.\n' | |
| 419 ' log ALL\n' | |
| 420 '- Display all log messages.\n'; | |
|
turnidge
2015/08/03 18:16:22
The tabbing/layout here is odd - the commands are
Cutch
2015/08/03 19:29:56
Done.
| |
| 421 } | |
| 422 | |
| 352 class AsyncNextCommand extends DebuggerCommand { | 423 class AsyncNextCommand extends DebuggerCommand { |
| 353 AsyncNextCommand(Debugger debugger) : super(debugger, 'anext', []) { | 424 AsyncNextCommand(Debugger debugger) : super(debugger, 'anext', []) { |
| 354 } | 425 } |
| 355 | 426 |
| 356 Future run(List<String> args) async { | 427 Future run(List<String> args) async { |
| 357 if (debugger.isolatePaused()) { | 428 if (debugger.isolatePaused()) { |
| 358 var event = debugger.isolate.pauseEvent; | 429 var event = debugger.isolate.pauseEvent; |
| 359 if (event.asyncContinuation == null) { | 430 if (event.asyncContinuation == null) { |
| 360 debugger.console.print("No async continuation at this location"); | 431 debugger.console.print("No async continuation at this location"); |
| 361 } else { | 432 } else { |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 874 } | 945 } |
| 875 | 946 |
| 876 String helpShort = 'Refresh debugging information of various sorts'; | 947 String helpShort = 'Refresh debugging information of various sorts'; |
| 877 | 948 |
| 878 String helpLong = | 949 String helpLong = |
| 879 'Refresh debugging information of various sorts.\n' | 950 'Refresh debugging information of various sorts.\n' |
| 880 '\n' | 951 '\n' |
| 881 'Syntax: refresh <subcommand>\n'; | 952 'Syntax: refresh <subcommand>\n'; |
| 882 } | 953 } |
| 883 | 954 |
| 884 class _VMStreamPrinter { | 955 class _ConsoleStreamPrinter { |
| 885 ObservatoryDebugger _debugger; | 956 ObservatoryDebugger _debugger; |
| 886 | 957 |
| 887 _VMStreamPrinter(this._debugger); | 958 _ConsoleStreamPrinter(this._debugger); |
| 888 | 959 Level _minimumLogLevel = Level.OFF; |
|
turnidge
2015/08/03 18:16:22
OFF is ok. Did you consider a different default,
Cutch
2015/08/03 19:29:56
I'll start with OFF but we might want to reconside
| |
| 889 String _savedStream; | 960 String _savedStream; |
| 890 String _savedIsolate; | 961 String _savedIsolate; |
| 891 String _savedLine; | 962 String _savedLine; |
| 892 List<String> _buffer = []; | 963 List<String> _buffer = []; |
| 893 | 964 |
| 894 void onEvent(String streamName, ServiceEvent event) { | 965 void onEvent(String streamName, ServiceEvent event) { |
| 966 if (event.kind == ServiceEvent.kLogging) { | |
| 967 // Check if we should print this log message. | |
| 968 if (event.logRecord['level'].value < _minimumLogLevel.value) { | |
| 969 return; | |
| 970 } | |
| 971 } | |
| 895 String isolateName = event.isolate.name; | 972 String isolateName = event.isolate.name; |
| 896 // If we get a line from a different isolate/stream, flush | 973 // If we get a line from a different isolate/stream, flush |
| 897 // any pending output, even if it is not newline-terminated. | 974 // any pending output, even if it is not newline-terminated. |
| 898 if ((_savedIsolate != null && isolateName != _savedIsolate) || | 975 if ((_savedIsolate != null && isolateName != _savedIsolate) || |
| 899 (_savedStream != null && streamName != _savedStream)) { | 976 (_savedStream != null && streamName != _savedStream)) { |
| 900 flush(); | 977 flush(); |
| 901 } | 978 } |
| 902 String data = event.bytesAsString; | 979 String data; |
| 903 bool hasNewline = data.endsWith('\n'); | 980 bool hasNewline; |
| 981 if (event.kind == ServiceEvent.kLogging) { | |
| 982 data = event.logRecord["message"].valueAsString; | |
|
turnidge
2015/08/03 18:16:22
I'm wondering why valueAsString is showing up here
Cutch
2015/08/03 19:29:56
The messages are transmitted as instances. I think
| |
| 983 hasNewline = true; | |
| 984 } else { | |
| 985 data = event.bytesAsString; | |
| 986 hasNewline = data.endsWith('\n'); | |
| 987 } | |
| 904 if (_savedLine != null) { | 988 if (_savedLine != null) { |
| 905 data = _savedLine + data; | 989 data = _savedLine + data; |
| 906 _savedIsolate = null; | 990 _savedIsolate = null; |
| 907 _savedStream = null; | 991 _savedStream = null; |
| 908 _savedLine = null; | 992 _savedLine = null; |
| 909 } | 993 } |
| 910 var lines = data.split('\n').where((line) => line != '').toList(); | 994 var lines = data.split('\n').where((line) => line != '').toList(); |
| 911 if (lines.isEmpty) { | 995 if (lines.isEmpty) { |
| 912 return; | 996 return; |
| 913 } | 997 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 979 new StepCommand(this), | 1063 new StepCommand(this), |
| 980 new AsyncNextCommand(this), | 1064 new AsyncNextCommand(this), |
| 981 new FinishCommand(this), | 1065 new FinishCommand(this), |
| 982 new BreakCommand(this), | 1066 new BreakCommand(this), |
| 983 new SetCommand(this), | 1067 new SetCommand(this), |
| 984 new ClearCommand(this), | 1068 new ClearCommand(this), |
| 985 new DeleteCommand(this), | 1069 new DeleteCommand(this), |
| 986 new InfoCommand(this), | 1070 new InfoCommand(this), |
| 987 new IsolateCommand(this), | 1071 new IsolateCommand(this), |
| 988 new RefreshCommand(this), | 1072 new RefreshCommand(this), |
| 1073 new LogCommand(this), | |
| 989 ]); | 1074 ]); |
| 990 _stdioPrinter = new _VMStreamPrinter(this); | 1075 _stdioPrinter = new _ConsoleStreamPrinter(this); |
| 991 } | 1076 } |
| 992 | 1077 |
| 993 VM get vm => page.app.vm; | 1078 VM get vm => page.app.vm; |
| 994 | 1079 |
| 995 void updateIsolate(Isolate iso) { | 1080 void updateIsolate(Isolate iso) { |
| 1081 cancelFutureSubscription(_logSubscriptionFuture); | |
| 1082 _logSubscriptionFuture = null; | |
| 996 _isolate = iso; | 1083 _isolate = iso; |
| 997 if (_isolate != null) { | 1084 if (_isolate != null) { |
| 998 if ((exceptions != iso.exceptionsPauseInfo) && | 1085 if ((exceptions != iso.exceptionsPauseInfo) && |
| 999 (iso.exceptionsPauseInfo != null)) { | 1086 (iso.exceptionsPauseInfo != null)) { |
| 1000 exceptions = iso.exceptionsPauseInfo; | 1087 exceptions = iso.exceptionsPauseInfo; |
| 1001 console.print("Now pausing for $exceptions exceptions"); | 1088 console.print("Now pausing for $exceptions exceptions"); |
| 1002 } | 1089 } |
| 1003 | 1090 |
| 1091 _logSubscriptionFuture = vm.listenEventStream(Isolate.kLoggingStream, | |
| 1092 onEvent); | |
|
turnidge
2015/08/03 18:16:22
Streams are per-vm, not per-isolate, so it is not
Cutch
2015/08/03 19:29:56
Done.
| |
| 1093 | |
| 1004 _isolate.reload().then((response) { | 1094 _isolate.reload().then((response) { |
| 1005 // TODO(turnidge): Currently the debugger relies on all libs | 1095 // TODO(turnidge): Currently the debugger relies on all libs |
| 1006 // being loaded. Fix this. | 1096 // being loaded. Fix this. |
| 1007 var pending = []; | 1097 var pending = []; |
| 1008 for (var lib in _isolate.libraries) { | 1098 for (var lib in _isolate.libraries) { |
| 1009 if (!lib.loaded) { | 1099 if (!lib.loaded) { |
| 1010 pending.add(lib.load()); | 1100 pending.add(lib.load()); |
| 1011 } | 1101 } |
| 1012 } | 1102 } |
| 1013 Future.wait(pending).then((_) { | 1103 Future.wait(pending).then((_) { |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1231 _reportBreakpointEvent(event); | 1321 _reportBreakpointEvent(event); |
| 1232 } | 1322 } |
| 1233 break; | 1323 break; |
| 1234 | 1324 |
| 1235 case ServiceEvent.kIsolateStart: | 1325 case ServiceEvent.kIsolateStart: |
| 1236 case ServiceEvent.kGraph: | 1326 case ServiceEvent.kGraph: |
| 1237 case ServiceEvent.kGC: | 1327 case ServiceEvent.kGC: |
| 1238 case ServiceEvent.kInspect: | 1328 case ServiceEvent.kInspect: |
| 1239 break; | 1329 break; |
| 1240 | 1330 |
| 1331 case ServiceEvent.kLogging: | |
| 1332 _stdioPrinter.onEvent(event.logRecord['level'].name, event); | |
| 1333 break; | |
| 1334 | |
| 1241 default: | 1335 default: |
| 1242 console.print('Unrecognized event: $event'); | 1336 console.print('Unrecognized event: $event'); |
| 1243 break; | 1337 break; |
| 1244 } | 1338 } |
| 1245 } | 1339 } |
| 1246 | 1340 |
| 1247 _VMStreamPrinter _stdioPrinter; | 1341 Future<StreamSubscription> _logSubscriptionFuture; |
|
turnidge
2015/08/03 18:16:22
Move this with other subscription futures.
Cutch
2015/08/03 19:29:56
Done.
| |
| 1342 | |
| 1343 _ConsoleStreamPrinter _stdioPrinter; | |
|
turnidge
2015/08/03 18:16:22
Rename _stdioPrinter to _consolePrinter?
Cutch
2015/08/03 19:29:56
Done.
| |
| 1248 | 1344 |
| 1249 void flushStdio() { | 1345 void flushStdio() { |
| 1250 _stdioPrinter.flush(); | 1346 _stdioPrinter.flush(); |
| 1251 } | 1347 } |
| 1252 | 1348 |
| 1253 void onStdout(ServiceEvent event) { | 1349 void onStdout(ServiceEvent event) { |
| 1254 _stdioPrinter.onEvent('stdout', event); | 1350 _stdioPrinter.onEvent('stdout', event); |
| 1255 } | 1351 } |
| 1256 | 1352 |
| 1257 void onStderr(ServiceEvent event) { | 1353 void onStderr(ServiceEvent event) { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1399 } | 1495 } |
| 1400 }); | 1496 }); |
| 1401 } | 1497 } |
| 1402 | 1498 |
| 1403 void onPoll() { | 1499 void onPoll() { |
| 1404 debugger.flushStdio(); | 1500 debugger.flushStdio(); |
| 1405 } | 1501 } |
| 1406 | 1502 |
| 1407 @override | 1503 @override |
| 1408 void detached() { | 1504 void detached() { |
| 1505 debugger.isolate = null; | |
| 1409 cancelFutureSubscription(_isolateSubscriptionFuture); | 1506 cancelFutureSubscription(_isolateSubscriptionFuture); |
| 1410 _isolateSubscriptionFuture = null; | 1507 _isolateSubscriptionFuture = null; |
| 1411 cancelFutureSubscription(_debugSubscriptionFuture); | 1508 cancelFutureSubscription(_debugSubscriptionFuture); |
| 1412 _debugSubscriptionFuture = null; | 1509 _debugSubscriptionFuture = null; |
| 1413 cancelFutureSubscription(_stdoutSubscriptionFuture); | 1510 cancelFutureSubscription(_stdoutSubscriptionFuture); |
| 1414 _stdoutSubscriptionFuture = null; | 1511 _stdoutSubscriptionFuture = null; |
| 1415 cancelFutureSubscription(_stderrSubscriptionFuture); | 1512 cancelFutureSubscription(_stderrSubscriptionFuture); |
| 1416 _stderrSubscriptionFuture = null; | 1513 _stderrSubscriptionFuture = null; |
| 1417 super.detached(); | 1514 super.detached(); |
| 1418 } | 1515 } |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1882 } | 1979 } |
| 1883 }); | 1980 }); |
| 1884 } | 1981 } |
| 1885 | 1982 |
| 1886 void focus() { | 1983 void focus() { |
| 1887 $['textBox'].focus(); | 1984 $['textBox'].focus(); |
| 1888 } | 1985 } |
| 1889 | 1986 |
| 1890 DebuggerInputElement.created() : super.created(); | 1987 DebuggerInputElement.created() : super.created(); |
| 1891 } | 1988 } |
| OLD | NEW |