Skip to content

Commit d016374

Browse files
authored
chore(compass-query-bar, compass-aggregations): add telemetry events for failed ai and success ai COMPASS-7137 (#4752)
1 parent 78ad515 commit d016374

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

packages/compass-aggregations/src/modules/pipeline-builder/pipeline-ai.ts

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type Stage from './stage';
1313
import { updatePipelinePreview } from './builder-helpers';
1414
import type { AtlasServiceNetworkError } from '@mongodb-js/atlas-service/renderer';
1515

16-
const { log, mongoLogId } = createLoggerAndTelemetry('AI-PIPELINE-UI');
16+
const { log, mongoLogId, track } = createLoggerAndTelemetry('AI-PIPELINE-UI');
1717

1818
const emptyPipelineError =
1919
'No pipeline was returned. Please try again with a different prompt.';
@@ -112,15 +112,34 @@ export type AIPipelineSucceededAction = {
112112
type: AIPipelineActionTypes.AIPipelineSucceeded;
113113
};
114114

115-
function logFailed(errorMessage: string) {
116-
log.info(
115+
type FailedResponseTrackMessage = {
116+
editor_view_type: 'stages' | 'text';
117+
errorCode?: number;
118+
errorMessage: string;
119+
errorName: string;
120+
};
121+
122+
function trackAndLogFailed({
123+
editor_view_type,
124+
errorCode,
125+
errorMessage,
126+
errorName,
127+
}: FailedResponseTrackMessage) {
128+
log.warn(
117129
mongoLogId(1_001_000_230),
118130
'AIPipeline',
119131
'AI pipeline request failed',
120132
{
133+
errorCode,
121134
errorMessage,
135+
errorName,
122136
}
123137
);
138+
track('AI Response Failed', () => ({
139+
editor_view_type,
140+
error_code: errorCode,
141+
error_name: errorName,
142+
}));
124143
}
125144

126145
export const runAIPipelineGeneration = (
@@ -136,11 +155,18 @@ export const runAIPipelineGeneration = (
136155
const {
137156
pipelineBuilder: {
138157
aiPipeline: { aiPipelineFetchId: existingFetchId },
158+
pipelineMode,
139159
},
140160
namespace,
141161
dataService: { dataService },
142162
} = getState();
143163

164+
const editor_view_type = pipelineMode === 'builder-ui' ? 'stages' : 'text';
165+
track('AI Prompt Submitted', () => ({
166+
editor_view_type,
167+
user_input_length: userInput.length,
168+
}));
169+
144170
if (aiPipelineFetchId !== -1) {
145171
// Cancel the active request as this one will override.
146172
abort(existingFetchId);
@@ -188,7 +214,12 @@ export const runAIPipelineGeneration = (
188214
// If we already aborted so we ignore the error.
189215
return;
190216
}
191-
logFailed((err as AtlasServiceNetworkError).message);
217+
trackAndLogFailed({
218+
editor_view_type,
219+
errorCode: (err as AtlasServiceNetworkError).statusCode,
220+
errorMessage: (err as AtlasServiceNetworkError).message,
221+
errorName: 'request_error',
222+
});
192223
// We're going to reset input state with this error, show the error in the
193224
// toast instead
194225
if ((err as AtlasServiceNetworkError).statusCode === 401) {
@@ -226,7 +257,12 @@ export const runAIPipelineGeneration = (
226257
throw new Error(emptyPipelineError);
227258
}
228259
} catch (err) {
229-
logFailed((err as Error).message);
260+
trackAndLogFailed({
261+
editor_view_type,
262+
errorCode: (err as AtlasServiceNetworkError).statusCode,
263+
errorMessage: (err as Error).message,
264+
errorName: 'empty_pipeline_error',
265+
});
230266
dispatch({
231267
type: AIPipelineActionTypes.AIPipelineFailed,
232268
errorMessage: (err as Error).message,
@@ -249,6 +285,12 @@ export const runAIPipelineGeneration = (
249285

250286
pipelineBuilder.reset(pipelineText);
251287

288+
track('AI Prompt Generated', () => ({
289+
editor_view_type,
290+
syntax_errors: true,
291+
query_shape: pipelineBuilder.stages.map((stage) => stage.operator),
292+
}));
293+
252294
dispatch({
253295
type: AIPipelineActionTypes.LoadGeneratedPipeline,
254296
stages: pipelineBuilder.stages,

packages/compass-query-bar/src/stores/ai-query-reducer.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('aiQueryReducer', function () {
3737
const mockAtlasService = {
3838
getQueryFromUserInput: sandbox
3939
.stub()
40-
.resolves({ content: { query: { _id: 1 } } }),
40+
.resolves({ content: { query: { filter: '{_id: 1}' } } }),
4141
};
4242

4343
const mockDataService = {

packages/compass-query-bar/src/stores/ai-query-reducer.ts

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,27 @@ export type AIQuerySucceededAction = {
103103
fields: QueryFormFields;
104104
};
105105

106-
function logFailed(errorMessage: string) {
107-
log.info(mongoLogId(1_001_000_198), 'AIQuery', 'AI query request failed', {
106+
type FailedResponseTrackMessage = {
107+
errorCode?: number;
108+
errorName: string;
109+
errorMessage: string;
110+
};
111+
112+
function trackAndLogFailed({
113+
errorCode,
114+
errorName,
115+
errorMessage,
116+
}: FailedResponseTrackMessage) {
117+
log.warn(mongoLogId(1_001_000_198), 'AIQuery', 'AI query request failed', {
118+
errorCode,
108119
errorMessage,
120+
errorName,
109121
});
122+
track('AI Response Failed', () => ({
123+
editor_view_type: 'find',
124+
error_name: errorName,
125+
error_code: errorCode,
126+
}));
110127
}
111128

112129
export const runAIQuery = (
@@ -172,7 +189,11 @@ export const runAIQuery = (
172189
// If we already aborted so we ignore the error.
173190
return;
174191
}
175-
logFailed((err as AtlasServiceNetworkError).message);
192+
trackAndLogFailed({
193+
errorName: 'request_error',
194+
errorCode: (err as AtlasServiceNetworkError).statusCode,
195+
errorMessage: (err as AtlasServiceNetworkError).message,
196+
});
176197
// We're going to reset input state with this error, show the error in the
177198
// toast instead
178199
if ((err as AtlasServiceNetworkError).statusCode === 401) {
@@ -204,14 +225,17 @@ export const runAIQuery = (
204225
return;
205226
}
206227

207-
let fields;
228+
let generatedFields: QueryFormFields;
208229
try {
209-
fields = {
210-
...mapQueryToFormFields(DEFAULT_FIELD_VALUES),
211-
...parseQueryAttributesToFormFields(jsonResponse.content.query),
212-
};
230+
generatedFields = parseQueryAttributesToFormFields(
231+
jsonResponse.content.query
232+
);
213233
} catch (err: any) {
214-
logFailed(err?.message);
234+
trackAndLogFailed({
235+
errorName: 'could_not_parse_fields',
236+
errorCode: (err as AtlasServiceNetworkError).statusCode,
237+
errorMessage: err?.message,
238+
});
215239
dispatch({
216240
type: AIQueryActionTypes.AIQueryFailed,
217241
errorMessage: err?.message,
@@ -220,31 +244,43 @@ export const runAIQuery = (
220244
}
221245

222246
// Error when the response is empty or there is nothing to map.
223-
if (!fields || Object.keys(fields).length === 0) {
247+
if (!generatedFields || Object.keys(generatedFields).length === 0) {
224248
const msg =
225249
'No query was returned from the ai. Consider re-wording your prompt.';
226-
logFailed(msg);
250+
trackAndLogFailed({
251+
errorName: 'no_usable_query_from_ai',
252+
errorMessage: msg,
253+
});
227254
dispatch({
228255
type: AIQueryActionTypes.AIQueryFailed,
229256
errorMessage: msg,
230257
});
231258
return;
232259
}
233260

261+
const queryFields = {
262+
...mapQueryToFormFields(DEFAULT_FIELD_VALUES),
263+
...generatedFields,
264+
};
265+
234266
log.info(
235267
mongoLogId(1_001_000_199),
236268
'AIQuery',
237269
'AI query request succeeded',
238270
{
239271
query: {
240-
...fields,
272+
...queryFields,
241273
},
242274
}
243275
);
276+
track('AI Prompt Generated', () => ({
277+
editor_view_type: 'find',
278+
query_shape: Object.keys(generatedFields),
279+
}));
244280

245281
dispatch({
246282
type: AIQueryActionTypes.AIQuerySucceeded,
247-
fields,
283+
fields: queryFields,
248284
});
249285
};
250286
};

0 commit comments

Comments
 (0)