mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[DataUsage][Serverless] Handle usage metrics errors (#197056)](https://github.com/elastic/kibana/pull/197056) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Ash","email":"1849116+ashokaditya@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-10-24T13:48:33Z","message":"[DataUsage][Serverless] Handle usage metrics errors (#197056)","sha":"1267bd7129912690d469ae6d359c8242a679dfb8","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:version","v8.17.0"],"title":"[DataUsage][Serverless] Handle usage metrics errors","number":197056,"url":"https://github.com/elastic/kibana/pull/197056","mergeCommit":{"message":"[DataUsage][Serverless] Handle usage metrics errors (#197056)","sha":"1267bd7129912690d469ae6d359c8242a679dfb8"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197056","number":197056,"mergeCommit":{"message":"[DataUsage][Serverless] Handle usage metrics errors (#197056)","sha":"1267bd7129912690d469ae6d359c8242a679dfb8"}},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Ash <1849116+ashokaditya@users.noreply.github.com>
This commit is contained in:
parent
75933e164b
commit
8e5c5fa72b
7 changed files with 94 additions and 62 deletions
|
@ -8,6 +8,7 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Charts } from './charts';
|
||||
import { useBreadcrumbs } from '../../utils/use_breadcrumbs';
|
||||
import { useKibanaContextForPlugin } from '../../utils/use_kibana';
|
||||
|
@ -29,7 +30,7 @@ const FlexItemWithCss = ({ children }: { children: React.ReactNode }) => (
|
|||
|
||||
export const DataUsageMetrics = () => {
|
||||
const {
|
||||
services: { chrome, appParams },
|
||||
services: { chrome, appParams, notifications },
|
||||
} = useKibanaContextForPlugin();
|
||||
useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome);
|
||||
|
||||
|
@ -43,10 +44,15 @@ export const DataUsageMetrics = () => {
|
|||
setUrlDateRangeFilter,
|
||||
} = useDataUsageMetricsUrlParams();
|
||||
|
||||
const { data: dataStreams, isFetching: isFetchingDataStreams } = useGetDataUsageDataStreams({
|
||||
const {
|
||||
error: errorFetchingDataStreams,
|
||||
data: dataStreams,
|
||||
isFetching: isFetchingDataStreams,
|
||||
} = useGetDataUsageDataStreams({
|
||||
selectedDataStreams: dataStreamsFromUrl,
|
||||
options: {
|
||||
enabled: true,
|
||||
retry: false,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -93,6 +99,7 @@ export const DataUsageMetrics = () => {
|
|||
const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker();
|
||||
|
||||
const {
|
||||
error: errorFetchingDataUsageMetrics,
|
||||
data,
|
||||
isFetching,
|
||||
isFetched,
|
||||
|
@ -157,6 +164,23 @@ export const DataUsageMetrics = () => {
|
|||
onChangeMetricTypesFilter,
|
||||
]);
|
||||
|
||||
if (errorFetchingDataUsageMetrics) {
|
||||
notifications.toasts.addDanger({
|
||||
title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', {
|
||||
defaultMessage: 'Error getting usage metrics',
|
||||
}),
|
||||
text: errorFetchingDataUsageMetrics.message,
|
||||
});
|
||||
}
|
||||
if (errorFetchingDataStreams) {
|
||||
notifications.toasts.addDanger({
|
||||
title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', {
|
||||
defaultMessage: 'Error getting data streams',
|
||||
}),
|
||||
text: errorFetchingDataStreams.message,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="flexStart" direction="column">
|
||||
<FlexItemWithCss>
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../common';
|
||||
|
@ -33,22 +32,19 @@ export const useGetDataUsageDataStreams = ({
|
|||
options?: UseQueryOptions<GetDataUsageDataStreamsResponse, IHttpFetchError>;
|
||||
}): UseQueryResult<GetDataUsageDataStreamsResponse, IHttpFetchError> => {
|
||||
const http = useKibanaContextForPlugin().services.http;
|
||||
const {
|
||||
services: { notifications },
|
||||
} = useKibanaContextForPlugin();
|
||||
|
||||
return useQuery<GetDataUsageDataStreamsResponse, IHttpFetchError>({
|
||||
queryKey: ['get-data-usage-data-streams'],
|
||||
...options,
|
||||
keepPreviousData: true,
|
||||
queryFn: async () => {
|
||||
const dataStreamsResponse = await http.get<GetDataUsageDataStreamsResponse>(
|
||||
DATA_USAGE_DATA_STREAMS_API_ROUTE,
|
||||
{
|
||||
const dataStreamsResponse = await http
|
||||
.get<GetDataUsageDataStreamsResponse>(DATA_USAGE_DATA_STREAMS_API_ROUTE, {
|
||||
version: '1',
|
||||
// query: {},
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error.body;
|
||||
});
|
||||
|
||||
const augmentedDataStreamsBasedOnSelectedItems = dataStreamsResponse.reduce<{
|
||||
selected: GetDataUsageDataStreamsResponse;
|
||||
|
@ -87,13 +83,5 @@ export const useGetDataUsageDataStreams = ({
|
|||
: PAGING_PARAMS.default
|
||||
);
|
||||
},
|
||||
onError: (error: IHttpFetchError) => {
|
||||
notifications.toasts.addDanger({
|
||||
title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', {
|
||||
defaultMessage: 'Error getting data streams',
|
||||
}),
|
||||
text: error.message,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import { UsageMetricsRequestBody, UsageMetricsResponseSchemaBody } from '../../common/rest_types';
|
||||
|
@ -23,33 +22,26 @@ export const useGetDataUsageMetrics = (
|
|||
options: UseQueryOptions<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>> = {}
|
||||
): UseQueryResult<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>> => {
|
||||
const http = useKibanaContextForPlugin().services.http;
|
||||
const {
|
||||
services: { notifications },
|
||||
} = useKibanaContextForPlugin();
|
||||
|
||||
return useQuery<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>>({
|
||||
queryKey: ['get-data-usage-metrics', body],
|
||||
...options,
|
||||
keepPreviousData: true,
|
||||
queryFn: async ({ signal }) => {
|
||||
return http.post<UsageMetricsResponseSchemaBody>(DATA_USAGE_METRICS_API_ROUTE, {
|
||||
signal,
|
||||
version: '1',
|
||||
body: JSON.stringify({
|
||||
from: body.from,
|
||||
to: body.to,
|
||||
metricTypes: body.metricTypes,
|
||||
dataStreams: body.dataStreams,
|
||||
}),
|
||||
});
|
||||
},
|
||||
onError: (error: IHttpFetchError<ErrorType>) => {
|
||||
notifications.toasts.addDanger({
|
||||
title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', {
|
||||
defaultMessage: 'Error getting usage metrics',
|
||||
}),
|
||||
text: error.message,
|
||||
});
|
||||
return http
|
||||
.post<UsageMetricsResponseSchemaBody>(DATA_USAGE_METRICS_API_ROUTE, {
|
||||
signal,
|
||||
version: '1',
|
||||
body: JSON.stringify({
|
||||
from: body.from,
|
||||
to: body.to,
|
||||
metricTypes: body.metricTypes,
|
||||
dataStreams: body.dataStreams,
|
||||
}),
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error.body;
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server';
|
||||
import { CustomHttpRequestError } from '../utils/custom_http_request_error';
|
||||
import { BaseError } from '../common/errors';
|
||||
import { AutoOpsError } from '../services/errors';
|
||||
|
||||
export class NotFoundError extends BaseError {}
|
||||
|
||||
|
@ -31,6 +32,13 @@ export const errorHandler = <E extends Error>(
|
|||
});
|
||||
}
|
||||
|
||||
if (error instanceof AutoOpsError) {
|
||||
return res.customError({
|
||||
statusCode: 503,
|
||||
body: error,
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof NotFoundError) {
|
||||
return res.notFound({ body: error });
|
||||
}
|
||||
|
|
|
@ -18,7 +18,11 @@ import {
|
|||
} from '../../common/rest_types';
|
||||
import { AppContextService } from './app_context';
|
||||
import { AutoOpsConfig } from '../types';
|
||||
import { AutoOpsError } from './errors';
|
||||
|
||||
const AGENT_CREATION_FAILED_ERROR = 'AutoOps API could not create the autoops agent';
|
||||
const AUTO_OPS_AGENT_CREATION_PREFIX = '[AutoOps API] Creating autoops agent failed';
|
||||
const AUTO_OPS_MISSING_CONFIG_ERROR = 'Missing autoops configuration';
|
||||
export class AutoOpsAPIService {
|
||||
constructor(private appContextService: AppContextService) {}
|
||||
public async autoOpsUsageMetricsAPI(requestBody: UsageMetricsRequestBody) {
|
||||
|
@ -34,8 +38,8 @@ export class AutoOpsAPIService {
|
|||
|
||||
const autoopsConfig = this.appContextService.getConfig()?.autoops;
|
||||
if (!autoopsConfig) {
|
||||
logger.error('[AutoOps API] Missing autoops configuration', errorMetadata);
|
||||
throw new Error('missing autoops configuration');
|
||||
logger.error(`[AutoOps API] ${AUTO_OPS_MISSING_CONFIG_ERROR}`, errorMetadata);
|
||||
throw new AutoOpsError(AUTO_OPS_MISSING_CONFIG_ERROR);
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
|
@ -86,7 +90,7 @@ export class AutoOpsAPIService {
|
|||
(error: Error | AxiosError) => {
|
||||
if (!axios.isAxiosError(error)) {
|
||||
logger.error(
|
||||
`[AutoOps API] Creating autoops failed with an error ${error} ${requestConfigDebugStatus}`,
|
||||
`${AUTO_OPS_AGENT_CREATION_PREFIX} with an error ${error} ${requestConfigDebugStatus}`,
|
||||
errorMetadataWithRequestConfig
|
||||
);
|
||||
throw new Error(withRequestIdMessage(error.message));
|
||||
|
@ -97,7 +101,7 @@ export class AutoOpsAPIService {
|
|||
if (error.response) {
|
||||
// The request was made and the server responded with a status code and error data
|
||||
logger.error(
|
||||
`[AutoOps API] Creating autoops failed because the AutoOps API responding with a status code that falls out of the range of 2xx: ${JSON.stringify(
|
||||
`${AUTO_OPS_AGENT_CREATION_PREFIX} because the AutoOps API responded with a status code that falls out of the range of 2xx: ${JSON.stringify(
|
||||
error.response.status
|
||||
)}} ${JSON.stringify(error.response.data)}} ${requestConfigDebugStatus}`,
|
||||
{
|
||||
|
@ -111,30 +115,26 @@ export class AutoOpsAPIService {
|
|||
},
|
||||
}
|
||||
);
|
||||
throw new Error(
|
||||
withRequestIdMessage(`the AutoOps API could not create the autoops agent`)
|
||||
);
|
||||
throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR));
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
logger.error(
|
||||
`[AutoOps API] Creating autoops agent failed while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`,
|
||||
`${AUTO_OPS_AGENT_CREATION_PREFIX} while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`,
|
||||
errorMetadataWithRequestConfig
|
||||
);
|
||||
throw new Error(withRequestIdMessage(`no response received from the AutoOps API`));
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
logger.error(
|
||||
`[AutoOps API] Creating autoops agent failed to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`,
|
||||
`${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`,
|
||||
errorMetadataWithRequestConfig
|
||||
);
|
||||
throw new Error(
|
||||
withRequestIdMessage('the AutoOps API could not create the autoops agent')
|
||||
);
|
||||
throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
logger.debug(`[AutoOps API] Created an autoops agent ${response}`);
|
||||
logger.debug(`[AutoOps API] Successfully created an autoops agent ${response}`);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
10
x-pack/plugins/data_usage/server/services/errors.ts
Normal file
10
x-pack/plugins/data_usage/server/services/errors.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { BaseError } from '../common/errors';
|
||||
|
||||
export class AutoOpsError extends BaseError {}
|
|
@ -4,10 +4,12 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { ValidationError } from '@kbn/config-schema';
|
||||
import { AppContextService } from './app_context';
|
||||
import { AutoOpsAPIService } from './autoops_api';
|
||||
import type { DataUsageContext } from '../types';
|
||||
import { MetricTypes } from '../../common/rest_types';
|
||||
import { AutoOpsError } from './errors';
|
||||
|
||||
export class DataUsageService {
|
||||
private appContextService: AppContextService;
|
||||
|
@ -32,12 +34,20 @@ export class DataUsageService {
|
|||
metricTypes: MetricTypes[];
|
||||
dataStreams: string[];
|
||||
}) {
|
||||
const response = await this.autoOpsAPIService.autoOpsUsageMetricsAPI({
|
||||
from,
|
||||
to,
|
||||
metricTypes,
|
||||
dataStreams,
|
||||
});
|
||||
return response.data;
|
||||
try {
|
||||
const response = await this.autoOpsAPIService.autoOpsUsageMetricsAPI({
|
||||
from,
|
||||
to,
|
||||
metricTypes,
|
||||
dataStreams,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
if (error instanceof ValidationError) {
|
||||
throw new AutoOpsError(error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue