From 09f756b9a1d89e941652625372636ed66d293f44 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 16 Mar 2020 18:04:58 +0000 Subject: [PATCH] [ dart:developer ] Added `filterKey` optional parameter to TimelineTask constructors. Providing `filterKey` will result in all timeline events associated with the TimelineTask including a `filterKey` entry in their arguments map, set to the value provided in the constructor. This will allow for a consistent way for tooling to filter asynchronous timeline events. Fixes https://github.com/dart-lang/sdk/issues/40861 Change-Id: I06d3f9c73f06c2ff0e495f1b6a57fcf357d625a8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/139312 Commit-Queue: Ben Konyi Reviewed-by: Kenzie Schmoll Reviewed-by: Siva Annamalai --- CHANGELOG.md | 8 ++++++ .../service/get_vm_timeline_rpc_test.dart | 15 +++++++---- sdk/lib/developer/timeline.dart | 25 +++++++++++++++++-- sdk_nnbd/lib/developer/timeline.dart | 25 +++++++++++++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c994ce29fb..58bf9ec65fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ was allowed. The value of that getter on a `TypeError` was the same string as returned by `toString`, so it is still available. +#### `dart:developer` + +* The constructors for `TimelineTask` now accept an optional `filterKey` + parameter. If provided, the arguments for all events associated with the task + will contain an entry named `filterKey`, set to the value of the `filterKey` + parameter provided in the constructor. This will be used by tooling to allow + for better filtering of timeline events. + #### `dart:html` * **Breaking Change**: Changed the return type of several html native methods diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart index f68010b6c6e..25bcec05ec3 100644 --- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart +++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart @@ -15,7 +15,7 @@ primeTimeline() { Timeline.instantSync('ISYNC', arguments: {'fruit': 'banana'}); Timeline.finishSync(); TimelineTask parentTask = TimelineTask.withTaskId(42); - TimelineTask task = TimelineTask(parent: parentTask); + TimelineTask task = TimelineTask(parent: parentTask, filterKey: 'testFilter'); task.start('TASK1', arguments: {'task1-start-key': 'task1-start-value'}); task.instant('ITASK', arguments: {'task1-instant-key': 'task1-instant-value'}); @@ -133,17 +133,22 @@ var tests = [ expect(eventsContains(dartEvents, 'E', 'apple'), isTrue); expect( eventsContains(dartEvents, 'b', 'TASK1', { + 'filterKey': 'testFilter', 'task1-start-key': 'task1-start-value', 'parentId': 42.toRadixString(16) }), isTrue); expect( - eventsContains(dartEvents, 'e', 'TASK1', - {'task1-finish-key': 'task1-finish-value'}), + eventsContains(dartEvents, 'e', 'TASK1', { + 'filterKey': 'testFilter', + 'task1-finish-key': 'task1-finish-value', + }), isTrue); expect( - eventsContains(dartEvents, 'n', 'ITASK', - {'task1-instant-key': 'task1-instant-value'}), + eventsContains(dartEvents, 'n', 'ITASK', { + 'filterKey': 'testFilter', + 'task1-instant-key': 'task1-instant-value', + }), isTrue); expect(eventsContains(dartEvents, 'q', 'ITASK'), isFalse); expect(eventsContains(dartEvents, 'B', 'peach'), isTrue); diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart index de1ec2cd45b..cd1b43d95a2 100644 --- a/sdk/lib/developer/timeline.dart +++ b/sdk/lib/developer/timeline.dart @@ -186,8 +186,13 @@ class TimelineTask { /// If [parent] is provided, the parent's task ID is provided as argument /// 'parentId' when [start] is called. In DevTools, this argument will result /// in this [TimelineTask] being linked to the [parent] [TimelineTask]. - TimelineTask({TimelineTask parent}) + /// + /// If [filterKey] is provided, a property named `filterKey` will be inserted + /// into the arguments of each event associated with this task. The + /// `filterKey` will be set to the value of [filterKey]. + TimelineTask({TimelineTask parent, String filterKey}) : _parent = parent, + _filterKey = filterKey, _taskId = _getNextAsyncId() {} /// Create a task with an explicit [taskId]. This is useful if you are @@ -196,8 +201,13 @@ class TimelineTask { /// Important note: only provide task IDs which have been obtained as a /// result of invoking [TimelineTask.pass]. Specifying a custom ID can lead /// to ID collisions, resulting in incorrect rendering of timeline events. - TimelineTask.withTaskId(int taskId) + /// + /// If [filterKey] is provided, a property named `filterKey` will be inserted + /// into the arguments of each event associated with this task. The + /// `filterKey` will be set to the value of [filterKey]. + TimelineTask.withTaskId(int taskId, {String filterKey}) : _parent = null, + _filterKey = filterKey, _taskId = taskId { ArgumentError.checkNotNull(taskId, 'taskId'); } @@ -212,6 +222,7 @@ class TimelineTask { block._start({ if (arguments != null) ...arguments, if (_parent != null) 'parentId': _parent._taskId.toRadixString(16), + if (_filterKey != null) _kFilterKey: _filterKey, }); } @@ -224,6 +235,10 @@ class TimelineTask { if (arguments != null) { instantArguments = new Map.from(arguments); } + if (_filterKey != null) { + instantArguments ??= {}; + instantArguments[_kFilterKey] = _filterKey; + } _reportTaskEvent( _taskId, 'n', 'Dart', name, _argumentsAsJson(instantArguments)); } @@ -237,6 +252,10 @@ class TimelineTask { if (_stack.length == 0) { throw new StateError('Uneven calls to start and finish'); } + if (_filterKey != null) { + arguments ??= {}; + arguments[_kFilterKey] = _filterKey; + } // Pop top item off of stack. var block = _stack.removeLast(); block._finish(arguments); @@ -254,7 +273,9 @@ class TimelineTask { return r; } + static const String _kFilterKey = 'filterKey'; final TimelineTask _parent; + final String _filterKey; final int _taskId; final List<_AsyncBlock> _stack = []; } diff --git a/sdk_nnbd/lib/developer/timeline.dart b/sdk_nnbd/lib/developer/timeline.dart index c41d8145f4c..cc9cf4045ee 100644 --- a/sdk_nnbd/lib/developer/timeline.dart +++ b/sdk_nnbd/lib/developer/timeline.dart @@ -186,8 +186,13 @@ class TimelineTask { /// If [parent] is provided, the parent's task ID is provided as argument /// 'parentId' when [start] is called. In DevTools, this argument will result /// in this [TimelineTask] being linked to the [parent] [TimelineTask]. - TimelineTask({TimelineTask? parent}) + /// + /// If [filterKey] is provided, a property named `filterKey` will be inserted + /// into the arguments of each event associated with this task. The + /// `filterKey` will be set to the value of [filterKey]. + TimelineTask({TimelineTask? parent, String? filterKey}) : _parent = parent, + _filterKey = filterKey, _taskId = _getNextAsyncId() {} /// Create a task with an explicit [taskId]. This is useful if you are @@ -196,8 +201,13 @@ class TimelineTask { /// Important note: only provide task IDs which have been obtained as a /// result of invoking [TimelineTask.pass]. Specifying a custom ID can lead /// to ID collisions, resulting in incorrect rendering of timeline events. - TimelineTask.withTaskId(int taskId) + /// + /// If [filterKey] is provided, a property named `filterKey` will be inserted + /// into the arguments of each event associated with this task. The + /// `filterKey` will be set to the value of [filterKey]. + TimelineTask.withTaskId(int taskId, {String? filterKey}) : _parent = null, + _filterKey = filterKey, _taskId = taskId { // TODO: When NNBD is complete, delete the following line. ArgumentError.checkNotNull(taskId, 'taskId'); @@ -222,6 +232,7 @@ class TimelineTask { } } if (_parent != null) map['parentId'] = _parent!._taskId.toRadixString(16); + if (_filterKey != null) map[_kFilterKey] = _filterKey; block._start(map); } @@ -235,6 +246,10 @@ class TimelineTask { if (arguments != null) { instantArguments = new Map.from(arguments); } + if (_filterKey != null) { + instantArguments ??= {}; + instantArguments[_kFilterKey] = _filterKey; + } _reportTaskEvent( _taskId, 'n', 'Dart', name, _argumentsAsJson(instantArguments)); } @@ -248,6 +263,10 @@ class TimelineTask { if (_stack.length == 0) { throw new StateError('Uneven calls to start and finish'); } + if (_filterKey != null) { + arguments ??= {}; + arguments[_kFilterKey] = _filterKey; + } // Pop top item off of stack. var block = _stack.removeLast(); block._finish(arguments); @@ -265,7 +284,9 @@ class TimelineTask { return r; } + static const String _kFilterKey = 'filterKey'; final TimelineTask? _parent; + final String? _filterKey; final int _taskId; final List<_AsyncBlock> _stack = []; }