Skip to content

Commit ae6c10b

Browse files
[ES|QL] Send failures to our monitoring cluster (elastic#269027)
## Summary Right now we are not sending the errors to our monitoring cluster. This will route the errors to monitoring. We are using: - apm for client side - otel and logger for server side Note: UI behavior preserved at every site (fallbacks/toasts/return-undefined all retained). The only thing that changed is that the errors now reach Cloud observability where you can filter by `labels.app:esql` AND `labels.error_type:<X>`. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1 parent 57fa1bf commit ae6c10b

15 files changed

Lines changed: 242 additions & 108 deletions

File tree

packages/kbn-optimizer/limits.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pageLoadAssetSize:
5656
embeddableAlertsTable: 6524
5757
enterpriseSearch: 37565
5858
entityStore: 9718
59-
esql: 21193
59+
esql: 25000
6060
esqlDataGrid: 10209
6161
esUiShared: 101220
6262
evals: 6375

src/platform/packages/private/kbn-esql-editor/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export { helpLabel } from './src/editor_menu/menu_i18n';
1818
export { registerESQLEditorAnalyticsEvents } from './src/telemetry/events_registration';
1919
export { ESQLEditorTelemetryService } from './src/telemetry/telemetry_service';
2020

21+
export { reportEsqlError } from './src/report_error';
22+
export type { ReportEsqlErrorOptions } from './src/report_error';
23+
2124
// React.lazy support
2225
// eslint-disable-next-line import/no-default-export
2326
export default ESQLEditor;

src/platform/packages/private/kbn-esql-editor/src/editor_menu/help_popover.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { LanguageDocumentationFlyout } from '@kbn/language-documentation';
3434
import { getCategorizationField } from '@kbn/aiops-utils';
3535
import { prettifyQueryTemplate } from '@kbn/esql-language/src/commands/registry/options/recommended_queries/utils';
3636
import { ESQLEditorTelemetryService } from '../telemetry/telemetry_service';
37+
import { reportEsqlError } from '../report_error';
3738
import type { ESQLEditorDeps } from '../types';
3839
import { useEsqlEditorActions } from '../editor_actions_context';
3940
import { helpLabel } from './menu_i18n';
@@ -157,7 +158,7 @@ export const HelpPopover: React.FC<{
157158
lastFetchedQueries.current = extensions.recommendedQueries;
158159
}
159160
} catch (error) {
160-
// Do nothing if the extensions are not available
161+
reportEsqlError(error, { errorType: 'HelpExtensionsFetch' });
161162
}
162163
};
163164

src/platform/packages/private/kbn-esql-editor/src/editor_visor/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { NLInput } from './nl_input';
2929
import { visorStyles, visorWidthPercentage, dropdownWidthPercentage } from './visor.styles';
3030
import type { ESQLEditorDeps } from '../types';
3131
import { useNlToEsqlCheck } from '../hooks/use_nl_to_esql_check';
32+
import { reportEsqlError } from '../report_error';
3233

3334
export { VisorMode } from './mode_selector';
3435

@@ -125,6 +126,7 @@ export function QuickSearchVisor({
125126
setNlValue('');
126127
}
127128
} catch (error) {
129+
reportEsqlError(error, { errorType: 'NlToEsql' });
128130
const message =
129131
(error as { body?: { message?: string } })?.body?.message ??
130132
i18n.translate('esqlEditor.visor.nlError', {

src/platform/packages/private/kbn-esql-editor/src/hooks/use_query_validation.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
} from '../helpers';
2222
import { createTimedCallbacks } from '../telemetry/timed_callbacks';
2323
import { addQueriesToCache } from '../history_local_storage';
24+
import { reportEsqlError } from '../report_error';
2425
import type { DataErrorsControl } from '../types';
2526

2627
interface ValidationLatencyTracking {
@@ -275,7 +276,9 @@ export const useQueryValidation = ({
275276
return;
276277
}
277278
queryValidation(subscription)
278-
.catch(() => {})
279+
.catch((error) => {
280+
reportEsqlError(error, { errorType: 'ValidationDebounced' });
281+
})
279282
.finally(() => {
280283
subscription.active = false;
281284
});

src/platform/packages/private/kbn-esql-editor/src/lookup_join/use_lookup_index_privileges.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
1212
import type { SecurityHasPrivilegesResponse } from '@elastic/elasticsearch/lib/api/types';
1313
import { memoize } from 'lodash';
1414
import { LOOKUP_INDEX_PRIVILEGES_ROUTE } from '@kbn/esql-types';
15+
import { reportEsqlError } from '../report_error';
1516
import type { ESQLEditorDeps } from '../types';
1617

1718
type IndexPrivileges = SecurityHasPrivilegesResponse['index'];
@@ -54,8 +55,7 @@ export const useLookupIndexPrivileges = () => {
5455
try {
5556
return await http!.get<IndexPrivileges>(LOOKUP_INDEX_PRIVILEGES_ROUTE, options);
5657
} catch (error) {
57-
// eslint-disable-next-line no-console
58-
console.error('Error fetching user privileges:', error);
58+
reportEsqlError(error, { errorType: 'LookupIndexPrivilegesFetch' });
5959
return {};
6060
}
6161
},
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import { apm } from '@elastic/apm-rum';
11+
12+
type LabelValue = string | number | boolean | null | undefined;
13+
14+
export interface ReportEsqlErrorOptions {
15+
errorType: string;
16+
labels?: Record<string, LabelValue>;
17+
}
18+
19+
export const reportEsqlError = (
20+
error: unknown,
21+
{ errorType, labels }: ReportEsqlErrorOptions
22+
): void => {
23+
const captured = error instanceof Error ? error : new Error(String(error));
24+
apm.captureError(captured, {
25+
labels: { app: 'esql', error_type: errorType, ...labels },
26+
});
27+
};

src/platform/packages/private/kbn-esql-editor/src/telemetry/telemetry_service.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,26 @@ import {
1919
ESQL_RESOURCE_BROWSER_ITEM_TOGGLED,
2020
ESQL_RESOURCE_BROWSER_OPENED,
2121
} from './events_registration';
22+
import { reportEsqlError } from '../report_error';
23+
24+
jest.mock('../report_error', () => ({
25+
reportEsqlError: jest.fn(),
26+
}));
2227

2328
describe('ESQLEditorTelemetryService', () => {
2429
let mockAnalytics: jest.Mocked<AnalyticsServiceStart>;
2530
let telemetryService: ESQLEditorTelemetryService;
26-
let consoleLogSpy: jest.SpyInstance;
2731

2832
beforeEach(() => {
2933
mockAnalytics = {
3034
reportEvent: jest.fn(),
3135
} as unknown as jest.Mocked<AnalyticsServiceStart>;
3236

3337
telemetryService = new ESQLEditorTelemetryService(mockAnalytics);
34-
35-
// Mock console.log to avoid test output pollution
36-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
3738
});
3839

3940
afterEach(() => {
4041
jest.clearAllMocks();
41-
consoleLogSpy.mockRestore();
4242
});
4343

4444
describe('trackLookupJoinHoverActionShown', () => {
@@ -156,10 +156,9 @@ describe('ESQLEditorTelemetryService', () => {
156156
telemetryService.trackLookupJoinHoverActionShown(invalidEncodedMessage);
157157

158158
expect(mockAnalytics.reportEvent).not.toHaveBeenCalled();
159-
expect(consoleLogSpy).toHaveBeenCalledWith(
160-
'Failed to parse hover message command data',
161-
expect.any(Error)
162-
);
159+
expect(reportEsqlError).toHaveBeenCalledWith(expect.any(Error), {
160+
errorType: 'HoverMessageParse',
161+
});
163162
});
164163
});
165164
});

src/platform/packages/private/kbn-esql-editor/src/telemetry/telemetry_service.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
} from './events_registration';
3838
import type { IndexEditorCommandArgs } from '../lookup_join/use_lookup_index_editor';
3939
import { COMMAND_ID as LOOKUP_INDEX_EDITOR_COMMAND } from '../lookup_join/use_lookup_index_editor';
40+
import { reportEsqlError } from '../report_error';
4041

4142
export enum ResourceBrowserType {
4243
DATA_SOURCES = 'data_sources',
@@ -54,17 +55,21 @@ export class ESQLEditorTelemetryService {
5455
try {
5556
this._analytics.reportEvent(eventType, eventData);
5657
} catch (error) {
57-
// eslint-disable-next-line no-console
58-
console.log('Failed to report telemetry event', error);
58+
reportEsqlError(error, {
59+
errorType: 'TelemetryEvent',
60+
labels: { event_type: eventType },
61+
});
5962
}
6063
}
6164

6265
private _reportPerformanceEvent(eventData: PerformanceMetricEvent) {
6366
try {
6467
reportPerformanceMetricEvent(this._analytics, eventData);
6568
} catch (error) {
66-
// eslint-disable-next-line no-console
67-
console.log('Failed to report performance metric event', error);
69+
reportEsqlError(error, {
70+
errorType: 'TelemetryPerformance',
71+
labels: { event_name: eventData.eventName },
72+
});
6873
}
6974
}
7075

@@ -115,8 +120,7 @@ export class ESQLEditorTelemetryService {
115120
commandData = JSON.parse(decodedData) as IndexEditorCommandArgs;
116121
}
117122
} catch (error) {
118-
// eslint-disable-next-line no-console
119-
console.log('Failed to parse hover message command data', error);
123+
reportEsqlError(error, { errorType: 'HoverMessageParse' });
120124
}
121125

122126
if (commandData) {

src/platform/plugins/shared/esql/public/source_enricher_service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type { Logger } from '@kbn/logging';
1111
import type { ESQLSourceResult } from '@kbn/esql-types';
12+
import { reportEsqlError } from '@kbn/esql-editor';
1213

1314
type SourceEnricher = (sources: ESQLSourceResult[]) => Promise<ESQLSourceResult[]>;
1415

@@ -32,6 +33,7 @@ export class SourceEnricherService {
3233
enriched = await enricher(enriched);
3334
} catch (error) {
3435
this.logger.error(error);
36+
reportEsqlError(error, { errorType: 'SourceEnricher' });
3537
}
3638
}
3739
return enriched;

0 commit comments

Comments
 (0)