Skip to content

Add metrics for devtools IPL #1404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
## 11.3.1-dev

- Add metrics measuring DevTools Initial Page Load time.
- Add `ext.dwds.sendEvent` service extension to dwds so other tools
can send events to the debugger.
Event format:
```
{
'type': '<event type>',
'payload': {
'screen: '<screen name>',
'action: '<action name>',
}
}
```
Currently supported event values:
```
{
'type: 'DevtoolsEvent',
'payload': {
'screen': 'debugger'
'action': 'screenReady'
}
}
```

## 11.3.0

- Update SDK constraint to `>=2.14.0 <3.0.0`
Expand Down
31 changes: 30 additions & 1 deletion dwds/lib/src/dwds_vm_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class DwdsVmClient {
await client.dispose();
}();

static Future<DwdsVmClient> create(DebugService debugService) async {
static Future<DwdsVmClient> create(
DebugService debugService, DwdsStats dwdsStats) async {
// Set up hot restart as an extension.
var requestController = StreamController<Map<String, Object>>();
var responseController = StreamController<Map<String, Object>>();
Expand Down Expand Up @@ -154,6 +155,12 @@ class DwdsVmClient {
});
await client.registerService('ext.dwds.screenshot', 'DWDS');

client.registerServiceCallback('ext.dwds.sendEvent', (event) async {
_processSendEvent(event, chromeProxyService, dwdsStats);
return {'result': Success().toJson()};
});
await client.registerService('ext.dwds.sendEvent', 'DWDS');

client.registerServiceCallback('ext.dwds.emitEvent', (event) async {
emitEvent(DwdsEvent(
event['type'] as String, event['payload'] as Map<String, dynamic>));
Expand Down Expand Up @@ -187,6 +194,28 @@ class DwdsVmClient {
}
}

void _processSendEvent(Map<String, dynamic> event,
ChromeProxyService chromeProxyService, DwdsStats dwdsStats) {
var type = event['type'] as String;
var payload = event['payload'] as Map<String, dynamic>;
switch (type) {
case 'DevtoolsEvent':
{
var screen = payload == null ? null : payload['screen'];
var action = payload == null ? null : payload['action'];
if (screen == 'debugger' &&
action == 'screenReady' &&
dwdsStats.isFirstDebuggerReady()) {
emitEvent(DwdsEvent.debuggerReady(DateTime.now()
.difference(dwdsStats.debuggerStart)
.inMilliseconds));
} else {
_logger.warning('Ignoring unknown event: $event');
}
}
}
}

Future<void> _disableBreakpointsAndResume(
VmService client, ChromeProxyService chromeProxyService) async {
_logger.info('Attempting to disable breakpoints and resume the isolate');
Expand Down
78 changes: 78 additions & 0 deletions dwds/lib/src/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,90 @@

import 'dart:async';

import 'package:vm_service/vm_service.dart';

class DwdsStats {
/// The time when the user starts the debugger.
final DateTime debuggerStart;

var _isDebuggerReady = false;

/// Records and returns whether the debugger became ready.
bool isFirstDebuggerReady() {
final wasReady = _isDebuggerReady;
_isDebuggerReady = true;
return !wasReady;
}

DwdsStats(this.debuggerStart);
}

class DwdsEventKind {
static const String compilerUpdateDependencies =
'COMPILER_UPDATE_DEPENDENCIES';
static const String devtoolsLaunch = 'DEVTOOLS_LAUNCH';
static const String evaluate = 'EVALUATE';
static const String evaluateInFrame = 'EVALUATE_IN_FRAME';
static const String getIsolate = 'GET_ISOLATE';
static const String getScripts = 'GET_SCRIPTS';
static const String getSourceReport = 'GET_SOURCE_REPORT';
static const String debuggerReady = 'DEBUGGER_READY';
static const String getVM = 'GET_VM';
static const String resume = 'RESUME';

DwdsEventKind._();
}

class DwdsEvent {
final String type;
final Map<String, dynamic> payload;

DwdsEvent(this.type, this.payload);

DwdsEvent.compilerUpdateDependencies(String entrypoint)
: this(DwdsEventKind.compilerUpdateDependencies, {
'entrypoint': entrypoint,
});

DwdsEvent.devtoolsLaunch() : this(DwdsEventKind.devtoolsLaunch, {});

DwdsEvent.evaluate(String expression, Response result)
: this(DwdsEventKind.evaluate, {
'expression': expression,
'success': result != null && result is InstanceRef,
if (result != null && result is ErrorRef) 'error': result,
});

DwdsEvent.evaluateInFrame(String expression, Response result)
: this(DwdsEventKind.evaluateInFrame, {
'expression': expression,
'success': result != null && result is InstanceRef,
if (result != null && result is ErrorRef) 'error': result,
});

DwdsEvent.getIsolate() : this(DwdsEventKind.getIsolate, {});

DwdsEvent.getScripts() : this(DwdsEventKind.getScripts, {});

DwdsEvent.getVM() : this(DwdsEventKind.getVM, {});

DwdsEvent.resume(String step) : this(DwdsEventKind.resume, {'step': step});

DwdsEvent.getSourceReport() : this(DwdsEventKind.getSourceReport, {});

DwdsEvent.debuggerReady(int elapsedMilliseconds)
: this(DwdsEventKind.debuggerReady, {
'elapsedMilliseconds': elapsedMilliseconds,
});

void addException(dynamic exception) {
payload['exception'] = exception;
}

void addElapsedTime(int elapsedMilliseconds) {
payload['elapsedMilliseconds'] = elapsedMilliseconds;
}

@override
String toString() {
return 'TYPE: $type Payload: $payload';
Expand Down
17 changes: 11 additions & 6 deletions dwds/lib/src/handlers/dev_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,13 @@ class DevHandler {
}

Future<AppDebugServices> loadAppServices(AppConnection appConnection) async {
var dwdsStats = DwdsStats(DateTime.now());
var appId = appConnection.request.appId;
if (_servicesByAppId[appId] == null) {
var debugService = await _startLocalDebugService(
await _chromeConnection(), appConnection);
var appServices = await _createAppDebugServices(
appConnection.request.appId, debugService);
appConnection.request.appId, debugService, dwdsStats);
unawaited(appServices.chromeProxyService.remoteDebugger.onClose.first
.whenComplete(() async {
await appServices.close();
Expand Down Expand Up @@ -434,8 +435,8 @@ class DevHandler {
}

Future<AppDebugServices> _createAppDebugServices(
String appId, DebugService debugService) async {
var webdevClient = await DwdsVmClient.create(debugService);
String appId, DebugService debugService, DwdsStats dwdsStats) async {
var webdevClient = await DwdsVmClient.create(debugService, dwdsStats);
if (_spawnDds) {
await debugService.startDartDevelopmentService();
}
Expand Down Expand Up @@ -463,6 +464,7 @@ class DevHandler {
// Waits for a `DevToolsRequest` to be sent from the extension background
// when the extension is clicked.
extensionDebugger.devToolsRequestStream.listen((devToolsRequest) async {
var dwdsStats = DwdsStats(DateTime.now());
var connection = _appConnectionByAppId[devToolsRequest.appId];
if (connection == null) {
// TODO(grouma) - Ideally we surface this warning to the extension so
Expand Down Expand Up @@ -491,8 +493,11 @@ class DevHandler {
expressionCompiler: _expressionCompiler,
spawnDds: _spawnDds,
);
var appServices =
await _createAppDebugServices(devToolsRequest.appId, debugService);
var appServices = await _createAppDebugServices(
devToolsRequest.appId,
debugService,
dwdsStats,
);
var encodedUri = await debugService.encodedUri;
extensionDebugger.sendEvent('dwds.encodedUri', encodedUri);
unawaited(appServices.chromeProxyService.remoteDebugger.onClose.first
Expand All @@ -516,7 +521,7 @@ class DevHandler {
// TODO(grouma) - We may want to log the debugServiceUri if we don't launch
// DevTools so that users can manually connect.
if (!_serveDevTools) return;
emitEvent(DwdsEvent('DEVTOOLS_LAUNCH', {}));
emitEvent(DwdsEvent.devtoolsLaunch());
await remoteDebugger.sendCommand('Target.createTarget', params: {
'newWindow': true,
'url': Uri(
Expand Down
Loading