From 8d912665813d309292a833619e4f45339d973a11 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Thu, 7 Nov 2024 17:06:09 -0800 Subject: [PATCH 1/5] Include screen information with unified_analytics events --- .../src/shared/analytics/_analytics_web.dart | 60 +++++++++++-------- packages/devtools_app/pubspec.yaml | 2 +- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart index 6e31105ecdf..cb14cd7999a 100644 --- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart +++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart @@ -56,6 +56,7 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { // than a fixed list of fields. See // https://github.com/flutter/devtools/pull/3281#discussion_r692376353. external factory GtagEventDevTools({ + String? screen, String? event_category, String? event_label, // Event e.g., gaScreenViewEvent, gaSelectEvent, etc. String? send_to, // UA ID of target GA property to receive event data. @@ -115,6 +116,7 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { }); factory GtagEventDevTools._create({ + required String screen, required String event_category, required String event_label, String? send_to, @@ -123,6 +125,7 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { ScreenAnalyticsMetrics? screenMetrics, }) { return GtagEventDevTools( + screen: screen, event_category: event_category, event_label: event_label, send_to: send_to, @@ -192,6 +195,8 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { ); } + external String? get screen; + // Custom dimensions: external String? get user_app; external String? get user_build; @@ -226,6 +231,7 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { extension type GtagExceptionDevTools._(JSObject _) implements GtagException { external factory GtagExceptionDevTools({ + String? screen, String? description, bool fatal, @@ -419,18 +425,16 @@ Future shouldShowAnalyticsConsentMessage() async { return shouldShow; } -void screen( - String screenName, [ - int value = 0, -]) { +void screen(String screenName, [int value = 0]) { _log.fine('Event: Screen(screenName:$screenName, value:$value)'); final gtagEvent = GtagEventDevTools._create( + screen: screenName, event_category: gac.screenViewEvent, event_label: gac.init, value: value, send_to: gaDevToolsPropertyId(), ); - _sendEventForScreen(screenName, gtagEvent); + _sendEventForScreen(gtagEvent); } String _operationKey(String screenName, String timedOperation) { @@ -570,13 +574,14 @@ void _timing( 'durationMicros:$durationMicros)', ); final gtagEvent = GtagEventDevTools._create( + screen: screenName, event_category: gac.timingEvent, event_label: timedOperation, value: durationMicros, send_to: gaDevToolsPropertyId(), screenMetrics: screenMetrics, ); - _sendEventForScreen(screenName, gtagEvent); + _sendEventForScreen(gtagEvent); } /// Sends an analytics event to signal that something in DevTools was selected. @@ -595,6 +600,7 @@ void select( 'nonInteraction:$nonInteraction)', ); final gtagEvent = GtagEventDevTools._create( + screen: screenName, event_category: gac.selectEvent, event_label: selectedItem, value: value, @@ -603,7 +609,7 @@ void select( screenMetrics: screenMetricsProvider != null ? screenMetricsProvider() : null, ); - _sendEventForScreen(screenName, gtagEvent); + _sendEventForScreen(gtagEvent); } /// Sends an analytics event to signal that something in DevTools was viewed. @@ -620,6 +626,7 @@ void impression( 'item:$item)', ); final gtagEvent = GtagEventDevTools._create( + screen: screenName, event_category: gac.impressionEvent, event_label: item, non_interaction: true, @@ -627,7 +634,7 @@ void impression( screenMetrics: screenMetricsProvider != null ? screenMetricsProvider() : null, ); - _sendEventForScreen(screenName, gtagEvent); + _sendEventForScreen(gtagEvent); } String? _lastGaError; @@ -879,9 +886,9 @@ void legacyOnSetupAnalytics() { jsHookupListenerForGA(); } -void _sendEventForScreen(String screenName, GtagEventDevTools gtagEvent) { +void _sendEventForScreen(GtagEventDevTools gtagEvent) { GTag.event( - screenName, + gtagEvent.screen!, gaEventProvider: () => gtagEvent, ); final uaEvent = _uaEventFromGtagEvent(gtagEvent); @@ -892,6 +899,7 @@ ua.Event _uaEventFromGtagEvent(GtagEventDevTools gtagEvent) { // Any dimensions or metrics that have a null value will be removed from // the event data in the [ua.Event.devtoolsEvent] constructor. return ua.Event.devtoolsEvent( + screen: gtagEvent.screen!, eventCategory: gtagEvent.event_category!, label: gtagEvent.event_label!, value: gtagEvent.value, @@ -912,21 +920,23 @@ ua.Event _uaEventFromGtagEvent(GtagEventDevTools gtagEvent) { // all of the below metrics will be non-null at the same time, it is okay to // include all the metrics here. The [ua.Event.devtoolsEvent] constructor // will remove any entries with a null value from the sent event parameters. - uiDurationMicros: gtagEvent.ui_duration_micros, - rasterDurationMicros: gtagEvent.raster_duration_micros, - shaderCompilationDurationMicros: - gtagEvent.shader_compilation_duration_micros, - traceEventCount: gtagEvent.trace_event_count, - cpuSampleCount: gtagEvent.cpu_sample_count, - cpuStackDepth: gtagEvent.cpu_stack_depth, - heapDiffObjectsBefore: gtagEvent.heap_diff_objects_before, - heapDiffObjectsAfter: gtagEvent.heap_diff_objects_after, - heapObjectsTotal: gtagEvent.heap_objects_total, - rootSetCount: gtagEvent.root_set_count, - rowCount: gtagEvent.row_count, - inspectorTreeControllerId: gtagEvent.inspector_tree_controller_id, - androidAppId: gtagEvent.android_app_id, - iosBundleId: gtagEvent.ios_bundle_id, + additionalMetrics: { + 'uiDurationMicros': gtagEvent.ui_duration_micros, + 'rasterDurationMicros': gtagEvent.raster_duration_micros, + 'shaderCompilationDurationMicros': + gtagEvent.shader_compilation_duration_micros, + 'traceEventCount': gtagEvent.trace_event_count, + 'cpuSampleCount': gtagEvent.cpu_sample_count, + 'cpuStackDepth': gtagEvent.cpu_stack_depth, + 'heapDiffObjectsBefore': gtagEvent.heap_diff_objects_before, + 'heapDiffObjectsAfter': gtagEvent.heap_diff_objects_after, + 'heapObjectsTotal': gtagEvent.heap_objects_total, + 'rootSetCount': gtagEvent.root_set_count, + 'rowCount': gtagEvent.row_count, + 'inspectorTreeControllerId': gtagEvent.inspector_tree_controller_id, + 'androidAppId': gtagEvent.android_app_id, + 'iosBundleId': gtagEvent.ios_bundle_id, + }, ); } diff --git a/packages/devtools_app/pubspec.yaml b/packages/devtools_app/pubspec.yaml index a37b60b9bc1..a96b21d49ae 100644 --- a/packages/devtools_app/pubspec.yaml +++ b/packages/devtools_app/pubspec.yaml @@ -53,7 +53,7 @@ dependencies: stack_trace: ^1.12.0 stream_channel: ^2.1.1 string_scanner: ^1.1.0 - unified_analytics: ^6.1.5 + unified_analytics: ^7.0.0 vm_service: ^14.2.5 vm_service_protos: ^1.0.0 vm_snapshot_analysis: ^0.7.6 From b930a0c9d761e4b9b0ad4384be5b41adea893932 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 8 Nov 2024 09:28:53 -0800 Subject: [PATCH 2/5] rename method --- .../lib/src/shared/analytics/_analytics_web.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart index cb14cd7999a..7bd96adc337 100644 --- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart +++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart @@ -434,7 +434,7 @@ void screen(String screenName, [int value = 0]) { value: value, send_to: gaDevToolsPropertyId(), ); - _sendEventForScreen(gtagEvent); + _sendEvent(gtagEvent); } String _operationKey(String screenName, String timedOperation) { @@ -581,7 +581,7 @@ void _timing( send_to: gaDevToolsPropertyId(), screenMetrics: screenMetrics, ); - _sendEventForScreen(gtagEvent); + _sendEvent(gtagEvent); } /// Sends an analytics event to signal that something in DevTools was selected. @@ -609,7 +609,7 @@ void select( screenMetrics: screenMetricsProvider != null ? screenMetricsProvider() : null, ); - _sendEventForScreen(gtagEvent); + _sendEvent(gtagEvent); } /// Sends an analytics event to signal that something in DevTools was viewed. @@ -634,7 +634,7 @@ void impression( screenMetrics: screenMetricsProvider != null ? screenMetricsProvider() : null, ); - _sendEventForScreen(gtagEvent); + _sendEvent(gtagEvent); } String? _lastGaError; @@ -886,7 +886,7 @@ void legacyOnSetupAnalytics() { jsHookupListenerForGA(); } -void _sendEventForScreen(GtagEventDevTools gtagEvent) { +void _sendEvent(GtagEventDevTools gtagEvent) { GTag.event( gtagEvent.screen!, gaEventProvider: () => gtagEvent, From a9b65a9500bef1382d5661e943dc35e1107b1bbd Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 8 Nov 2024 10:29:38 -0800 Subject: [PATCH 3/5] Use custom metrics class --- .../src/shared/analytics/_analytics_web.dart | 111 +++++++++++++++--- .../devtools_app/web/devtools_analytics.js | 3 + 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart index 7bd96adc337..c5f9e9826ac 100644 --- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart +++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart @@ -111,8 +111,11 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { int? root_set_count, // metric10 int? row_count, // metric11 int? inspector_tree_controller_id, // metric12 + // Deep Link screen metrics. See [DeepLinkScreenMetrics]. String? android_app_id, //metric13 String? ios_bundle_id, //metric14 + // Inspector screen metrics. See [InspectorScreenMetrics]. + bool? is_v2_inspector, // metric15 }); factory GtagEventDevTools._create({ @@ -192,6 +195,9 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { ios_bundle_id: screenMetrics is DeepLinkScreenMetrics ? screenMetrics.iosBundleId : null, + // [InspectorScreenMetrics] + is_v2_inspector: + screenMetrics is InspectorScreenMetrics ? screenMetrics.isV2 : null, ); } @@ -227,6 +233,7 @@ extension type GtagEventDevTools._(JSObject _) implements GtagEvent { external int? get inspector_tree_controller_id; external String? get android_app_id; external String? get ios_bundle_id; + external bool? get is_v2_inspector; } extension type GtagExceptionDevTools._(JSObject _) implements GtagException { @@ -280,8 +287,11 @@ extension type GtagExceptionDevTools._(JSObject _) implements GtagException { int? root_set_count, // metric10 int? row_count, // metric11 int? inspector_tree_controller_id, // metric12 + // Deep Link screen metrics. See [DeepLinkScreenMetrics]. String? android_app_id, //metric13 String? ios_bundle_id, //metric14 + // Inspector screen metrics. See [InspectorScreenMetrics]. + bool? is_v2_inspector, // metric15 }); factory GtagExceptionDevTools._create( @@ -353,6 +363,9 @@ extension type GtagExceptionDevTools._(JSObject _) implements GtagException { ios_bundle_id: screenMetrics is DeepLinkScreenMetrics ? screenMetrics.iosBundleId : null, + // [InspectorScreenMetrics] + is_v2_inspector: + screenMetrics is InspectorScreenMetrics ? screenMetrics.isV2 : null, ); } @@ -386,6 +399,7 @@ extension type GtagExceptionDevTools._(JSObject _) implements GtagException { external int? get inspector_tree_controller_id; external String? get android_app_id; external String? get ios_bundle_id; + external bool? get is_v2_inspector; } /// Whether google analytics are enabled. @@ -920,23 +934,24 @@ ua.Event _uaEventFromGtagEvent(GtagEventDevTools gtagEvent) { // all of the below metrics will be non-null at the same time, it is okay to // include all the metrics here. The [ua.Event.devtoolsEvent] constructor // will remove any entries with a null value from the sent event parameters. - additionalMetrics: { - 'uiDurationMicros': gtagEvent.ui_duration_micros, - 'rasterDurationMicros': gtagEvent.raster_duration_micros, - 'shaderCompilationDurationMicros': + additionalMetrics: _DevToolsEventMetrics( + uiDurationMicros: gtagEvent.ui_duration_micros, + rasterDurationMicros: gtagEvent.raster_duration_micros, + shaderCompilationDurationMicros: gtagEvent.shader_compilation_duration_micros, - 'traceEventCount': gtagEvent.trace_event_count, - 'cpuSampleCount': gtagEvent.cpu_sample_count, - 'cpuStackDepth': gtagEvent.cpu_stack_depth, - 'heapDiffObjectsBefore': gtagEvent.heap_diff_objects_before, - 'heapDiffObjectsAfter': gtagEvent.heap_diff_objects_after, - 'heapObjectsTotal': gtagEvent.heap_objects_total, - 'rootSetCount': gtagEvent.root_set_count, - 'rowCount': gtagEvent.row_count, - 'inspectorTreeControllerId': gtagEvent.inspector_tree_controller_id, - 'androidAppId': gtagEvent.android_app_id, - 'iosBundleId': gtagEvent.ios_bundle_id, - }, + traceEventCount: gtagEvent.trace_event_count, + cpuSampleCount: gtagEvent.cpu_sample_count, + cpuStackDepth: gtagEvent.cpu_stack_depth, + heapDiffObjectsBefore: gtagEvent.heap_diff_objects_before, + heapDiffObjectsAfter: gtagEvent.heap_diff_objects_after, + heapObjectsTotal: gtagEvent.heap_objects_total, + rootSetCount: gtagEvent.root_set_count, + rowCount: gtagEvent.row_count, + inspectorTreeControllerId: gtagEvent.inspector_tree_controller_id, + isV2Inspector: gtagEvent.is_v2_inspector, + androidAppId: gtagEvent.android_app_id, + iosBundleId: gtagEvent.ios_bundle_id, + ), ); } @@ -979,3 +994,67 @@ ua.Event _uaEventFromGtagException( }, ); } + +final class _DevToolsEventMetrics extends ua.CustomMetrics { + _DevToolsEventMetrics({ + required this.rasterDurationMicros, + required this.shaderCompilationDurationMicros, + required this.traceEventCount, + required this.cpuSampleCount, + required this.cpuStackDepth, + required this.heapDiffObjectsBefore, + required this.heapDiffObjectsAfter, + required this.heapObjectsTotal, + required this.rootSetCount, + required this.rowCount, + required this.inspectorTreeControllerId, + required this.isV2Inspector, + required this.androidAppId, + required this.iosBundleId, + required this.uiDurationMicros, + }); + + // [PerformanceScreenMetrics] + final int? uiDurationMicros; + final int? rasterDurationMicros; + final int? shaderCompilationDurationMicros; + final int? traceEventCount; + + // [ProfilerScreenMetrics] + final int? cpuSampleCount; + final int? cpuStackDepth; + + // [MemoryScreenMetrics] + final int? heapDiffObjectsBefore; + final int? heapDiffObjectsAfter; + final int? heapObjectsTotal; + + // [InspectorScreenMetrics] + final int? rootSetCount; + final int? rowCount; + final int? inspectorTreeControllerId; + final bool? isV2Inspector; + + // [DeepLinkScreenMetrics] + final String? androidAppId; + final String? iosBundleId; + + @override + Map toMap() => ({ + 'uiDurationMicros': uiDurationMicros, + 'rasterDurationMicros': rasterDurationMicros, + 'shaderCompilationDurationMicros': shaderCompilationDurationMicros, + 'traceEventCount': traceEventCount, + 'cpuSampleCount': cpuSampleCount, + 'cpuStackDepth': cpuStackDepth, + 'heapDiffObjectsBefore': heapDiffObjectsBefore, + 'heapDiffObjectsAfter': heapDiffObjectsAfter, + 'heapObjectsTotal': heapObjectsTotal, + 'rootSetCount': rootSetCount, + 'rowCount': rowCount, + 'inspectorTreeControllerId': inspectorTreeControllerId, + 'isV2Inspector': isV2Inspector, + 'androidAppId': androidAppId, + 'iosBundleId': iosBundleId, + }..removeWhere((key, value) => value == null)) as Map; +} diff --git a/packages/devtools_app/web/devtools_analytics.js b/packages/devtools_app/web/devtools_analytics.js index f44f93a0336..cb6ddb0f838 100644 --- a/packages/devtools_app/web/devtools_analytics.js +++ b/packages/devtools_app/web/devtools_analytics.js @@ -44,6 +44,9 @@ function initializeGA() { 'metric10': 'root_set_count', 'metric11': 'row_count', 'metric12': 'inspector_tree_controller_id', + 'metric13': 'android_app_id', + 'metric14': 'ios_bundle_id', + 'metric15': 'is_v2_inspector', }, cookie_flags: 'SameSite=None;Secure', }); From 901990c7ef528f609b78759e1a39cde6451e6ffe Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Mon, 11 Nov 2024 09:29:51 -0800 Subject: [PATCH 4/5] bump dtd --- packages/devtools_app/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools_app/pubspec.yaml b/packages/devtools_app/pubspec.yaml index a96b21d49ae..df00f01ae16 100644 --- a/packages/devtools_app/pubspec.yaml +++ b/packages/devtools_app/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: devtools_app_shared: ^0.2.2 devtools_extensions: ^0.3.0-wip devtools_shared: ^10.0.1 - dtd: ^2.3.0 + dtd: ^2.4.0 file: ^7.0.0 file_selector: ^1.0.0 fixnum: ^1.1.0 From 19bfec8a43abbc6f673d66a0c7c6831df272b3b0 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Mon, 11 Nov 2024 11:15:33 -0800 Subject: [PATCH 5/5] try casting --- .../devtools_app/lib/src/shared/analytics/_analytics_web.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart index c5f9e9826ac..1cd77d5fd33 100644 --- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart +++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart @@ -1056,5 +1056,6 @@ final class _DevToolsEventMetrics extends ua.CustomMetrics { 'isV2Inspector': isV2Inspector, 'androidAppId': androidAppId, 'iosBundleId': iosBundleId, - }..removeWhere((key, value) => value == null)) as Map; + }..removeWhere((key, value) => value == null)) + .cast(); }