Skip to content

Commit 79043df

Browse files
authored
fix: error message metric now correctly emitted (#1123)
* fix: error message metric now correctly emitted * lint * 0 is fallback status code * correct field name * lint * fix: error message metric now correctly emitted * fix: isawserror
1 parent e1f403f commit 79043df

File tree

3 files changed

+59
-22
lines changed

3 files changed

+59
-22
lines changed

server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import * as path from 'path'
77
import {
88
ChatTriggerType,
9+
CodeWhispererStreamingServiceException,
910
GenerateAssistantResponseCommandInput,
1011
GenerateAssistantResponseCommandOutput,
1112
SendMessageCommandInput,
@@ -68,7 +69,7 @@ import { ChatSessionManagementService } from '../chat/chatSessionManagementServi
6869
import { ChatTelemetryController } from '../chat/telemetry/chatTelemetryController'
6970
import { QuickAction } from '../chat/quickActions'
7071
import { Metric } from '../../shared/telemetry/metric'
71-
import { getErrorMessage, isAwsError, isNullish, isObject } from '../../shared/utils'
72+
import { getErrorMessage, getHttpStatusCode, isAwsError, isNullish, isObject } from '../../shared/utils'
7273
import { HELP_MESSAGE } from '../chat/constants'
7374
import { TelemetryService } from '../../shared/telemetry/telemetryService'
7475
import {
@@ -1094,9 +1095,22 @@ export class AgenticChatController implements ChatHandlers {
10941095
tabId: string,
10951096
metric: Metric<CombinedConversationEvent>
10961097
): ChatResult | ResponseError<ChatResult> {
1097-
if (isAwsError(err) || (isObject(err) && 'statusCode' in err && typeof err.statusCode === 'number')) {
1098-
metric.setDimension('cwsprChatRepsonseCode', err.statusCode ?? 400)
1099-
this.#telemetryController.emitMessageResponseError(tabId, metric.metric, err.requestId, err.message)
1098+
if (isAwsError(err) || (isObject(err) && typeof getHttpStatusCode(err) === 'number')) {
1099+
let errorMessage: string
1100+
let requestID: string | undefined
1101+
1102+
if (err instanceof CodeWhispererStreamingServiceException) {
1103+
errorMessage = err.message
1104+
requestID = err.$metadata.requestId
1105+
} else {
1106+
errorMessage = 'Not a CodeWhispererStreamingServiceException.'
1107+
if (err instanceof Error || err?.message) {
1108+
errorMessage += ` Error is: ${err.message}`
1109+
}
1110+
}
1111+
1112+
metric.setDimension('cwsprChatResponseCode', getHttpStatusCode(err) ?? 0)
1113+
this.#telemetryController.emitMessageResponseError(tabId, metric.metric, requestID, errorMessage)
11001114
}
11011115

11021116
// return non-model errors back to the client as errors

server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -250,25 +250,25 @@ export class ChatTelemetryController {
250250
requestId?: string,
251251
errorReason?: string
252252
) {
253-
this.emitConversationMetric(
254-
{
255-
name: ChatTelemetryEventName.MessageResponseError,
256-
data: {
257-
cwsprChatHasCodeSnippet: metric.cwsprChatHasCodeSnippet,
258-
cwsprChatTriggerInteraction: metric.cwsprChatTriggerInteraction,
259-
cwsprChatUserIntent: metric.cwsprChatUserIntent,
260-
cwsprChatProgrammingLanguage: metric.cwsprChatProgrammingLanguage,
261-
cwsprChatActiveEditorTotalCharacters: metric.cwsprChatActiveEditorTotalCharacters,
262-
cwsprChatActiveEditorImportCount: metric.cwsprChatActiveEditorImportCount,
263-
cwsprChatRepsonseCode: metric.cwsprChatRepsonseCode,
264-
cwsprChatRequestLength: metric.cwsprChatRequestLength,
265-
cwsprChatConversationType: metric.cwsprChatConversationType,
266-
requestId: requestId,
267-
reasonDesc: getTelemetryReasonDesc(errorReason),
268-
},
253+
this.#telemetry.emitMetric({
254+
name: ChatTelemetryEventName.MessageResponseError,
255+
data: {
256+
cwsprChatHasCodeSnippet: metric.cwsprChatHasCodeSnippet,
257+
cwsprChatTriggerInteraction: metric.cwsprChatTriggerInteraction,
258+
cwsprChatUserIntent: metric.cwsprChatUserIntent,
259+
cwsprChatProgrammingLanguage: metric.cwsprChatProgrammingLanguage,
260+
cwsprChatActiveEditorTotalCharacters: metric.cwsprChatActiveEditorTotalCharacters,
261+
cwsprChatActiveEditorImportCount: metric.cwsprChatActiveEditorImportCount,
262+
cwsprChatRepsonseCode: metric.cwsprChatRepsonseCode,
263+
cwsprChatRequestLength: metric.cwsprChatRequestLength,
264+
cwsprChatConversationType: metric.cwsprChatConversationType,
265+
requestId: requestId,
266+
reasonDesc: getTelemetryReasonDesc(errorReason),
267+
credentialStartUrl: this.#credentialsProvider.getConnectionMetadata()?.sso?.startUrl,
268+
result: 'Succeeded',
269+
[CONVERSATION_ID_METRIC_KEY]: this.getConversationId(tabId),
269270
},
270-
tabId
271-
)
271+
})
272272
}
273273

274274
public enqueueCodeDiffEntry(params: Omit<InsertToCursorPositionParams, 'name'>) {

server/aws-lsp-codewhisperer/src/shared/utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { distance } from 'fastest-levenshtein'
44
import { Suggestion } from './codeWhispererService'
55
import { CodewhispererCompletionType } from './telemetry/types'
66
import { BUILDER_ID_START_URL, crashMonitoringDirName, driveLetterRegex, MISSING_BEARER_TOKEN_ERROR } from './constants'
7+
import { CodeWhispererStreamingServiceException } from '@amzn/codewhisperer-streaming'
8+
import { ServiceException } from '@smithy/smithy-client'
79
import { getAuthFollowUpType } from '../language-server/chat/utils'
810
export type SsoConnectionType = 'builderId' | 'identityCenter' | 'none'
911

@@ -303,6 +305,27 @@ export function isStringOrNull(object: any): object is string | null {
303305
return typeof object === 'string' || object === null
304306
}
305307

308+
// Port of implementation in AWS Toolkit for VSCode
309+
// https://github.com/aws/aws-toolkit-vscode/blob/c22efa03e73b241564c8051c35761eb8620edb83/packages/core/src/shared/errors.ts#L648
310+
export function getHttpStatusCode(err: unknown): number | undefined {
311+
if (hasResponse(err) && err?.$response?.statusCode !== undefined) {
312+
return err?.$response?.statusCode
313+
}
314+
if (hasMetadata(err) && err.$metadata?.httpStatusCode !== undefined) {
315+
return err.$metadata?.httpStatusCode
316+
}
317+
318+
return undefined
319+
}
320+
321+
function hasResponse<T>(error: T): error is T & Pick<ServiceException, '$response'> {
322+
return typeof (error as { $response?: unknown })?.$response === 'object'
323+
}
324+
325+
function hasMetadata<T>(error: T): error is T & Pick<CodeWhispererStreamingServiceException, '$metadata'> {
326+
return typeof (error as { $metadata?: unknown })?.$metadata === 'object'
327+
}
328+
306329
export function hasConnectionExpired(error: any) {
307330
if (error instanceof Error) {
308331
const authFollowType = getAuthFollowUpType(error)

0 commit comments

Comments
 (0)