Skip to content

Commit 3f729f7

Browse files
author
Anna Gringauze
authored
Fix issues in DevTools load time reporting (#1518)
* Fix issues in DevTools load time reporting - Store dwdsStats on appServices for an app to make sure we are updating an reporting the same stats for an app. Previously, if the app services already existed, we would use incorrect object to report the stats, causing incorrect times and missing reports. - Set the times on dwdsStats when debug request arrives to make sure times are recorded only from the time when the user starts debugging. - Process `pageReady` events from any DevTools page, as DevTools does not always show the debugger page first. - Enabled previously skipped tests. Closes:#1517 * Format
1 parent 9cfdbdd commit 3f729f7

File tree

7 files changed

+72
-55
lines changed

7 files changed

+72
-55
lines changed

dwds/CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
## 13.0.0-dev
22
- Change wording of paused overlay from "Paused in Dart DevTools" to "Paused"
3-
- Allow sending back the Dart DevTools URL from DWDS instead of launching
3+
- Allow sending back the Dart DevTools URL from DWDS instead of launching
44
Dart DevTools, to support embedding Dart DevTools in Chrome DevTools.
55
- Temporarily disable the paused in debugger overlay.
66
- Add `SdkConfiguration` and `SdkConfigurationProvider` classes to allow
77
for lazily created SDK configurations.
8+
- Fix an issue in reporting DevTools stats where the DevTools load time was
9+
not always recorded.
810
- Add an `ide` query parameter to the Dart DevTools URL for analytics.
911

1012
**Breaking changes:**
11-
- `Dwds.start` and `ExpressionCompilerService` now take
12-
`sdkConfigurationProvider` argument instead of separate SDK-related file
13+
- `Dwds.start` and `ExpressionCompilerService` now take
14+
`sdkConfigurationProvider` argument instead of separate SDK-related file
1315
paths.
1416

1517
## 12.1.0

dwds/lib/dwds.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ class Dwds {
8989

9090
Future<DebugConnection> debugConnection(AppConnection appConnection) async {
9191
if (!_enableDebugging) throw StateError('Debugging is not enabled.');
92-
final dwdsStats = DwdsStats(DateTime.now());
93-
var appDebugServices =
94-
await _devHandler.loadAppServices(appConnection, dwdsStats);
92+
var appDebugServices = await _devHandler.loadAppServices(appConnection);
9593
await appDebugServices.chromeProxyService.isInitialized;
9694
return DebugConnection(appDebugServices);
9795
}

dwds/lib/src/dwds_vm_client.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,9 @@ void _processSendEvent(Map<String, dynamic> event,
150150
switch (type) {
151151
case 'DevtoolsEvent':
152152
{
153-
var screen = payload == null ? null : payload['screen'];
154153
var action = payload == null ? null : payload['action'];
155-
if (screen == 'debugger' && action == 'pageReady') {
156-
if (dwdsStats.isFirstDebuggerReady()) {
154+
if (action == 'pageReady') {
155+
if (dwdsStats.isFirstDebuggerReady) {
157156
if (dwdsStats.devToolsStart != null) {
158157
emitEvent(DwdsEvent.devToolsLoad(DateTime.now()
159158
.difference(dwdsStats.devToolsStart)
@@ -165,6 +164,7 @@ void _processSendEvent(Map<String, dynamic> event,
165164
.inMilliseconds));
166165
}
167166
} else {
167+
print('Ignoring already received event: $event');
168168
_logger.warning('Ignoring already received event: $event');
169169
}
170170
} else {

dwds/lib/src/events.dart

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,27 @@ import 'package:vm_service/vm_service.dart';
1010

1111
class DwdsStats {
1212
/// The time when the user starts the debugger.
13-
final DateTime debuggerStart;
13+
DateTime _debuggerStart;
14+
DateTime get debuggerStart => _debuggerStart;
1415

1516
/// The time when dwds launches DevTools.
16-
DateTime devToolsStart;
17-
18-
var _isDebuggerReady = false;
17+
DateTime _devToolsStart;
18+
DateTime get devToolsStart => _devToolsStart;
19+
20+
/// Records and returns weither the debugger is ready.
21+
bool _isFirstDebuggerReady = true;
22+
bool get isFirstDebuggerReady {
23+
var wasReady = _isFirstDebuggerReady;
24+
_isFirstDebuggerReady = false;
25+
return wasReady;
26+
}
1927

20-
/// Records and returns whether the debugger became ready.
21-
bool isFirstDebuggerReady() {
22-
final wasReady = _isDebuggerReady;
23-
_isDebuggerReady = true;
24-
return !wasReady;
28+
void updateLoadTime({DateTime debuggerStart, DateTime devToolsStart}) {
29+
_debuggerStart = debuggerStart;
30+
_devToolsStart = devToolsStart;
2531
}
2632

27-
DwdsStats(this.debuggerStart);
33+
DwdsStats();
2834
}
2935

3036
class DwdsEventKind {

dwds/lib/src/handlers/dev_handler.dart

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,13 @@ class DevHandler {
226226
);
227227
}
228228

229-
Future<AppDebugServices> loadAppServices(
230-
AppConnection appConnection, DwdsStats dwdsStats) async {
229+
Future<AppDebugServices> loadAppServices(AppConnection appConnection) async {
231230
var appId = appConnection.request.appId;
232231
if (_servicesByAppId[appId] == null) {
233232
var debugService = await _startLocalDebugService(
234233
await _chromeConnection(), appConnection);
235234
var appServices = await _createAppDebugServices(
236-
appConnection.request.appId, debugService, dwdsStats);
235+
appConnection.request.appId, debugService);
237236
unawaited(appServices.chromeProxyService.remoteDebugger.onClose.first
238237
.whenComplete(() async {
239238
await appServices.close();
@@ -329,11 +328,10 @@ class DevHandler {
329328
'Otherwise check the docs for the tool you are using.'))));
330329
return;
331330
}
332-
333-
var dwdsStats = DwdsStats(DateTime.now());
331+
var debuggerStart = DateTime.now();
334332
AppDebugServices appServices;
335333
try {
336-
appServices = await loadAppServices(appConnection, dwdsStats);
334+
appServices = await loadAppServices(appConnection);
337335
} catch (_) {
338336
var error = 'Unable to connect debug services to your '
339337
'application. Most likely this means you are trying to '
@@ -374,7 +372,10 @@ class DevHandler {
374372
..promptExtension = false))));
375373

376374
appServices.connectedInstanceId = appConnection.request.instanceId;
377-
dwdsStats.devToolsStart = DateTime.now();
375+
appServices.dwdsStats.updateLoadTime(
376+
debuggerStart: debuggerStart,
377+
devToolsStart: DateTime.now(),
378+
);
378379
await _launchDevTools(
379380
appServices.chromeProxyService.remoteDebugger,
380381
_constructDevToolsUri(appServices.debugService.uri,
@@ -448,12 +449,14 @@ class DevHandler {
448449
}
449450

450451
Future<AppDebugServices> _createAppDebugServices(
451-
String appId, DebugService debugService, DwdsStats dwdsStats) async {
452+
String appId, DebugService debugService) async {
453+
var dwdsStats = DwdsStats();
452454
var webdevClient = await DwdsVmClient.create(debugService, dwdsStats);
453455
if (_spawnDds) {
454456
await debugService.startDartDevelopmentService();
455457
}
456-
var appDebugService = AppDebugServices(debugService, webdevClient);
458+
var appDebugService =
459+
AppDebugServices(debugService, webdevClient, dwdsStats);
457460
var encodedUri = await debugService.encodedUri;
458461
_logger.info('Debug service listening on $encodedUri\n');
459462
await appDebugService.chromeProxyService.remoteDebugger
@@ -477,7 +480,6 @@ class DevHandler {
477480
// Waits for a `DevToolsRequest` to be sent from the extension background
478481
// when the extension is clicked.
479482
extensionDebugger.devToolsRequestStream.listen((devToolsRequest) async {
480-
var dwdsStats = DwdsStats(DateTime.now());
481483
var connection = _appConnectionByAppId[devToolsRequest.appId];
482484
if (connection == null) {
483485
// TODO(grouma) - Ideally we surface this warning to the extension so
@@ -486,6 +488,7 @@ class DevHandler {
486488
'Not connected to an app with id: ${devToolsRequest.appId}');
487489
return;
488490
}
491+
var debuggerStart = DateTime.now();
489492
var appId = devToolsRequest.appId;
490493
if (_servicesByAppId[appId] == null) {
491494
var debugService = await DebugService.start(
@@ -510,7 +513,6 @@ class DevHandler {
510513
var appServices = await _createAppDebugServices(
511514
devToolsRequest.appId,
512515
debugService,
513-
dwdsStats,
514516
);
515517
var encodedUri = await debugService.encodedUri;
516518
extensionDebugger.sendEvent('dwds.encodedUri', encodedUri);
@@ -525,8 +527,8 @@ class DevHandler {
525527
extensionDebugConnections.add(DebugConnection(appServices));
526528
_servicesByAppId[appId] = appServices;
527529
}
528-
final encodedUri = await _servicesByAppId[appId].debugService.encodedUri;
529-
dwdsStats.devToolsStart = DateTime.now();
530+
final appServices = _servicesByAppId[appId];
531+
final encodedUri = await appServices.debugService.encodedUri;
530532

531533
// If we only want the URI, this means we are embedding Dart DevTools in
532534
// Chrome DevTools. Therefore return early.
@@ -538,11 +540,12 @@ class DevHandler {
538540
extensionDebugger.sendEvent('dwds.devtoolsUri', devToolsUri);
539541
return;
540542
}
541-
542543
final devToolsUri = _constructDevToolsUri(
543544
encodedUri,
544545
ideQueryParam: 'DebugExtension',
545546
);
547+
appServices.dwdsStats.updateLoadTime(
548+
debuggerStart: debuggerStart, devToolsStart: DateTime.now());
546549
await _launchDevTools(extensionDebugger, devToolsUri);
547550
});
548551
}

dwds/lib/src/services/app_debug_services.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
import 'dart:async';
88

99
import '../dwds_vm_client.dart';
10+
import '../events.dart';
1011
import 'chrome_proxy_service.dart' show ChromeProxyService;
1112
import 'debug_service.dart';
1213

1314
/// A container for all the services required for debugging an application.
1415
class AppDebugServices {
1516
final DebugService debugService;
1617
final DwdsVmClient dwdsVmClient;
18+
final DwdsStats dwdsStats;
1719

1820
ChromeProxyService get chromeProxyService =>
1921
debugService.chromeProxyService as ChromeProxyService;
@@ -28,7 +30,7 @@ class AppDebugServices {
2830
/// We only allow a given app to be debugged in a single tab at a time.
2931
String connectedInstanceId;
3032

31-
AppDebugServices(this.debugService, this.dwdsVmClient);
33+
AppDebugServices(this.debugService, this.dwdsVmClient, this.dwdsStats);
3234

3335
Future<void> close() =>
3436
_closed ??= Future.wait([debugService.close(), dwdsVmClient.close()]);

dwds/test/events_test.dart

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ void main() {
9696
return result;
9797
}
9898

99+
/// Runs [action] and waits for an event matching [eventMatcher].
100+
Future<T> expectEventsDuring<T>(
101+
List<Matcher> eventMatchers, Future<T> Function() action,
102+
{Timeout timeout}) async {
103+
// The events stream is a broadcast stream so start listening
104+
// before the action.
105+
final events = eventMatchers.map((matcher) => expectLater(
106+
pipe(context.testServer.dwds.events, timeout: timeout),
107+
emitsThrough(matcher)));
108+
final result = await action();
109+
await Future.wait(events);
110+
return result;
111+
}
112+
99113
setUpAll(() async {
100114
setCurrentLogWriter();
101115
initialEvents = expectLater(
@@ -117,34 +131,26 @@ void main() {
117131
await context.tearDown();
118132
});
119133

120-
test('emits DEVTOOLS_LAUNCH event', () async {
121-
await expectEventDuring(
122-
matchesEvent(DwdsEventKind.devtoolsLaunch, {}),
134+
test('emits DEBUGGER_READY and DEVTOOLS_LOAD events', () async {
135+
await expectEventsDuring(
136+
[
137+
matchesEvent(DwdsEventKind.debuggerReady, {
138+
'elapsedMilliseconds': isNotNull,
139+
}),
140+
matchesEvent(DwdsEventKind.devToolsLoad, {
141+
'elapsedMilliseconds': isNotNull,
142+
}),
143+
],
123144
() => keyboard.sendChord([Keyboard.alt, 'd']),
124145
);
125146
});
126147

127-
test('emits DEBUGGER_READY event', () async {
128-
await expectEventDuring(
129-
matchesEvent(DwdsEventKind.debuggerReady, {
130-
'elapsedMilliseconds': isNotNull,
131-
}),
132-
() => keyboard.sendChord([Keyboard.alt, 'd']),
133-
);
134-
},
135-
skip: 'Enable after publishing of '
136-
'https://github.com/flutter/devtools/pull/3346');
137-
138-
test('emits DEVTOOLS_LOAD events', () async {
148+
test('emits DEVTOOLS_LAUNCH event', () async {
139149
await expectEventDuring(
140-
matchesEvent(DwdsEventKind.devToolsLoad, {
141-
'elapsedMilliseconds': isNotNull,
142-
}),
150+
matchesEvent(DwdsEventKind.devtoolsLaunch, {}),
143151
() => keyboard.sendChord([Keyboard.alt, 'd']),
144152
);
145-
},
146-
skip: 'Enable after publishing of '
147-
'https://github.com/flutter/devtools/pull/3346');
153+
});
148154

149155
test('events can be listened to multiple times', () async {
150156
events.listen((_) {});

0 commit comments

Comments
 (0)