Skip to content

Commit 4223081

Browse files
authored
feat(telemetry): add telemetry for restoring and forgetting connections (#5454)
Includes a new telemetry event, 'auth_modifyConnection' which will begin to encompass changes to connections.
1 parent d677876 commit 4223081

File tree

6 files changed

+86
-15
lines changed

6 files changed

+86
-15
lines changed

packages/amazonq/test/unit/codewhisperer/util/authUtil.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ describe('AuthUtil', async function () {
290290
)
291291
await authUtil.secondaryAuth.useNewConnection(conn3)
292292

293-
await authUtil.clearExtraConnections() // method under test
293+
await authUtil.clearExtraConnections('test') // method under test
294294

295295
// Only the conn that AuthUtil is using is remaining
296296
assert.deepStrictEqual(

packages/core/src/auth/secondaryAuth.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import { Auth } from './auth'
1212
import { once, onceChanged } from '../shared/utilities/functionUtils'
1313
import { isNonNullable } from '../shared/utilities/tsUtils'
1414
import { ToolIdStateKey } from '../shared/globalState'
15-
import { Connection, SsoConnection, StatefulConnection } from './connection'
15+
import { Connection, getTelemetryMetadataForConn, SsoConnection, StatefulConnection } from './connection'
1616
import { indent } from '../shared/utilities/textUtilities'
17+
import { telemetry } from '../shared/telemetry/telemetry'
1718

1819
export type ToolId = 'codecatalyst' | 'codewhisperer' | 'testId'
1920

@@ -244,13 +245,28 @@ export class SecondaryAuth<T extends Connection = Connection> {
244245

245246
// Used to lazily restore persisted connections.
246247
// Kind of clunky. We need an async module loader layer to make things ergonomic.
247-
public readonly restoreConnection: () => Promise<T | undefined> = once(async () => {
248+
public readonly restoreConnection: (source?: string) => Promise<T | undefined> = once(async (source?: string) => {
248249
try {
249-
await this.auth.tryAutoConnect()
250-
this.#savedConnection = await this.loadSavedConnection()
251-
this.#onDidChangeActiveConnection.fire(this.activeConnection)
250+
return await telemetry.auth_modifyConnection.run(async () => {
251+
telemetry.record({
252+
source,
253+
action: 'restore',
254+
connectionState: 'undefined',
255+
})
256+
await this.auth.tryAutoConnect()
257+
this.#savedConnection = await this.loadSavedConnection()
258+
this.#onDidChangeActiveConnection.fire(this.activeConnection)
252259

253-
return this.#savedConnection
260+
const conn = this.#activeConnection
261+
if (conn) {
262+
telemetry.record({
263+
connectionState: this.auth.getConnectionState(conn),
264+
...(await getTelemetryMetadataForConn(conn)),
265+
})
266+
}
267+
268+
return this.#savedConnection
269+
})
254270
} catch (err) {
255271
getLogger().warn(`auth (${this.toolId}): failed to restore connection: %s`, err)
256272
}

packages/core/src/codecatalyst/auth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ export class CodeCatalystAuthenticationProvider {
151151
}
152152
}
153153

154-
public async restore() {
155-
await this.secondaryAuth.restoreConnection()
154+
public async restore(source?: string) {
155+
await this.secondaryAuth.restoreConnection(source)
156156
}
157157

158158
private async accessDeniedExceptionHandler(showReauthPrompt: boolean = true) {

packages/core/src/codewhisperer/activation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ export async function activate(context: ExtContext): Promise<void> {
294294
vscode.commands.registerCommand('aws.amazonq.openEditorAtRange', openEditorAtRange)
295295
)
296296

297-
await auth.restore()
298-
await auth.clearExtraConnections()
297+
await auth.restore('startup')
298+
await auth.clearExtraConnections('startup')
299299

300300
if (auth.isConnectionExpired()) {
301301
auth.showReauthenticatePrompt().catch((e) => {

packages/core/src/codewhisperer/util/authUtil.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
scopesGumby,
2626
isIdcSsoConnection,
2727
hasExactScopes,
28+
getTelemetryMetadataForConn,
2829
} from '../../auth/connection'
2930
import { getLogger } from '../../shared/logger'
3031
import { Commands } from '../../shared/vscode/commands2'
@@ -35,6 +36,7 @@ import { showReauthenticateMessage } from '../../shared/utilities/messages'
3536
import { showAmazonQWalkthroughOnce } from '../../amazonq/onboardingPage/walkthrough'
3637
import { setContext } from '../../shared/vscode/setContext'
3738
import { isInDevEnv } from '../../shared/vscode/env'
39+
import { telemetry } from '../../shared/telemetry/telemetry'
3840

3941
/** Backwards compatibility for connections w pre-chat scopes */
4042
export const codeWhispererCoreScopes = [...scopesCodeWhispererCore]
@@ -99,7 +101,7 @@ export class AuthUtil {
99101
'Amazon Q',
100102
isValidCodeWhispererCoreConnection
101103
)
102-
public readonly restore = () => this.secondaryAuth.restoreConnection()
104+
public readonly restore = (source?: string) => this.secondaryAuth.restoreConnection(source)
103105

104106
public constructor(public readonly auth = Auth.instance) {}
105107

@@ -402,15 +404,29 @@ export class AuthUtil {
402404
* auth connections that the Amazon Q extension has cached. We need to remove these
403405
* as they are irrelevant to the Q extension and can cause issues.
404406
*/
405-
public async clearExtraConnections(): Promise<void> {
407+
public async clearExtraConnections(source: string): Promise<void> {
406408
const currentQConn = this.conn
407409
// Q currently only maintains 1 connection at a time, so we assume everything else is extra.
408410
// IMPORTANT: In the case Q starts to manage multiple connections, this implementation will need to be updated.
409411
const allOtherConnections = (await this.auth.listConnections()).filter((c) => c.id !== currentQConn?.id)
410412
for (const conn of allOtherConnections) {
411413
getLogger().warn(`forgetting extra amazon q connection: %O`, conn)
412-
// in a Dev Env the connection may be used by code catalyst, so we forget instead of fully deleting
413-
isInDevEnv() ? await this.auth.forgetConnection(conn) : await this.auth.deleteConnection(conn)
414+
await telemetry.auth_modifyConnection.run(async () => {
415+
telemetry.record({
416+
connectionState: Auth.instance.getConnectionState(conn) ?? 'undefined',
417+
source,
418+
...(await getTelemetryMetadataForConn(conn)),
419+
})
420+
421+
if (isInDevEnv()) {
422+
telemetry.record({ action: 'forget' })
423+
// in a Dev Env the connection may be used by code catalyst, so we forget instead of fully deleting
424+
await this.auth.forgetConnection(conn)
425+
} else {
426+
telemetry.record({ action: 'delete' })
427+
await this.auth.deleteConnection(conn)
428+
}
429+
})
414430
}
415431
}
416432
}

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@
270270
"name": "awsRegion",
271271
"type": "string",
272272
"description": "An AWS region."
273+
},
274+
{
275+
"name": "connectionState",
276+
"type": "string",
277+
"description": "A detailed state of a specific auth connection. Use `authStatus` for a higher level view of an extension's general connection."
273278
}
274279
],
275280
"metrics": [
@@ -1039,6 +1044,40 @@
10391044
}
10401045
],
10411046
"passive": true
1047+
},
1048+
{
1049+
"name": "auth_modifyConnection",
1050+
"description": "An auth connection was modified in some way, e.g. deleted, updated",
1051+
"metadata": [
1052+
{
1053+
"type": "action",
1054+
"required": true
1055+
},
1056+
{
1057+
"type": "authScopes",
1058+
"required": false
1059+
},
1060+
{
1061+
"type": "connectionState",
1062+
"required": true
1063+
},
1064+
{
1065+
"type": "credentialStartUrl",
1066+
"required": false
1067+
},
1068+
{
1069+
"type": "source",
1070+
"required": true
1071+
},
1072+
{
1073+
"type": "ssoRegistrationClientId",
1074+
"required": false
1075+
},
1076+
{
1077+
"type": "ssoRegistrationExpiresAt",
1078+
"required": false
1079+
}
1080+
]
10421081
}
10431082
]
10441083
}

0 commit comments

Comments
 (0)