Skip to content

Commit acd0cbc

Browse files
authored
telemetry(amazonq): Add webview load metric for amazonq (aws#5518)
## Problem - We have no detailed information on how long the amazonq webview took for first meaningful paint - We have no way to keep track whether or not webviews fail to load or any error events are that emitted ## Solution - The onready event gets fired when "UI is initialized and rendered". See https://github.com/aws/mynah-ui/blob/main/docs/PROPERTIES.md#onready - Listen to error events on the window and forward them to the vscode side ## I'm trying to answer the following questions with these metrics : - How long are webviews taking to load? - How long until they're interactive? - What errors are occurring in the webview?
1 parent 3645ec4 commit acd0cbc

File tree

6 files changed

+77
-1
lines changed

6 files changed

+77
-1
lines changed

packages/core/src/amazonq/webview/messages/messageDispatcher.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,41 @@ import { MessagePublisher } from '../../messages/messagePublisher'
88
import { MessageListener } from '../../messages/messageListener'
99
import { TabType } from '../ui/storages/tabsStorage'
1010
import { getLogger } from '../../../shared/logger'
11+
import { amazonqMark } from '../../../shared/performance/marks'
12+
import { telemetry } from '../../../shared/telemetry'
1113

1214
export function dispatchWebViewMessagesToApps(
1315
webview: Webview,
1416
webViewToAppsMessagePublishers: Map<TabType, MessagePublisher<any>>
1517
) {
1618
webview.onDidReceiveMessage((msg) => {
19+
if (msg.command === 'ui-is-ready') {
20+
/**
21+
* ui-is-ready isn't associated to any tab so just record the telemetry event and continue.
22+
* This would be equivalent of the duration between "user clicked open q" and "ui has become available"
23+
* NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview.
24+
*/
25+
26+
telemetry.webview_load.emit({
27+
webviewName: 'amazonq',
28+
duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration,
29+
result: 'Succeeded',
30+
})
31+
performance.clearMarks(amazonqMark.uiReady)
32+
performance.clearMarks(amazonqMark.open)
33+
return
34+
}
35+
36+
if (msg.type === 'error') {
37+
const event = msg.event === 'webview_load' ? telemetry.webview_load : telemetry.webview_error
38+
event.emit({
39+
webviewName: 'amazonqChat',
40+
result: 'Failed',
41+
reasonDesc: msg.errorMessage,
42+
})
43+
return
44+
}
45+
1746
const appMessagePublisher = webViewToAppsMessagePublishers.get(msg.tabType)
1847
if (appMessagePublisher === undefined) {
1948
return

packages/core/src/amazonq/webview/ui/connector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class Connector {
6464
private readonly tabsStorage
6565
private readonly amazonqCommonsConnector: AmazonQCommonsConnector
6666

67-
private isUIReady = false
67+
isUIReady = false
6868

6969
constructor(props: ConnectorProps) {
7070
this.sendMessageToExtension = props.sendMessageToExtension

packages/core/src/amazonq/webview/ui/main.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
2222
let mynahUI: MynahUI
2323
// eslint-disable-next-line prefer-const
2424
let connector: Connector
25+
26+
window.addEventListener('error', (e) => {
27+
const { error, message } = e
28+
ideApi.postMessage({
29+
type: 'error',
30+
event: connector.isUIReady ? 'webview_error' : 'webview_load',
31+
errorMessage: error ? error.toString() : message,
32+
})
33+
})
34+
2535
const tabsStorage = new TabsStorage({
2636
onTabTimeout: (tabID) => {
2737
mynahUI.addChatItem(tabID, {

packages/core/src/amazonq/webview/webView.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { MessagePublisher } from '../messages/messagePublisher'
2121
import { TabType } from './ui/storages/tabsStorage'
2222
import { deactivateInitialViewBadge, shouldShowBadge } from '../util/viewBadgeHandler'
2323
import { telemetry } from '../../shared/telemetry/telemetry'
24+
import { amazonqMark } from '../../shared/performance/marks'
2425

2526
export class AmazonQChatViewProvider implements WebviewViewProvider {
2627
public static readonly viewType = 'aws.AmazonQChatView'
@@ -64,6 +65,8 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
6465
webviewView.webview
6566
)
6667

68+
performance.mark(amazonqMark.open)
69+
6770
// badge is shown, emit telemetry for first time an existing, unscoped user tries Q
6871
// note: this will fire on any not-properly-scoped Q entry.
6972
// this means we can't tie it directly to the badge although it is hinted at
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export const amazonqMark = {
7+
open: 'amazonq/webview/open',
8+
uiReady: 'amazonq/webview/uiReady',
9+
}

packages/core/src/shared/telemetry/vscodeTelemetry.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@
295295
"name": "functionName",
296296
"type": "string",
297297
"description": "The name of the function"
298+
},
299+
{
300+
"name": "webviewName",
301+
"type": "string",
302+
"description": "The name of the webview"
298303
}
299304
],
300305
"metrics": [
@@ -1122,6 +1127,26 @@
11221127
],
11231128
"passive": true,
11241129
"trackPerformance": true
1130+
},
1131+
{
1132+
"name": "webview_load",
1133+
"description": "Represents a webview load event",
1134+
"metadata": [
1135+
{
1136+
"type": "webviewName",
1137+
"required": true
1138+
}
1139+
]
1140+
},
1141+
{
1142+
"name": "webview_error",
1143+
"description": "Represents an error that occurs in a webview",
1144+
"metadata": [
1145+
{
1146+
"type": "webviewName",
1147+
"required": true
1148+
}
1149+
]
11251150
}
11261151
]
11271152
}

0 commit comments

Comments
 (0)