mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
9c5e11b07b
commit
9c05ae58b3
36 changed files with 511 additions and 423 deletions
|
@ -57,7 +57,9 @@ export function AnomalyDetectionSetupLink() {
|
|||
export function MissingJobsAlert({ environment }: { environment?: string }) {
|
||||
const { data = DEFAULT_DATA, status } = useFetcher(
|
||||
(callApmApi) =>
|
||||
callApmApi({ endpoint: `GET /api/apm/settings/anomaly-detection/jobs` }),
|
||||
callApmApi({
|
||||
endpoint: `GET /api/apm/settings/anomaly-detection/jobs`,
|
||||
}),
|
||||
[],
|
||||
{ preservePreviousData: false, showToastOnError: false }
|
||||
);
|
||||
|
|
|
@ -13,7 +13,6 @@ import { asInteger } from '../../../../common/utils/formatters';
|
|||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { ChartPreview } from '../chart_preview';
|
||||
import { EnvironmentField, IsAboveField, ServiceField } from '../fields';
|
||||
import { getAbsoluteTimeRange } from '../helper';
|
||||
|
@ -46,20 +45,23 @@ export function ErrorCountAlertTrigger(props: Props) {
|
|||
|
||||
const { threshold, windowSize, windowUnit, environment } = alertParams;
|
||||
|
||||
const { data } = useFetcher(() => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
environment,
|
||||
serviceName,
|
||||
const { data } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_count',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
environment,
|
||||
serviceName,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [windowSize, windowUnit, environment, serviceName]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[windowSize, windowUnit, environment, serviceName]
|
||||
);
|
||||
|
||||
const defaults = {
|
||||
threshold: 25,
|
||||
|
|
|
@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n';
|
|||
import { map } from 'lodash';
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useFetcher } from '../../../../../observability/public';
|
||||
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
||||
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
||||
import { getDurationFormatter } from '../../../../common/utils/formatters';
|
||||
|
@ -16,7 +15,7 @@ import { TimeSeries } from '../../../../typings/timeseries';
|
|||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import {
|
||||
getMaxY,
|
||||
getResponseTimeTickFormatter,
|
||||
|
@ -88,29 +87,32 @@ export function TransactionDurationAlertTrigger(props: Props) {
|
|||
windowUnit,
|
||||
} = alertParams;
|
||||
|
||||
const { data } = useFetcher(() => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
aggregationType,
|
||||
environment,
|
||||
serviceName,
|
||||
transactionType: alertParams.transactionType,
|
||||
const { data } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_duration',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
aggregationType,
|
||||
environment,
|
||||
serviceName,
|
||||
transactionType: alertParams.transactionType,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [
|
||||
aggregationType,
|
||||
environment,
|
||||
serviceName,
|
||||
alertParams.transactionType,
|
||||
windowSize,
|
||||
windowUnit,
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
aggregationType,
|
||||
environment,
|
||||
serviceName,
|
||||
alertParams.transactionType,
|
||||
windowSize,
|
||||
windowUnit,
|
||||
]
|
||||
);
|
||||
|
||||
const maxY = getMaxY([
|
||||
{ data: data ?? [] } as TimeSeries<{ x: number; y: number | null }>,
|
||||
|
|
|
@ -12,7 +12,6 @@ import { useApmServiceContext } from '../../../context/apm_service/use_apm_servi
|
|||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { ChartPreview } from '../chart_preview';
|
||||
import {
|
||||
EnvironmentField,
|
||||
|
@ -54,27 +53,30 @@ export function TransactionErrorRateAlertTrigger(props: Props) {
|
|||
|
||||
const thresholdAsPercent = (threshold ?? 0) / 100;
|
||||
|
||||
const { data } = useFetcher(() => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
environment,
|
||||
serviceName,
|
||||
transactionType: alertParams.transactionType,
|
||||
const { data } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (windowSize && windowUnit) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/alerts/chart_preview/transaction_error_rate',
|
||||
params: {
|
||||
query: {
|
||||
...getAbsoluteTimeRange(windowSize, windowUnit),
|
||||
environment,
|
||||
serviceName,
|
||||
transactionType: alertParams.transactionType,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [
|
||||
alertParams.transactionType,
|
||||
environment,
|
||||
serviceName,
|
||||
windowSize,
|
||||
windowUnit,
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
alertParams.transactionType,
|
||||
environment,
|
||||
serviceName,
|
||||
windowSize,
|
||||
windowUnit,
|
||||
]
|
||||
);
|
||||
|
||||
if (serviceName && !transactionTypes.length) {
|
||||
return null;
|
||||
|
|
|
@ -25,10 +25,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
||||
import {
|
||||
APIReturnType,
|
||||
callApmApi,
|
||||
} from '../../../services/rest/createCallApmApi';
|
||||
import { APIReturnType } from '../../../services/rest/createCallApmApi';
|
||||
import { px } from '../../../style/variables';
|
||||
import { SignificantTermsTable } from './SignificantTermsTable';
|
||||
import { ChartContainer } from '../../shared/charts/chart_container';
|
||||
|
@ -65,32 +62,35 @@ export function ErrorCorrelations() {
|
|||
const { urlParams, uiFilters } = useUrlParams();
|
||||
const { transactionName, transactionType, start, end } = urlParams;
|
||||
|
||||
const { data, status } = useFetcher(() => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/correlations/failed_transactions',
|
||||
params: {
|
||||
query: {
|
||||
serviceName,
|
||||
transactionName,
|
||||
transactionType,
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
fieldNames: fieldNames.map((field) => field.label).join(','),
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/correlations/failed_transactions',
|
||||
params: {
|
||||
query: {
|
||||
serviceName,
|
||||
transactionName,
|
||||
transactionType,
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
fieldNames: fieldNames.map((field) => field.label).join(','),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
transactionName,
|
||||
transactionType,
|
||||
uiFilters,
|
||||
fieldNames,
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
transactionName,
|
||||
transactionType,
|
||||
uiFilters,
|
||||
fieldNames,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -26,10 +26,7 @@ import {
|
|||
import { getDurationFormatter } from '../../../../common/utils/formatters';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
||||
import {
|
||||
APIReturnType,
|
||||
callApmApi,
|
||||
} from '../../../services/rest/createCallApmApi';
|
||||
import { APIReturnType } from '../../../services/rest/createCallApmApi';
|
||||
import { SignificantTermsTable } from './SignificantTermsTable';
|
||||
import { ChartContainer } from '../../shared/charts/chart_container';
|
||||
|
||||
|
@ -65,34 +62,37 @@ export function LatencyCorrelations() {
|
|||
const { urlParams, uiFilters } = useUrlParams();
|
||||
const { transactionName, transactionType, start, end } = urlParams;
|
||||
|
||||
const { data, status } = useFetcher(() => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/correlations/slow_transactions',
|
||||
params: {
|
||||
query: {
|
||||
serviceName,
|
||||
transactionName,
|
||||
transactionType,
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
durationPercentile,
|
||||
fieldNames: fieldNames.map((field) => field.label).join(','),
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/correlations/slow_transactions',
|
||||
params: {
|
||||
query: {
|
||||
serviceName,
|
||||
transactionName,
|
||||
transactionType,
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
durationPercentile,
|
||||
fieldNames: fieldNames.map((field) => field.label).join(','),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
transactionName,
|
||||
transactionType,
|
||||
uiFilters,
|
||||
durationPercentile,
|
||||
fieldNames,
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
transactionName,
|
||||
transactionType,
|
||||
uiFilters,
|
||||
durationPercentile,
|
||||
fieldNames,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -23,7 +23,6 @@ import { useTrackPageview } from '../../../../../observability/public';
|
|||
import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { fontFamilyCode, fontSizes, px, units } from '../../../style/variables';
|
||||
import { ApmHeader } from '../../shared/ApmHeader';
|
||||
import { SearchBar } from '../../shared/search_bar';
|
||||
|
@ -70,24 +69,27 @@ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) {
|
|||
const { urlParams, uiFilters } = useUrlParams();
|
||||
const { start, end } = urlParams;
|
||||
|
||||
const { data: errorGroupData } = useFetcher(() => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/errors/{groupId}',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
groupId,
|
||||
const { data: errorGroupData } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/errors/{groupId}',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
groupId,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [serviceName, start, end, groupId, uiFilters]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[serviceName, start, end, groupId, uiFilters]
|
||||
);
|
||||
|
||||
const { errorDistributionData } = useErrorGroupDistributionFetcher({
|
||||
serviceName,
|
||||
|
|
|
@ -18,7 +18,6 @@ import { useTrackPageview } from '../../../../../observability/public';
|
|||
import { Projection } from '../../../../common/projections';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { LocalUIFilters } from '../../shared/LocalUIFilters';
|
||||
import { SearchBar } from '../../shared/search_bar';
|
||||
import { ErrorDistribution } from '../ErrorGroupDetails/Distribution';
|
||||
|
@ -37,27 +36,30 @@ function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) {
|
|||
groupId: undefined,
|
||||
});
|
||||
|
||||
const { data: errorGroupListData } = useFetcher(() => {
|
||||
const normalizedSortDirection = sortDirection === 'asc' ? 'asc' : 'desc';
|
||||
const { data: errorGroupListData } = useFetcher(
|
||||
(callApmApi) => {
|
||||
const normalizedSortDirection = sortDirection === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/errors',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/errors',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
sortField,
|
||||
sortDirection: normalizedSortDirection,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
sortField,
|
||||
sortDirection: normalizedSortDirection,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [serviceName, start, end, sortField, sortDirection, uiFilters]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[serviceName, start, end, sortField, sortDirection, uiFilters]
|
||||
);
|
||||
|
||||
useTrackPageview({
|
||||
app: 'apm',
|
||||
|
|
|
@ -21,6 +21,7 @@ export const fetchUxOverviewDate = async ({
|
|||
}: FetchDataParams): Promise<UxFetchDataResponse> => {
|
||||
const data = await callApmApi({
|
||||
endpoint: 'GET /api/apm/rum-client/web-core-vitals',
|
||||
signal: null,
|
||||
params: {
|
||||
query: {
|
||||
start: new Date(absoluteTime.start).toISOString(),
|
||||
|
@ -41,6 +42,7 @@ export async function hasRumData({
|
|||
}: HasDataParams): Promise<UXHasDataResponse> {
|
||||
return await callApmApi({
|
||||
endpoint: 'GET /api/apm/observability_overview/has_rum_data',
|
||||
signal: null,
|
||||
params: {
|
||||
query: {
|
||||
start: new Date(absoluteTime.start).toISOString(),
|
||||
|
|
|
@ -17,7 +17,6 @@ import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
|||
import { useLicenseContext } from '../../../context/license/use_license_context';
|
||||
import { useTheme } from '../../../hooks/use_theme';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { DatePicker } from '../../shared/DatePicker';
|
||||
import { LicensePrompt } from '../../shared/LicensePrompt';
|
||||
import { Controls } from './Controls';
|
||||
|
@ -86,28 +85,31 @@ export function ServiceMap({
|
|||
const license = useLicenseContext();
|
||||
const { urlParams } = useUrlParams();
|
||||
|
||||
const { data = { elements: [] }, status, error } = useFetcher(() => {
|
||||
// When we don't have a license or a valid license, don't make the request.
|
||||
if (!license || !isActivePlatinumLicense(license)) {
|
||||
return;
|
||||
}
|
||||
const { data = { elements: [] }, status, error } = useFetcher(
|
||||
(callApmApi) => {
|
||||
// When we don't have a license or a valid license, don't make the request.
|
||||
if (!license || !isActivePlatinumLicense(license)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { start, end, environment } = urlParams;
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
isCachable: false,
|
||||
endpoint: 'GET /api/apm/service-map',
|
||||
params: {
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
serviceName,
|
||||
const { start, end, environment } = urlParams;
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
isCachable: false,
|
||||
endpoint: 'GET /api/apm/service-map',
|
||||
params: {
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
serviceName,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [license, serviceName, urlParams]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[license, serviceName, urlParams]
|
||||
);
|
||||
|
||||
const { ref, height } = useRefDimensions();
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ export async function saveConfig({
|
|||
try {
|
||||
await callApmApi({
|
||||
endpoint: 'PUT /api/apm/settings/agent-configuration',
|
||||
signal: null,
|
||||
params: {
|
||||
query: { overwrite: isEditMode },
|
||||
body: {
|
||||
|
|
|
@ -73,6 +73,7 @@ async function deleteConfig(
|
|||
try {
|
||||
await callApmApi({
|
||||
endpoint: 'DELETE /api/apm/settings/agent-configuration',
|
||||
signal: null,
|
||||
params: {
|
||||
body: {
|
||||
service: {
|
||||
|
|
|
@ -74,6 +74,7 @@ async function saveApmIndices({
|
|||
}) {
|
||||
await callApmApi({
|
||||
endpoint: 'POST /api/apm/settings/apm-indices/save',
|
||||
signal: null,
|
||||
params: {
|
||||
body: apmIndices,
|
||||
},
|
||||
|
|
|
@ -48,6 +48,7 @@ async function deleteConfig(
|
|||
try {
|
||||
await callApmApi({
|
||||
endpoint: 'DELETE /api/apm/settings/custom_links/{id}',
|
||||
signal: null,
|
||||
params: {
|
||||
path: { id: customLinkId },
|
||||
},
|
||||
|
|
|
@ -31,6 +31,7 @@ interface Props {
|
|||
const fetchTransaction = debounce(
|
||||
async (filters: Filter[], callback: (transaction: Transaction) => void) => {
|
||||
const transaction = await callApmApi({
|
||||
signal: null,
|
||||
endpoint: 'GET /api/apm/settings/custom_links/transaction',
|
||||
params: { query: convertFiltersToQuery(filters) },
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@ export async function saveCustomLink({
|
|||
if (id) {
|
||||
await callApmApi({
|
||||
endpoint: 'PUT /api/apm/settings/custom_links/{id}',
|
||||
signal: null,
|
||||
params: {
|
||||
path: { id },
|
||||
body: customLink,
|
||||
|
@ -43,6 +44,7 @@ export async function saveCustomLink({
|
|||
} else {
|
||||
await callApmApi({
|
||||
endpoint: 'POST /api/apm/settings/custom_links',
|
||||
signal: null,
|
||||
params: {
|
||||
body: customLink,
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ export async function createJobs({
|
|||
try {
|
||||
await callApmApi({
|
||||
endpoint: 'POST /api/apm/settings/anomaly-detection/jobs',
|
||||
signal: null,
|
||||
params: {
|
||||
body: { environments },
|
||||
},
|
||||
|
|
|
@ -8,7 +8,9 @@ import { useFetcher } from '../../../hooks/use_fetcher';
|
|||
export function useAnomalyDetectionJobsFetcher() {
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) =>
|
||||
callApmApi({ endpoint: `GET /api/apm/settings/anomaly-detection/jobs` }),
|
||||
callApmApi({
|
||||
endpoint: `GET /api/apm/settings/anomaly-detection/jobs`,
|
||||
}),
|
||||
[],
|
||||
{ showToastOnError: false }
|
||||
);
|
||||
|
|
|
@ -26,7 +26,6 @@ import {
|
|||
import { ServiceDependencyItem } from '../../../../../server/lib/services/get_service_dependencies';
|
||||
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { callApmApi } from '../../../../services/rest/createCallApmApi';
|
||||
import { px, unit } from '../../../../style/variables';
|
||||
import { AgentIcon } from '../../../shared/AgentIcon';
|
||||
import { SparkPlot } from '../../../shared/charts/spark_plot';
|
||||
|
@ -167,26 +166,29 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) {
|
|||
},
|
||||
];
|
||||
|
||||
const { data = [], status } = useFetcher(() => {
|
||||
if (!start || !end) {
|
||||
return;
|
||||
}
|
||||
const { data = [], status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!start || !end) {
|
||||
return;
|
||||
}
|
||||
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/dependencies',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/dependencies',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment: environment || ENVIRONMENT_ALL.value,
|
||||
numBuckets: 20,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment: environment || ENVIRONMENT_ALL.value,
|
||||
numBuckets: 20,
|
||||
},
|
||||
},
|
||||
});
|
||||
}, [start, end, serviceName, environment]);
|
||||
});
|
||||
},
|
||||
[start, end, serviceName, environment]
|
||||
);
|
||||
|
||||
// need top-level sortable fields for the managed table
|
||||
const items = data.map((item) => ({
|
||||
|
|
|
@ -16,7 +16,6 @@ import { asInteger } from '../../../../../common/utils/formatters';
|
|||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { callApmApi } from '../../../../services/rest/createCallApmApi';
|
||||
import { px, unit } from '../../../../style/variables';
|
||||
import { SparkPlot } from '../../../shared/charts/spark_plot';
|
||||
import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
|
||||
|
@ -140,50 +139,53 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
|
|||
},
|
||||
},
|
||||
status,
|
||||
} = useFetcher(() => {
|
||||
if (!start || !end || !transactionType) {
|
||||
return;
|
||||
}
|
||||
} = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!start || !end || !transactionType) {
|
||||
return;
|
||||
}
|
||||
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/error_groups',
|
||||
params: {
|
||||
path: { serviceName },
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
size: PAGE_SIZE,
|
||||
numBuckets: 20,
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sortField: tableOptions.sort.field,
|
||||
sortDirection: tableOptions.sort.direction,
|
||||
transactionType,
|
||||
},
|
||||
},
|
||||
}).then((response) => {
|
||||
return {
|
||||
items: response.error_groups,
|
||||
totalItemCount: response.total_error_groups,
|
||||
tableOptions: {
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sort: {
|
||||
field: tableOptions.sort.field,
|
||||
direction: tableOptions.sort.direction,
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/error_groups',
|
||||
params: {
|
||||
path: { serviceName },
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
size: PAGE_SIZE,
|
||||
numBuckets: 20,
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sortField: tableOptions.sort.field,
|
||||
sortDirection: tableOptions.sort.direction,
|
||||
transactionType,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}, [
|
||||
start,
|
||||
end,
|
||||
serviceName,
|
||||
uiFilters,
|
||||
tableOptions.pageIndex,
|
||||
tableOptions.sort.field,
|
||||
tableOptions.sort.direction,
|
||||
transactionType,
|
||||
]);
|
||||
}).then((response) => {
|
||||
return {
|
||||
items: response.error_groups,
|
||||
totalItemCount: response.total_error_groups,
|
||||
tableOptions: {
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sort: {
|
||||
field: tableOptions.sort.field,
|
||||
direction: tableOptions.sort.direction,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
[
|
||||
start,
|
||||
end,
|
||||
serviceName,
|
||||
uiFilters,
|
||||
tableOptions.pageIndex,
|
||||
tableOptions.sort.field,
|
||||
tableOptions.sort.direction,
|
||||
transactionType,
|
||||
]
|
||||
);
|
||||
|
||||
const {
|
||||
items,
|
||||
|
|
|
@ -9,7 +9,6 @@ import React from 'react';
|
|||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { InstancesLatencyDistributionChart } from '../../shared/charts/instances_latency_distribution_chart';
|
||||
import { ServiceOverviewInstancesTable } from './service_overview_instances_table';
|
||||
|
||||
|
@ -29,28 +28,31 @@ export function ServiceOverviewInstancesChartAndTable({
|
|||
uiFilters,
|
||||
} = useUrlParams();
|
||||
|
||||
const { data = [], status } = useFetcher(() => {
|
||||
if (!start || !end || !transactionType) {
|
||||
return;
|
||||
}
|
||||
const { data = [], status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!start || !end || !transactionType) {
|
||||
return;
|
||||
}
|
||||
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/service_overview_instances',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/service_overview_instances',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
numBuckets: 20,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
numBuckets: 20,
|
||||
},
|
||||
},
|
||||
});
|
||||
}, [start, end, serviceName, transactionType, uiFilters]);
|
||||
});
|
||||
},
|
||||
[start, end, serviceName, transactionType, uiFilters]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -13,7 +13,6 @@ import { useFetcher } from '../../../hooks/use_fetcher';
|
|||
import { useTheme } from '../../../hooks/use_theme';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { callApmApi } from '../../../services/rest/createCallApmApi';
|
||||
import { TimeseriesChart } from '../../shared/charts/timeseries_chart';
|
||||
|
||||
export function ServiceOverviewThroughputChart({
|
||||
|
@ -27,24 +26,27 @@ export function ServiceOverviewThroughputChart({
|
|||
const { transactionType } = useApmServiceContext();
|
||||
const { start, end } = urlParams;
|
||||
|
||||
const { data, status } = useFetcher(() => {
|
||||
if (serviceName && transactionType && start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/throughput',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (serviceName && transactionType && start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/throughput',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [serviceName, start, end, uiFilters, transactionType]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[serviceName, start, end, uiFilters, transactionType]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiPanel>
|
||||
|
|
|
@ -23,10 +23,7 @@ import {
|
|||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import {
|
||||
APIReturnType,
|
||||
callApmApi,
|
||||
} from '../../../../services/rest/createCallApmApi';
|
||||
import { APIReturnType } from '../../../../services/rest/createCallApmApi';
|
||||
import { px, unit } from '../../../../style/variables';
|
||||
import { SparkPlot } from '../../../shared/charts/spark_plot';
|
||||
import { ImpactBar } from '../../../shared/ImpactBar';
|
||||
|
@ -110,53 +107,56 @@ export function ServiceOverviewTransactionsTable(props: Props) {
|
|||
},
|
||||
},
|
||||
status,
|
||||
} = useFetcher(() => {
|
||||
if (!start || !end || !latencyAggregationType || !transactionType) {
|
||||
return;
|
||||
}
|
||||
} = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!start || !end || !latencyAggregationType || !transactionType) {
|
||||
return;
|
||||
}
|
||||
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/transactions/groups/overview',
|
||||
params: {
|
||||
path: { serviceName },
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
size: PAGE_SIZE,
|
||||
numBuckets: 20,
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sortField: tableOptions.sort.field,
|
||||
sortDirection: tableOptions.sort.direction,
|
||||
transactionType,
|
||||
latencyAggregationType: latencyAggregationType as LatencyAggregationType,
|
||||
},
|
||||
},
|
||||
}).then((response) => {
|
||||
return {
|
||||
items: response.transactionGroups,
|
||||
totalItemCount: response.totalTransactionGroups,
|
||||
tableOptions: {
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sort: {
|
||||
field: tableOptions.sort.field,
|
||||
direction: tableOptions.sort.direction,
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/transactions/groups/overview',
|
||||
params: {
|
||||
path: { serviceName },
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
size: PAGE_SIZE,
|
||||
numBuckets: 20,
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sortField: tableOptions.sort.field,
|
||||
sortDirection: tableOptions.sort.direction,
|
||||
transactionType,
|
||||
latencyAggregationType: latencyAggregationType as LatencyAggregationType,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}, [
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
uiFilters,
|
||||
tableOptions.pageIndex,
|
||||
tableOptions.sort.field,
|
||||
tableOptions.sort.direction,
|
||||
transactionType,
|
||||
latencyAggregationType,
|
||||
]);
|
||||
}).then((response) => {
|
||||
return {
|
||||
items: response.transactionGroups,
|
||||
totalItemCount: response.totalTransactionGroups,
|
||||
tableOptions: {
|
||||
pageIndex: tableOptions.pageIndex,
|
||||
sort: {
|
||||
field: tableOptions.sort.field,
|
||||
direction: tableOptions.sort.direction,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
[
|
||||
serviceName,
|
||||
start,
|
||||
end,
|
||||
uiFilters,
|
||||
tableOptions.pageIndex,
|
||||
tableOptions.sort.field,
|
||||
tableOptions.sort.direction,
|
||||
transactionType,
|
||||
latencyAggregationType,
|
||||
]
|
||||
);
|
||||
|
||||
const {
|
||||
items,
|
||||
|
|
|
@ -12,7 +12,6 @@ import { asPercent } from '../../../../../common/utils/formatters';
|
|||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { useTheme } from '../../../../hooks/use_theme';
|
||||
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { callApmApi } from '../../../../services/rest/createCallApmApi';
|
||||
import { TimeseriesChart } from '../timeseries_chart';
|
||||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
|
||||
|
@ -35,26 +34,29 @@ export function TransactionErrorRateChart({
|
|||
const { transactionType } = useApmServiceContext();
|
||||
const { start, end, transactionName } = urlParams;
|
||||
|
||||
const { data, status } = useFetcher(() => {
|
||||
if (transactionType && serviceName && start && end) {
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/transactions/charts/error_rate',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (transactionType && serviceName && start && end) {
|
||||
return callApmApi({
|
||||
endpoint:
|
||||
'GET /api/apm/services/{serviceName}/transactions/charts/error_rate',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
transactionName,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
transactionType,
|
||||
transactionName,
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [serviceName, start, end, uiFilters, transactionType, transactionName]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[serviceName, start, end, uiFilters, transactionType, transactionName]
|
||||
);
|
||||
|
||||
const errorRates = data?.transactionErrorRate || [];
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import { useParams } from 'react-router-dom';
|
|||
import { Annotation } from '../../../common/annotations';
|
||||
import { useFetcher } from '../../hooks/use_fetcher';
|
||||
import { useUrlParams } from '../url_params_context/use_url_params';
|
||||
import { callApmApi } from '../../services/rest/createCallApmApi';
|
||||
|
||||
export const AnnotationsContext = createContext({ annotations: [] } as {
|
||||
annotations: Annotation[];
|
||||
|
@ -27,23 +26,26 @@ export function AnnotationsContextProvider({
|
|||
const { start, end } = urlParams;
|
||||
const { environment } = uiFilters;
|
||||
|
||||
const { data = INITIAL_STATE } = useFetcher(() => {
|
||||
if (start && end && serviceName) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/annotation/search',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
const { data = INITIAL_STATE } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end && serviceName) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/services/{serviceName}/annotation/search',
|
||||
params: {
|
||||
path: {
|
||||
serviceName,
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [start, end, environment, serviceName]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[start, end, environment, serviceName]
|
||||
);
|
||||
|
||||
return <AnnotationsContext.Provider value={data} children={children} />;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import {
|
|||
} from '../../server/lib/ui_filters/local_ui_filters/config';
|
||||
import { fromQuery, toQuery } from '../components/shared/Links/url_helpers';
|
||||
import { removeUndefinedProps } from '../context/url_params_context/helpers';
|
||||
import { useCallApi } from './useCallApi';
|
||||
import { useFetcher } from './use_fetcher';
|
||||
import { useUrlParams } from '../context/url_params_context/use_url_params';
|
||||
import { LocalUIFilterName } from '../../common/ui_filter';
|
||||
|
@ -43,7 +42,6 @@ export function useLocalUIFilters({
|
|||
}) {
|
||||
const history = useHistory();
|
||||
const { uiFilters, urlParams } = useUrlParams();
|
||||
const callApi = useCallApi();
|
||||
|
||||
const values = pickKeys(uiFilters, ...filterNames);
|
||||
|
||||
|
@ -69,30 +67,34 @@ export function useLocalUIFilters({
|
|||
});
|
||||
};
|
||||
|
||||
const { data = getInitialData(filterNames), status } = useFetcher(() => {
|
||||
if (shouldFetch) {
|
||||
return callApi<LocalUIFiltersAPIResponse>({
|
||||
method: 'GET',
|
||||
pathname: `/api/apm/ui_filters/local_filters/${projection}`,
|
||||
query: {
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
start: urlParams.start,
|
||||
end: urlParams.end,
|
||||
filterNames: JSON.stringify(filterNames),
|
||||
...params,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [
|
||||
callApi,
|
||||
projection,
|
||||
uiFilters,
|
||||
urlParams.start,
|
||||
urlParams.end,
|
||||
filterNames,
|
||||
params,
|
||||
shouldFetch,
|
||||
]);
|
||||
const { data = getInitialData(filterNames), status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (shouldFetch && urlParams.start && urlParams.end) {
|
||||
return callApmApi({
|
||||
endpoint: `GET /api/apm/ui_filters/local_filters/${projection}` as const,
|
||||
params: {
|
||||
query: {
|
||||
uiFilters: JSON.stringify(uiFilters),
|
||||
start: urlParams.start,
|
||||
end: urlParams.end,
|
||||
// type expects string constants, but we have to send it as json
|
||||
filterNames: JSON.stringify(filterNames) as any,
|
||||
...params,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
projection,
|
||||
uiFilters,
|
||||
urlParams.start,
|
||||
urlParams.end,
|
||||
filterNames,
|
||||
params,
|
||||
shouldFetch,
|
||||
]
|
||||
);
|
||||
|
||||
const filters = data.map((filter) => ({
|
||||
...filter,
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
ENVIRONMENT_ALL,
|
||||
ENVIRONMENT_NOT_DEFINED,
|
||||
} from '../../common/environment_filter_values';
|
||||
import { callApmApi } from '../services/rest/createCallApmApi';
|
||||
|
||||
function getEnvironmentOptions(environments: string[]) {
|
||||
const environmentOptions = environments
|
||||
|
@ -32,20 +31,23 @@ export function useEnvironmentsFetcher({
|
|||
start?: string;
|
||||
end?: string;
|
||||
}) {
|
||||
const { data: environments = [], status = 'loading' } = useFetcher(() => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/ui_filters/environments',
|
||||
params: {
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
serviceName,
|
||||
const { data: environments = [], status = 'loading' } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (start && end) {
|
||||
return callApmApi({
|
||||
endpoint: 'GET /api/apm/ui_filters/environments',
|
||||
params: {
|
||||
query: {
|
||||
start,
|
||||
end,
|
||||
serviceName,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [start, end, serviceName]);
|
||||
});
|
||||
}
|
||||
},
|
||||
[start, end, serviceName]
|
||||
);
|
||||
|
||||
const environmentOptions = useMemo(
|
||||
() => getEnvironmentOptions(environments),
|
||||
|
|
|
@ -8,7 +8,10 @@ import { i18n } from '@kbn/i18n';
|
|||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { IHttpFetchError } from 'src/core/public';
|
||||
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
|
||||
import { APMClient, callApmApi } from '../services/rest/createCallApmApi';
|
||||
import {
|
||||
callApmApi,
|
||||
AutoAbortedAPMClient,
|
||||
} from '../services/rest/createCallApmApi';
|
||||
import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context';
|
||||
|
||||
export enum FETCH_STATUS {
|
||||
|
@ -39,6 +42,14 @@ function getDetailsFromErrorResponse(error: IHttpFetchError) {
|
|||
);
|
||||
}
|
||||
|
||||
const createAutoAbortedAPMClient = (
|
||||
signal: AbortSignal
|
||||
): AutoAbortedAPMClient => {
|
||||
return ((options: Parameters<AutoAbortedAPMClient>[0]) => {
|
||||
return callApmApi({ ...options, signal });
|
||||
}) as AutoAbortedAPMClient;
|
||||
};
|
||||
|
||||
// fetcher functions can return undefined OR a promise. Previously we had a more simple type
|
||||
// but it led to issues when using object destructuring with default values
|
||||
type InferResponseType<TReturn> = Exclude<TReturn, undefined> extends Promise<
|
||||
|
@ -48,7 +59,7 @@ type InferResponseType<TReturn> = Exclude<TReturn, undefined> extends Promise<
|
|||
: unknown;
|
||||
|
||||
export function useFetcher<TReturn>(
|
||||
fn: (callApmApi: APMClient) => TReturn,
|
||||
fn: (callApmApi: AutoAbortedAPMClient) => TReturn,
|
||||
fnDeps: any[],
|
||||
options: {
|
||||
preservePreviousData?: boolean;
|
||||
|
@ -66,10 +77,16 @@ export function useFetcher<TReturn>(
|
|||
const [counter, setCounter] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
let controller: AbortController = new AbortController();
|
||||
|
||||
async function doFetch() {
|
||||
const promise = fn(callApmApi);
|
||||
controller.abort();
|
||||
|
||||
controller = new AbortController();
|
||||
|
||||
const signal = controller.signal;
|
||||
|
||||
const promise = fn(createAutoAbortedAPMClient(signal));
|
||||
// if `fn` doesn't return a promise it is a signal that data fetching was not initiated.
|
||||
// This can happen if the data fetching is conditional (based on certain inputs).
|
||||
// In these cases it is not desirable to invoke the global loading spinner, or change the status to success
|
||||
|
@ -85,7 +102,11 @@ export function useFetcher<TReturn>(
|
|||
|
||||
try {
|
||||
const data = await promise;
|
||||
if (!didCancel) {
|
||||
// when http fetches are aborted, the promise will be rejected
|
||||
// and this code is never reached. For async operations that are
|
||||
// not cancellable, we need to check whether the signal was
|
||||
// aborted before updating the result.
|
||||
if (!signal.aborted) {
|
||||
setResult({
|
||||
data,
|
||||
status: FETCH_STATUS.SUCCESS,
|
||||
|
@ -95,7 +116,7 @@ export function useFetcher<TReturn>(
|
|||
} catch (e) {
|
||||
const err = e as Error | IHttpFetchError;
|
||||
|
||||
if (!didCancel) {
|
||||
if (!signal.aborted) {
|
||||
const errorDetails =
|
||||
'response' in err ? getDetailsFromErrorResponse(err) : err.message;
|
||||
|
||||
|
@ -130,7 +151,7 @@ export function useFetcher<TReturn>(
|
|||
doFetch();
|
||||
|
||||
return () => {
|
||||
didCancel = true;
|
||||
controller.abort();
|
||||
};
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
}, [
|
||||
|
|
|
@ -20,6 +20,7 @@ export const fetchObservabilityOverviewPageData = async ({
|
|||
}: FetchDataParams): Promise<ApmFetchDataResponse> => {
|
||||
const data = await callApmApi({
|
||||
endpoint: 'GET /api/apm/observability_overview',
|
||||
signal: null,
|
||||
params: {
|
||||
query: {
|
||||
start: new Date(absoluteTime.start).toISOString(),
|
||||
|
@ -59,5 +60,6 @@ export const fetchObservabilityOverviewPageData = async ({
|
|||
export async function hasData() {
|
||||
return await callApmApi({
|
||||
endpoint: 'GET /api/apm/observability_overview/has_data',
|
||||
signal: null,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -87,5 +87,6 @@ function isCachable(fetchOptions: FetchOptions) {
|
|||
// order the options object to make sure that two objects with the same arguments, produce produce the
|
||||
// same cache key regardless of the order of properties
|
||||
function getCacheKey(options: FetchOptions) {
|
||||
return hash(options);
|
||||
const { pathname, method, body, query, headers } = options;
|
||||
return hash({ pathname, method, body, query, headers });
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@ import { APMAPI } from '../../../server/routes/create_apm_api';
|
|||
import { Client } from '../../../server/routes/typings';
|
||||
|
||||
export type APMClient = Client<APMAPI['_S']>;
|
||||
export type AutoAbortedAPMClient = Client<APMAPI['_S'], { abortable: false }>;
|
||||
|
||||
export type APMClientOptions = Omit<
|
||||
FetchOptions,
|
||||
'query' | 'body' | 'pathname'
|
||||
'query' | 'body' | 'pathname' | 'signal'
|
||||
> & {
|
||||
endpoint: string;
|
||||
signal: AbortSignal | null;
|
||||
params?: {
|
||||
body?: any;
|
||||
query?: any;
|
||||
|
|
|
@ -9,11 +9,13 @@ import { callApmApi } from './createCallApmApi';
|
|||
export const createStaticIndexPattern = async () => {
|
||||
return await callApmApi({
|
||||
endpoint: 'POST /api/apm/index_pattern/static',
|
||||
signal: null,
|
||||
});
|
||||
};
|
||||
|
||||
export const getApmIndexPatternTitle = async () => {
|
||||
return await callApmApi({
|
||||
endpoint: 'GET /api/apm/index_pattern/title',
|
||||
signal: null,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -65,10 +65,12 @@ describe('createApmEventClient', () => {
|
|||
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
incomingRequest.on('abort', () => {
|
||||
setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 0);
|
||||
});
|
||||
incomingRequest.abort();
|
||||
setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 0);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ function getMockRequest() {
|
|||
url: '',
|
||||
events: {
|
||||
aborted$: {
|
||||
subscribe: jest.fn(),
|
||||
subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }),
|
||||
},
|
||||
},
|
||||
} as unknown) as KibanaRequest;
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
import { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { isLeft } from 'fp-ts/lib/Either';
|
||||
import { KibanaResponseFactory, RouteRegistrar } from 'src/core/server';
|
||||
import { RequestAbortedError } from '@elastic/elasticsearch/lib/errors';
|
||||
import { merge } from '../../../common/runtime_types/merge';
|
||||
import { strictKeysRt } from '../../../common/runtime_types/strict_keys_rt';
|
||||
import { APMConfig } from '../..';
|
||||
|
@ -132,6 +133,15 @@ export function createApi() {
|
|||
if (Boom.isBoom(error)) {
|
||||
return convertBoomToKibanaResponse(error, response);
|
||||
}
|
||||
|
||||
if (error instanceof RequestAbortedError) {
|
||||
return response.custom({
|
||||
statusCode: 499,
|
||||
body: {
|
||||
message: 'Client closed request',
|
||||
},
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,15 +131,20 @@ type MaybeOptional<T extends { params: Record<string, any> }> = RequiredKeys<
|
|||
? { params?: T['params'] }
|
||||
: { params: T['params'] };
|
||||
|
||||
export type Client<TRouteState> = <
|
||||
TEndpoint extends keyof TRouteState & string
|
||||
>(
|
||||
options: Omit<FetchOptions, 'query' | 'body' | 'pathname' | 'method'> & {
|
||||
export type Client<
|
||||
TRouteState,
|
||||
TOptions extends { abortable: boolean } = { abortable: true }
|
||||
> = <TEndpoint extends keyof TRouteState & string>(
|
||||
options: Omit<
|
||||
FetchOptions,
|
||||
'query' | 'body' | 'pathname' | 'method' | 'signal'
|
||||
> & {
|
||||
forceCache?: boolean;
|
||||
endpoint: TEndpoint;
|
||||
} & (TRouteState[TEndpoint] extends { params: t.Any }
|
||||
? MaybeOptional<{ params: t.TypeOf<TRouteState[TEndpoint]['params']> }>
|
||||
: {})
|
||||
: {}) &
|
||||
(TOptions extends { abortable: true } ? { signal: AbortSignal | null } : {})
|
||||
) => Promise<
|
||||
TRouteState[TEndpoint] extends { ret: any }
|
||||
? TRouteState[TEndpoint]['ret']
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue