Skip to content

Commit adacbb6

Browse files
committed
[DataUsage][Serverless] Handle usage metrics errors (#197056)
(cherry picked from commit 1267bd7)
1 parent 59e95ef commit adacbb6

7 files changed

Lines changed: 94 additions & 62 deletions

File tree

x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import React, { useCallback, useEffect, useMemo, useState } from 'react';
99
import { css } from '@emotion/react';
1010
import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic } from '@elastic/eui';
11+
import { i18n } from '@kbn/i18n';
1112
import { Charts } from './charts';
1213
import { useBreadcrumbs } from '../../utils/use_breadcrumbs';
1314
import { useKibanaContextForPlugin } from '../../utils/use_kibana';
@@ -29,7 +30,7 @@ const FlexItemWithCss = ({ children }: { children: React.ReactNode }) => (
2930

3031
export const DataUsageMetrics = () => {
3132
const {
32-
services: { chrome, appParams },
33+
services: { chrome, appParams, notifications },
3334
} = useKibanaContextForPlugin();
3435
useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome);
3536

@@ -43,10 +44,15 @@ export const DataUsageMetrics = () => {
4344
setUrlDateRangeFilter,
4445
} = useDataUsageMetricsUrlParams();
4546

46-
const { data: dataStreams, isFetching: isFetchingDataStreams } = useGetDataUsageDataStreams({
47+
const {
48+
error: errorFetchingDataStreams,
49+
data: dataStreams,
50+
isFetching: isFetchingDataStreams,
51+
} = useGetDataUsageDataStreams({
4752
selectedDataStreams: dataStreamsFromUrl,
4853
options: {
4954
enabled: true,
55+
retry: false,
5056
},
5157
});
5258

@@ -93,6 +99,7 @@ export const DataUsageMetrics = () => {
9399
const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker();
94100

95101
const {
102+
error: errorFetchingDataUsageMetrics,
96103
data,
97104
isFetching,
98105
isFetched,
@@ -157,6 +164,23 @@ export const DataUsageMetrics = () => {
157164
onChangeMetricTypesFilter,
158165
]);
159166

167+
if (errorFetchingDataUsageMetrics) {
168+
notifications.toasts.addDanger({
169+
title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', {
170+
defaultMessage: 'Error getting usage metrics',
171+
}),
172+
text: errorFetchingDataUsageMetrics.message,
173+
});
174+
}
175+
if (errorFetchingDataStreams) {
176+
notifications.toasts.addDanger({
177+
title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', {
178+
defaultMessage: 'Error getting data streams',
179+
}),
180+
text: errorFetchingDataStreams.message,
181+
});
182+
}
183+
160184
return (
161185
<EuiFlexGroup alignItems="flexStart" direction="column">
162186
<FlexItemWithCss>

x-pack/plugins/data_usage/public/hooks/use_get_data_streams.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*/
77

88
import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
9-
import { i18n } from '@kbn/i18n';
109
import { useQuery } from '@tanstack/react-query';
1110
import type { IHttpFetchError } from '@kbn/core-http-browser';
1211
import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../common';
@@ -33,22 +32,19 @@ export const useGetDataUsageDataStreams = ({
3332
options?: UseQueryOptions<GetDataUsageDataStreamsResponse, IHttpFetchError>;
3433
}): UseQueryResult<GetDataUsageDataStreamsResponse, IHttpFetchError> => {
3534
const http = useKibanaContextForPlugin().services.http;
36-
const {
37-
services: { notifications },
38-
} = useKibanaContextForPlugin();
3935

4036
return useQuery<GetDataUsageDataStreamsResponse, IHttpFetchError>({
4137
queryKey: ['get-data-usage-data-streams'],
4238
...options,
4339
keepPreviousData: true,
4440
queryFn: async () => {
45-
const dataStreamsResponse = await http.get<GetDataUsageDataStreamsResponse>(
46-
DATA_USAGE_DATA_STREAMS_API_ROUTE,
47-
{
41+
const dataStreamsResponse = await http
42+
.get<GetDataUsageDataStreamsResponse>(DATA_USAGE_DATA_STREAMS_API_ROUTE, {
4843
version: '1',
49-
// query: {},
50-
}
51-
);
44+
})
45+
.catch((error) => {
46+
throw error.body;
47+
});
5248

5349
const augmentedDataStreamsBasedOnSelectedItems = dataStreamsResponse.reduce<{
5450
selected: GetDataUsageDataStreamsResponse;
@@ -87,13 +83,5 @@ export const useGetDataUsageDataStreams = ({
8783
: PAGING_PARAMS.default
8884
);
8985
},
90-
onError: (error: IHttpFetchError) => {
91-
notifications.toasts.addDanger({
92-
title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', {
93-
defaultMessage: 'Error getting data streams',
94-
}),
95-
text: error.message,
96-
});
97-
},
9886
});
9987
};

x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*/
77

88
import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
9-
import { i18n } from '@kbn/i18n';
109
import { useQuery } from '@tanstack/react-query';
1110
import type { IHttpFetchError } from '@kbn/core-http-browser';
1211
import { UsageMetricsRequestBody, UsageMetricsResponseSchemaBody } from '../../common/rest_types';
@@ -23,33 +22,26 @@ export const useGetDataUsageMetrics = (
2322
options: UseQueryOptions<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>> = {}
2423
): UseQueryResult<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>> => {
2524
const http = useKibanaContextForPlugin().services.http;
26-
const {
27-
services: { notifications },
28-
} = useKibanaContextForPlugin();
2925

3026
return useQuery<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>>({
3127
queryKey: ['get-data-usage-metrics', body],
3228
...options,
3329
keepPreviousData: true,
3430
queryFn: async ({ signal }) => {
35-
return http.post<UsageMetricsResponseSchemaBody>(DATA_USAGE_METRICS_API_ROUTE, {
36-
signal,
37-
version: '1',
38-
body: JSON.stringify({
39-
from: body.from,
40-
to: body.to,
41-
metricTypes: body.metricTypes,
42-
dataStreams: body.dataStreams,
43-
}),
44-
});
45-
},
46-
onError: (error: IHttpFetchError<ErrorType>) => {
47-
notifications.toasts.addDanger({
48-
title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', {
49-
defaultMessage: 'Error getting usage metrics',
50-
}),
51-
text: error.message,
52-
});
31+
return http
32+
.post<UsageMetricsResponseSchemaBody>(DATA_USAGE_METRICS_API_ROUTE, {
33+
signal,
34+
version: '1',
35+
body: JSON.stringify({
36+
from: body.from,
37+
to: body.to,
38+
metricTypes: body.metricTypes,
39+
dataStreams: body.dataStreams,
40+
}),
41+
})
42+
.catch((error) => {
43+
throw error.body;
44+
});
5345
},
5446
});
5547
};

x-pack/plugins/data_usage/server/routes/error_handler.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server';
99
import { CustomHttpRequestError } from '../utils/custom_http_request_error';
1010
import { BaseError } from '../common/errors';
11+
import { AutoOpsError } from '../services/errors';
1112

1213
export class NotFoundError extends BaseError {}
1314

@@ -31,6 +32,13 @@ export const errorHandler = <E extends Error>(
3132
});
3233
}
3334

35+
if (error instanceof AutoOpsError) {
36+
return res.customError({
37+
statusCode: 503,
38+
body: error,
39+
});
40+
}
41+
3442
if (error instanceof NotFoundError) {
3543
return res.notFound({ body: error });
3644
}

x-pack/plugins/data_usage/server/services/autoops_api.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import {
1818
} from '../../common/rest_types';
1919
import { AppContextService } from './app_context';
2020
import { AutoOpsConfig } from '../types';
21+
import { AutoOpsError } from './errors';
2122

23+
const AGENT_CREATION_FAILED_ERROR = 'AutoOps API could not create the autoops agent';
24+
const AUTO_OPS_AGENT_CREATION_PREFIX = '[AutoOps API] Creating autoops agent failed';
25+
const AUTO_OPS_MISSING_CONFIG_ERROR = 'Missing autoops configuration';
2226
export class AutoOpsAPIService {
2327
constructor(private appContextService: AppContextService) {}
2428
public async autoOpsUsageMetricsAPI(requestBody: UsageMetricsRequestBody) {
@@ -34,8 +38,8 @@ export class AutoOpsAPIService {
3438

3539
const autoopsConfig = this.appContextService.getConfig()?.autoops;
3640
if (!autoopsConfig) {
37-
logger.error('[AutoOps API] Missing autoops configuration', errorMetadata);
38-
throw new Error('missing autoops configuration');
41+
logger.error(`[AutoOps API] ${AUTO_OPS_MISSING_CONFIG_ERROR}`, errorMetadata);
42+
throw new AutoOpsError(AUTO_OPS_MISSING_CONFIG_ERROR);
3943
}
4044

4145
logger.debug(
@@ -86,7 +90,7 @@ export class AutoOpsAPIService {
8690
(error: Error | AxiosError) => {
8791
if (!axios.isAxiosError(error)) {
8892
logger.error(
89-
`[AutoOps API] Creating autoops failed with an error ${error} ${requestConfigDebugStatus}`,
93+
`${AUTO_OPS_AGENT_CREATION_PREFIX} with an error ${error} ${requestConfigDebugStatus}`,
9094
errorMetadataWithRequestConfig
9195
);
9296
throw new Error(withRequestIdMessage(error.message));
@@ -97,7 +101,7 @@ export class AutoOpsAPIService {
97101
if (error.response) {
98102
// The request was made and the server responded with a status code and error data
99103
logger.error(
100-
`[AutoOps API] Creating autoops failed because the AutoOps API responding with a status code that falls out of the range of 2xx: ${JSON.stringify(
104+
`${AUTO_OPS_AGENT_CREATION_PREFIX} because the AutoOps API responded with a status code that falls out of the range of 2xx: ${JSON.stringify(
101105
error.response.status
102106
)}} ${JSON.stringify(error.response.data)}} ${requestConfigDebugStatus}`,
103107
{
@@ -111,30 +115,26 @@ export class AutoOpsAPIService {
111115
},
112116
}
113117
);
114-
throw new Error(
115-
withRequestIdMessage(`the AutoOps API could not create the autoops agent`)
116-
);
118+
throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR));
117119
} else if (error.request) {
118120
// The request was made but no response was received
119121
logger.error(
120-
`[AutoOps API] Creating autoops agent failed while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`,
122+
`${AUTO_OPS_AGENT_CREATION_PREFIX} while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`,
121123
errorMetadataWithRequestConfig
122124
);
123125
throw new Error(withRequestIdMessage(`no response received from the AutoOps API`));
124126
} else {
125127
// Something happened in setting up the request that triggered an Error
126128
logger.error(
127-
`[AutoOps API] Creating autoops agent failed to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`,
129+
`${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`,
128130
errorMetadataWithRequestConfig
129131
);
130-
throw new Error(
131-
withRequestIdMessage('the AutoOps API could not create the autoops agent')
132-
);
132+
throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR));
133133
}
134134
}
135135
);
136136

137-
logger.debug(`[AutoOps API] Created an autoops agent ${response}`);
137+
logger.debug(`[AutoOps API] Successfully created an autoops agent ${response}`);
138138
return response;
139139
}
140140

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { BaseError } from '../common/errors';
9+
10+
export class AutoOpsError extends BaseError {}

x-pack/plugins/data_usage/server/services/index.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
* 2.0; you may not use this file except in compliance with the Elastic License
55
* 2.0.
66
*/
7+
import { ValidationError } from '@kbn/config-schema';
78
import { AppContextService } from './app_context';
89
import { AutoOpsAPIService } from './autoops_api';
910
import type { DataUsageContext } from '../types';
1011
import { MetricTypes } from '../../common/rest_types';
12+
import { AutoOpsError } from './errors';
1113

1214
export class DataUsageService {
1315
private appContextService: AppContextService;
@@ -32,12 +34,20 @@ export class DataUsageService {
3234
metricTypes: MetricTypes[];
3335
dataStreams: string[];
3436
}) {
35-
const response = await this.autoOpsAPIService.autoOpsUsageMetricsAPI({
36-
from,
37-
to,
38-
metricTypes,
39-
dataStreams,
40-
});
41-
return response.data;
37+
try {
38+
const response = await this.autoOpsAPIService.autoOpsUsageMetricsAPI({
39+
from,
40+
to,
41+
metricTypes,
42+
dataStreams,
43+
});
44+
return response.data;
45+
} catch (error) {
46+
if (error instanceof ValidationError) {
47+
throw new AutoOpsError(error.message);
48+
}
49+
50+
throw error;
51+
}
4252
}
4353
}

0 commit comments

Comments
 (0)