mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[APM] Add ML expected model bounds as an option to Comparison controls (#132456)
* [ML] Add bounds options * [ML] Renable anomalyChartTimeseries boundaries * [ML] Make it into string * [ML] Make it into string * Match colors * [ML] Add comparisonEnabledRt * [ML] Fix types, tests * [ML] Revert json bucket span change * [ML] Add bounds options * [ML] Renable anomalyChartTimeseries boundaries * [ML] Make it into string * [ML] Make it into string * Match colors * [ML] Add comparisonEnabledRt * [ML] Fix types, tests * [ML] Revert json bucket span change * Refactor to use offset with TimeRangeComparisonEnum.ExpectedBounds * Change comparisonColor to be part of anomalySeries * Fix i18n * Add Comparison text to replace 'Previous period' * Fix expected bounds legend default to first * Hide values that are N/A in the tooltips * Fix i18n, color, and null values in tooltips * Refactor to use preferredEnvironment * Don't disable expected bounds by default * Match color of expected bounds with time comparison color * Fix tests * Use bucket_span as minBucketSize for anomaly results * Fix previousPeriodColor undefined for latency chart * Remove 'Comparison:' in legend * Change anomalyTimeseriesColor to use currentPeriod to match stuff * Fix type error * Fix lower model bounds * Add comments * Remove fit * Remove comparisonEnabledRt * Change text Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
561c774e3b
commit
c1d0ec5a0e
57 changed files with 524 additions and 226 deletions
|
@ -14,4 +14,5 @@ export interface ApmMlJob {
|
|||
jobState?: JOB_STATE;
|
||||
datafeedId?: string;
|
||||
datafeedState?: DATAFEED_STATE;
|
||||
bucketSpan?: string;
|
||||
}
|
||||
|
|
|
@ -62,17 +62,14 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
];
|
||||
|
||||
describe('with one environment', () => {
|
||||
const environments = [PROD];
|
||||
|
||||
describe('and all being selected', () => {
|
||||
const environment = ENVIRONMENT_ALL.value;
|
||||
const preferredEnvironment = PROD;
|
||||
it('returns the series for prod', () => {
|
||||
expect(
|
||||
getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txLatency,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: false,
|
||||
})?.environment
|
||||
).toBe(PROD);
|
||||
|
@ -81,18 +78,15 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
});
|
||||
|
||||
describe('with multiple environments', () => {
|
||||
const environments = [PROD, DEV];
|
||||
|
||||
describe('and all being selected', () => {
|
||||
const environment = ENVIRONMENT_ALL.value;
|
||||
const preferredEnvironment = ENVIRONMENT_ALL.value;
|
||||
|
||||
it('returns no series', () => {
|
||||
expect(
|
||||
getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txLatency,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: false,
|
||||
})
|
||||
).toBeUndefined();
|
||||
|
@ -101,8 +95,7 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txLatency,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: true,
|
||||
})
|
||||
).toBeUndefined();
|
||||
|
@ -110,14 +103,13 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
});
|
||||
|
||||
describe('and production being selected', () => {
|
||||
const environment = PROD;
|
||||
const preferredEnvironment = PROD;
|
||||
|
||||
it('returns the series for production', () => {
|
||||
const series = getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txFailureRate,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: false,
|
||||
});
|
||||
|
||||
|
@ -143,15 +135,13 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
}),
|
||||
];
|
||||
|
||||
const environments = [PROD];
|
||||
const environment = ENVIRONMENT_ALL.value;
|
||||
const preferredEnvironment = PROD;
|
||||
|
||||
it('selects the most recent version when transaction metrics are being used', () => {
|
||||
const series = getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txLatency,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: false,
|
||||
});
|
||||
|
||||
|
@ -162,8 +152,7 @@ describe('getPreferredServiceAnomalyTimeseries', () => {
|
|||
const series = getPreferredServiceAnomalyTimeseries({
|
||||
allAnomalyTimeseries,
|
||||
detectorType: ApmMlDetectorType.txLatency,
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions: true,
|
||||
});
|
||||
|
||||
|
|
|
@ -5,20 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ENVIRONMENT_ALL } from '../environment_filter_values';
|
||||
import { Environment } from '../environment_rt';
|
||||
import { ApmMlDetectorType } from './apm_ml_detectors';
|
||||
import { ServiceAnomalyTimeseries } from './service_anomaly_timeseries';
|
||||
|
||||
export function getPreferredServiceAnomalyTimeseries({
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
detectorType,
|
||||
allAnomalyTimeseries,
|
||||
fallbackToTransactions,
|
||||
}: {
|
||||
environment: Environment;
|
||||
environments: Environment[];
|
||||
preferredEnvironment: Environment;
|
||||
detectorType: ApmMlDetectorType;
|
||||
allAnomalyTimeseries: ServiceAnomalyTimeseries[];
|
||||
fallbackToTransactions: boolean;
|
||||
|
@ -27,11 +24,6 @@ export function getPreferredServiceAnomalyTimeseries({
|
|||
(serie) => serie.type === detectorType
|
||||
);
|
||||
|
||||
const preferredEnvironment =
|
||||
environment === ENVIRONMENT_ALL.value && environments.length === 1
|
||||
? environments[0]
|
||||
: environment;
|
||||
|
||||
return seriesForType.find(
|
||||
(serie) =>
|
||||
serie.environment === preferredEnvironment &&
|
||||
|
|
|
@ -7,4 +7,6 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const offsetRt = t.partial({ offset: t.string });
|
||||
export const offsetRt = t.partial({
|
||||
offset: t.string,
|
||||
});
|
|
@ -203,7 +203,7 @@ describe.skip('Service overview: Time Comparison', () => {
|
|||
cy.get('[data-test-subj="throughput"]')
|
||||
.get('#echHighlighterClipPath__throughput')
|
||||
.realHover({ position: 'center' });
|
||||
cy.contains('Previous period');
|
||||
cy.contains('Week before');
|
||||
cy.contains('0 tpm');
|
||||
|
||||
cy.contains('Throughput');
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../common/connections';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
|
@ -43,7 +44,10 @@ export function BackendDetailDependenciesTable() {
|
|||
end,
|
||||
environment,
|
||||
numBuckets: 20,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
kuery,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { usePreviousPeriodLabel } from '../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { asPercent } from '../../../../common/utils/formatters';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
|
@ -55,7 +57,10 @@ export function BackendFailedTransactionRateChart({
|
|||
backendName,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
kuery,
|
||||
environment,
|
||||
},
|
||||
|
@ -68,6 +73,8 @@ export function BackendFailedTransactionRateChart({
|
|||
const { currentPeriodColor, previousPeriodColor } = getTimeSeriesColor(
|
||||
ChartType.FAILED_TRANSACTION_RATE
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
const timeseries = useMemo(() => {
|
||||
const specs: Array<TimeSeries<Coordinate>> = [];
|
||||
|
||||
|
@ -87,15 +94,12 @@ export function BackendFailedTransactionRateChart({
|
|||
data: data.comparisonTimeseries,
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.backendErrorRateChart.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
});
|
||||
}
|
||||
|
||||
return specs;
|
||||
}, [data, currentPeriodColor, previousPeriodColor]);
|
||||
}, [data, currentPeriodColor, previousPeriodColor, previousPeriodLabel]);
|
||||
|
||||
return (
|
||||
<TimeseriesChart
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { usePreviousPeriodLabel } from '../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { getDurationFormatter } from '../../../../common/utils/formatters';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
|
@ -51,7 +53,10 @@ export function BackendLatencyChart({ height }: { height: number }) {
|
|||
backendName,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
kuery,
|
||||
environment,
|
||||
},
|
||||
|
@ -65,6 +70,8 @@ export function BackendLatencyChart({ height }: { height: number }) {
|
|||
ChartType.LATENCY_AVG
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
|
||||
const timeseries = useMemo(() => {
|
||||
const specs: Array<TimeSeries<Coordinate>> = [];
|
||||
|
||||
|
@ -84,15 +91,12 @@ export function BackendLatencyChart({ height }: { height: number }) {
|
|||
data: data.comparisonTimeseries,
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.backendLatencyChart.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
});
|
||||
}
|
||||
|
||||
return specs;
|
||||
}, [data, currentPeriodColor, previousPeriodColor]);
|
||||
}, [data, currentPeriodColor, previousPeriodColor, previousPeriodLabel]);
|
||||
|
||||
const maxY = getMaxY(timeseries);
|
||||
const latencyFormatter = getDurationFormatter(maxY);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { usePreviousPeriodLabel } from '../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { asTransactionRate } from '../../../../common/utils/formatters';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
|
@ -47,7 +49,10 @@ export function BackendThroughputChart({ height }: { height: number }) {
|
|||
backendName,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
kuery,
|
||||
environment,
|
||||
},
|
||||
|
@ -61,6 +66,8 @@ export function BackendThroughputChart({ height }: { height: number }) {
|
|||
ChartType.THROUGHPUT
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
|
||||
const timeseries = useMemo(() => {
|
||||
const specs: Array<TimeSeries<Coordinate>> = [];
|
||||
|
||||
|
@ -80,15 +87,12 @@ export function BackendThroughputChart({ height }: { height: number }) {
|
|||
data: data.comparisonTimeseries,
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.backendThroughputChart.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
});
|
||||
}
|
||||
|
||||
return specs;
|
||||
}, [data, currentPeriodColor, previousPeriodColor]);
|
||||
}, [data, currentPeriodColor, previousPeriodColor, previousPeriodLabel]);
|
||||
|
||||
return (
|
||||
<TimeseriesChart
|
||||
|
|
|
@ -9,6 +9,7 @@ import { METRIC_TYPE } from '@kbn/analytics';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { useUiTracker } from '@kbn/observability-plugin/public';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../../common/connections';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
|
@ -45,7 +46,10 @@ export function BackendInventoryDependenciesTable() {
|
|||
end,
|
||||
environment,
|
||||
numBuckets: 20,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
kuery,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
import { EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { usePreviousPeriodLabel } from '../../../../hooks/use_previous_period_text';
|
||||
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
|
||||
|
@ -41,6 +42,7 @@ export function ErrorDistribution({ distribution, title, fetchStatus }: Props) {
|
|||
const { urlParams } = useLegacyUrlParams();
|
||||
const { comparisonEnabled } = urlParams;
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
const timeseries = [
|
||||
{
|
||||
data: distribution.currentPeriod,
|
||||
|
@ -54,10 +56,7 @@ export function ErrorDistribution({ distribution, title, fetchStatus }: Props) {
|
|||
{
|
||||
data: distribution.previousPeriod,
|
||||
color: theme.eui.euiColorMediumShade,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.errorGroup.chart.ocurrences.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useMemo } from 'react';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
import { asInteger } from '../../../../../common/utils/formatters';
|
||||
import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n';
|
||||
|
@ -72,7 +73,7 @@ function ErrorGroupList({
|
|||
comparisonEnabled,
|
||||
}: Props) {
|
||||
const { query } = useApmParams('/services/{serviceName}/errors');
|
||||
|
||||
const { offset } = query;
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
|
@ -224,7 +225,9 @@ function ErrorGroupList({
|
|||
}
|
||||
)}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimeseries : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimeseries
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
@ -238,6 +241,7 @@ function ErrorGroupList({
|
|||
detailedStatistics,
|
||||
comparisonEnabled,
|
||||
detailedStatisticsLoading,
|
||||
offset,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import uuid from 'uuid';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
|
@ -126,7 +127,10 @@ export function ErrorGroupOverview() {
|
|||
groupIds: JSON.stringify(
|
||||
errorGroupMainStatistics.map(({ groupId }) => groupId).sort()
|
||||
),
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import React from 'react';
|
|||
import uuid from 'uuid';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { apmServiceInventoryOptimizedSorting } from '@kbn/observability-plugin/common';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { useAnomalyDetectionJobsContext } from '../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context';
|
||||
import { useLocalStorage } from '../../../hooks/use_local_storage';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
|
@ -110,7 +111,10 @@ function useServicesFetcher() {
|
|||
// Service name is sorted to guarantee the same order every time this API is called so the result can be cached.
|
||||
.sort()
|
||||
),
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import { METRIC_TYPE } from '@kbn/analytics';
|
|||
import React from 'react';
|
||||
import { useUiTracker } from '@kbn/observability-plugin/public';
|
||||
import { NodeDataDefinition } from 'cytoscape';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { ContentsProps } from '.';
|
||||
import { useAnyOfApmParams } from '../../../../hooks/use_apm_params';
|
||||
import { useApmRouter } from '../../../../hooks/use_apm_router';
|
||||
|
@ -56,7 +57,10 @@ export function BackendContents({
|
|||
environment,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { NodeDataDefinition } from 'cytoscape';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
import type { ContentsProps } from '.';
|
||||
import { useApmRouter } from '../../../../hooks/use_apm_router';
|
||||
|
@ -71,7 +72,10 @@ export function ServiceContents({
|
|||
environment,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { METRIC_TYPE } from '@kbn/analytics';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { useUiTracker } from '@kbn/observability-plugin/public';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../../common/connections';
|
||||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
|
@ -67,7 +68,10 @@ export function ServiceOverviewDependenciesTable({
|
|||
end,
|
||||
environment,
|
||||
numBuckets: 20,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { TypeOf } from '@kbn/typed-react-router-config';
|
||||
import React from 'react';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { asInteger } from '../../../../../common/utils/formatters';
|
||||
import { APIReturnType } from '../../../../services/rest/create_call_apm_api';
|
||||
import { truncate } from '../../../../utils/style';
|
||||
|
@ -46,6 +47,7 @@ export function getColumns({
|
|||
comparisonEnabled?: boolean;
|
||||
query: TypeOf<ApmRoutes, '/services/{serviceName}/errors'>['query'];
|
||||
}): Array<EuiBasicTableColumn<ErrorGroupMainStatistics['errorGroups'][0]>> {
|
||||
const { offset } = query;
|
||||
return [
|
||||
{
|
||||
name: i18n.translate('xpack.apm.errorsTable.typeColumnLabel', {
|
||||
|
@ -143,7 +145,9 @@ export function getColumns({
|
|||
}
|
||||
)}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimeseries : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimeseries
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
|
|
@ -15,6 +15,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { orderBy } from 'lodash';
|
||||
import React, { useState } from 'react';
|
||||
import uuid from 'uuid';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
|
||||
import { APIReturnType } from '../../../../services/rest/create_call_apm_api';
|
||||
import { ErrorOverviewLink } from '../../../shared/links/apm/error_overview_link';
|
||||
|
@ -149,7 +150,10 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
|
|||
groupIds: JSON.stringify(
|
||||
items.map(({ groupId: groupId }) => groupId).sort()
|
||||
),
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { EuiFlexItem, EuiPanel } from '@elastic/eui';
|
|||
import { orderBy } from 'lodash';
|
||||
import React, { useState } from 'react';
|
||||
import uuid from 'uuid';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
||||
|
@ -109,7 +110,10 @@ export function ServiceOverviewInstancesChartAndTable({
|
|||
start,
|
||||
end,
|
||||
transactionType,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -197,7 +201,10 @@ export function ServiceOverviewInstancesChartAndTable({
|
|||
serviceNodeIds: JSON.stringify(
|
||||
currentPeriodOrderedItems.map((item) => item.serviceNodeName)
|
||||
),
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { ActionMenu } from '@kbn/observability-plugin/public';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { isJavaAgentName } from '../../../../../common/agent_name';
|
||||
import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
|
||||
import {
|
||||
|
@ -55,6 +56,7 @@ export function getColumns({
|
|||
itemIdToExpandedRowMap,
|
||||
toggleRowActionMenu,
|
||||
itemIdToOpenActionMenuRowMap,
|
||||
offset,
|
||||
shouldShowSparkPlots = true,
|
||||
}: {
|
||||
serviceName: string;
|
||||
|
@ -64,6 +66,7 @@ export function getColumns({
|
|||
detailedStatsLoading: boolean;
|
||||
detailedStatsData?: ServiceInstanceDetailedStatistics;
|
||||
comparisonEnabled?: boolean;
|
||||
offset?: string;
|
||||
toggleRowDetails: (selectedServiceNodeName: string) => void;
|
||||
itemIdToExpandedRowMap: Record<string, ReactNode>;
|
||||
toggleRowActionMenu: (selectedServiceNodeName: string) => void;
|
||||
|
@ -130,7 +133,9 @@ export function getColumns({
|
|||
isLoading={detailedStatsLoading}
|
||||
series={currentPeriodTimestamp}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimestamp : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimestamp
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
@ -164,7 +169,9 @@ export function getColumns({
|
|||
isLoading={detailedStatsLoading}
|
||||
series={currentPeriodTimestamp}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimestamp : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimestamp
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
@ -198,7 +205,9 @@ export function getColumns({
|
|||
isLoading={detailedStatsLoading}
|
||||
series={currentPeriodTimestamp}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimestamp : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimestamp
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
@ -232,7 +241,9 @@ export function getColumns({
|
|||
isLoading={detailedStatsLoading}
|
||||
series={currentPeriodTimestamp}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimestamp : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimestamp
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
@ -266,7 +277,9 @@ export function getColumns({
|
|||
isLoading={detailedStatsLoading}
|
||||
series={currentPeriodTimestamp}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousPeriodTimestamp : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousPeriodTimestamp
|
||||
: undefined
|
||||
}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
/>
|
||||
|
|
|
@ -73,7 +73,7 @@ export function ServiceOverviewInstancesTable({
|
|||
const { agentName } = useApmServiceContext();
|
||||
|
||||
const {
|
||||
query: { kuery, latencyAggregationType, comparisonEnabled },
|
||||
query: { kuery, latencyAggregationType, comparisonEnabled, offset },
|
||||
} = useApmParams('/services/{serviceName}');
|
||||
|
||||
const [itemIdToOpenActionMenuRowMap, setItemIdToOpenActionMenuRowMap] =
|
||||
|
@ -134,6 +134,7 @@ export function ServiceOverviewInstancesTable({
|
|||
toggleRowActionMenu,
|
||||
itemIdToOpenActionMenuRowMap,
|
||||
shouldShowSparkPlots,
|
||||
offset,
|
||||
});
|
||||
|
||||
const pagination = {
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { usePreviousPeriodLabel } from '../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { ApmMlDetectorType } from '../../../../common/anomaly_detection/apm_ml_detectors';
|
||||
import { asExactTransactionRate } from '../../../../common/utils/formatters';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
|
@ -75,7 +77,10 @@ export function ServiceOverviewThroughputChart({
|
|||
start,
|
||||
end,
|
||||
transactionType,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
transactionName,
|
||||
},
|
||||
},
|
||||
|
@ -100,6 +105,7 @@ export function ServiceOverviewThroughputChart({
|
|||
ChartType.THROUGHPUT
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
const timeseries = [
|
||||
{
|
||||
data: data.currentPeriod,
|
||||
|
@ -115,10 +121,7 @@ export function ServiceOverviewThroughputChart({
|
|||
data: data.previousPeriod,
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.serviceOverview.throughtputChart.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
@ -157,7 +160,14 @@ export function ServiceOverviewThroughputChart({
|
|||
timeseries={timeseries}
|
||||
yLabelFormat={asExactTransactionRate}
|
||||
customTheme={comparisonChartTheme}
|
||||
anomalyTimeseries={preferredAnomalyTimeseries}
|
||||
anomalyTimeseries={
|
||||
preferredAnomalyTimeseries
|
||||
? {
|
||||
...preferredAnomalyTimeseries,
|
||||
color: previousPeriodColor,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ import { settings } from './settings';
|
|||
import { ApmMainTemplate } from './templates/apm_main_template';
|
||||
import { ServiceGroupsList } from '../app/service_groups';
|
||||
import { ServiceGroupsRedirect } from './service_groups_redirect';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const ServiceGroupsTitle = i18n.translate(
|
||||
'xpack.apm.views.serviceGroups.title',
|
||||
|
|
|
@ -25,7 +25,7 @@ import { RedirectToBackendOverviewRouteView } from './redirect_to_backend_overvi
|
|||
import { ServiceGroupTemplate } from '../templates/service_group_template';
|
||||
import { ServiceGroupsRedirect } from '../service_groups_redirect';
|
||||
import { RedirectTo } from '../redirect_to';
|
||||
import { offsetRt } from '../../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../../common/comparison_rt';
|
||||
import { TransactionTab } from '../../app/transaction_details/waterfall_with_summary/transaction_tabs';
|
||||
|
||||
function page<
|
||||
|
|
|
@ -28,7 +28,7 @@ import { ServiceDependencies } from '../../app/service_dependencies';
|
|||
import { ServiceLogs } from '../../app/service_logs';
|
||||
import { InfraOverview } from '../../app/infra_overview';
|
||||
import { LatencyAggregationType } from '../../../../common/latency_aggregation_types';
|
||||
import { offsetRt } from '../../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../../common/comparison_rt';
|
||||
|
||||
function page({
|
||||
title,
|
||||
|
|
|
@ -53,7 +53,7 @@ type Tab = NonNullable<EuiPageHeaderProps['tabs']>[0] & {
|
|||
|
||||
interface Props {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
children: React.ReactChild;
|
||||
selectedTab: Tab['key'];
|
||||
searchBarOptions?: React.ComponentProps<typeof SearchBar>;
|
||||
}
|
||||
|
@ -61,9 +61,7 @@ interface Props {
|
|||
export function ApmServiceTemplate(props: Props) {
|
||||
return (
|
||||
<ApmServiceContextProvider>
|
||||
<ServiceAnomalyTimeseriesContextProvider>
|
||||
<TemplateWithContext {...props} />
|
||||
</ServiceAnomalyTimeseriesContextProvider>
|
||||
<TemplateWithContext {...props} />
|
||||
</ApmServiceContextProvider>
|
||||
);
|
||||
}
|
||||
|
@ -127,8 +125,9 @@ function TemplateWithContext({
|
|||
}}
|
||||
>
|
||||
<SearchBar {...searchBarOptions} />
|
||||
|
||||
{children}
|
||||
<ServiceAnomalyTimeseriesContextProvider>
|
||||
{children}
|
||||
</ServiceAnomalyTimeseriesContextProvider>
|
||||
</ApmMainTemplate>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import { EuiPanel, EuiTitle } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
|
||||
import { usePreviousPeriodLabel } from '../../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../time_comparison/get_comparison_options';
|
||||
import { APIReturnType } from '../../../../services/rest/create_call_apm_api';
|
||||
import { asPercent } from '../../../../../common/utils/formatters';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
|
@ -89,7 +91,10 @@ export function FailedTransactionRateChart({
|
|||
end,
|
||||
transactionType,
|
||||
transactionName,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -113,6 +118,7 @@ export function FailedTransactionRateChart({
|
|||
ChartType.FAILED_TRANSACTION_RATE
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
const timeseries = [
|
||||
{
|
||||
data: data.currentPeriod.timeseries,
|
||||
|
@ -128,10 +134,7 @@ export function FailedTransactionRateChart({
|
|||
data: data.previousPeriod.timeseries,
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.errorRate.chart.errorRate.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
@ -170,7 +173,14 @@ export function FailedTransactionRateChart({
|
|||
yLabelFormat={yLabelFormat}
|
||||
yDomain={{ min: 0, max: 1 }}
|
||||
customTheme={comparisonChartTheme}
|
||||
anomalyTimeseries={preferredAnomalyTimeseries}
|
||||
anomalyTimeseries={
|
||||
preferredAnomalyTimeseries
|
||||
? {
|
||||
...preferredAnomalyTimeseries,
|
||||
color: previousPeriodColor,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Fit } from '@elastic/charts';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { rgba } from 'polished';
|
||||
import { EuiTheme } from '@kbn/kibana-react-plugin/common';
|
||||
|
@ -18,12 +17,20 @@ import {
|
|||
import { ServiceAnomalyTimeseries } from '../../../../../common/anomaly_detection/service_anomaly_timeseries';
|
||||
import { APMChartSpec } from '../../../../../typings/timeseries';
|
||||
|
||||
export const expectedBoundsTitle = i18n.translate(
|
||||
'xpack.apm.comparison.expectedBoundsTitle',
|
||||
{
|
||||
defaultMessage: 'Expected bounds',
|
||||
}
|
||||
);
|
||||
export function getChartAnomalyTimeseries({
|
||||
anomalyTimeseries,
|
||||
theme,
|
||||
anomalyTimeseriesColor,
|
||||
}: {
|
||||
anomalyTimeseries?: ServiceAnomalyTimeseries;
|
||||
theme: EuiTheme;
|
||||
anomalyTimeseriesColor?: string;
|
||||
}):
|
||||
| {
|
||||
boundaries: APMChartSpec[];
|
||||
|
@ -36,21 +43,20 @@ export function getChartAnomalyTimeseries({
|
|||
|
||||
const boundaries = [
|
||||
{
|
||||
title: 'model plot',
|
||||
title: expectedBoundsTitle,
|
||||
type: 'area',
|
||||
fit: Fit.Lookahead,
|
||||
hideLegend: true,
|
||||
hideLegend: false,
|
||||
hideTooltipValue: true,
|
||||
areaSeriesStyle: {
|
||||
point: {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
color: rgba(theme.eui.euiColorVis1, 0.5),
|
||||
stackAccessors: ['x'],
|
||||
yAccessors: ['y0'],
|
||||
y0Accessors: ['y1'],
|
||||
color: anomalyTimeseriesColor ?? rgba(theme.eui.euiColorVis1, 0.5),
|
||||
yAccessors: ['y1'],
|
||||
y0Accessors: ['y0'],
|
||||
data: anomalyTimeseries.bounds,
|
||||
key: 'expected_bounds',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useChartTheme } from '@kbn/observability-plugin/public';
|
||||
import { usePreviousPeriodLabel } from '../../../../hooks/use_previous_period_text';
|
||||
import { SERVICE_NODE_NAME } from '../../../../../common/elasticsearch_fieldnames';
|
||||
import {
|
||||
asTransactionRate,
|
||||
|
@ -104,6 +105,7 @@ export function InstancesLatencyDistributionChart({
|
|||
min: 0,
|
||||
max: Math.max(maxThroughput, maxComparisonThroughput),
|
||||
};
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
|
||||
return (
|
||||
<EuiPanel hasBorder={true}>
|
||||
|
@ -152,10 +154,7 @@ export function InstancesLatencyDistributionChart({
|
|||
{!!comparisonItems.length && (
|
||||
<BubbleSeries
|
||||
data={comparisonItems}
|
||||
id={i18n.translate(
|
||||
'xpack.apm.instancesLatencyDistributionChartLegend.previousPeriod',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
)}
|
||||
id={previousPeriodLabel}
|
||||
xAccessor={(item) => item.throughput}
|
||||
xScaleType={ScaleType.Linear}
|
||||
yAccessors={[(item) => item.latency]}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSelect, EuiTitle } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { isTimeComparison } from '../../time_comparison/get_comparison_options';
|
||||
import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
|
||||
import { getDurationFormatter } from '../../../../../common/utils/formatters';
|
||||
import { useLicenseContext } from '../../../../context/license/use_license_context';
|
||||
|
@ -48,7 +49,7 @@ export function LatencyChart({ height, kuery }: Props) {
|
|||
const license = useLicenseContext();
|
||||
|
||||
const {
|
||||
query: { comparisonEnabled, latencyAggregationType },
|
||||
query: { comparisonEnabled, latencyAggregationType, offset },
|
||||
} = useAnyOfApmParams(
|
||||
'/services/{serviceName}/overview',
|
||||
'/services/{serviceName}/transactions',
|
||||
|
@ -68,10 +69,11 @@ export function LatencyChart({ height, kuery }: Props) {
|
|||
const preferredAnomalyTimeseries = usePreferredServiceAnomalyTimeseries(
|
||||
ApmMlDetectorType.txLatency
|
||||
);
|
||||
const anomalyTimeseriesColor = previousPeriod?.color as string;
|
||||
|
||||
const timeseries = [
|
||||
currentPeriod,
|
||||
comparisonEnabled ? previousPeriod : undefined,
|
||||
comparisonEnabled && isTimeComparison(offset) ? previousPeriod : undefined,
|
||||
].filter(filterNil);
|
||||
|
||||
const latencyMaxY = getMaxY(timeseries);
|
||||
|
@ -131,7 +133,14 @@ export function LatencyChart({ height, kuery }: Props) {
|
|||
customTheme={comparisonChartTheme}
|
||||
timeseries={timeseries}
|
||||
yLabelFormat={getResponseTimeTickFormatter(latencyFormatter)}
|
||||
anomalyTimeseries={preferredAnomalyTimeseries}
|
||||
anomalyTimeseries={
|
||||
preferredAnomalyTimeseries
|
||||
? {
|
||||
...preferredAnomalyTimeseries,
|
||||
color: anomalyTimeseriesColor,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -17,8 +17,10 @@ import {
|
|||
niceTimeFormatter,
|
||||
Position,
|
||||
ScaleType,
|
||||
SeriesIdentifier,
|
||||
Settings,
|
||||
XYBrushEvent,
|
||||
XYChartSeriesIdentifier,
|
||||
YDomainRange,
|
||||
} from '@elastic/charts';
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
|
@ -26,6 +28,8 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useChartTheme } from '@kbn/observability-plugin/public';
|
||||
import { isExpectedBoundsComparison } from '../time_comparison/get_comparison_options';
|
||||
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
|
||||
import { ServiceAnomalyTimeseries } from '../../../../common/anomaly_detection/service_anomaly_timeseries';
|
||||
import { asAbsoluteDateTime } from '../../../../common/utils/formatters';
|
||||
import { Coordinate, TimeSeries } from '../../../../typings/timeseries';
|
||||
|
@ -36,10 +40,16 @@ import { FETCH_STATUS } from '../../../hooks/use_fetcher';
|
|||
import { useTheme } from '../../../hooks/use_theme';
|
||||
import { unit } from '../../../utils/style';
|
||||
import { ChartContainer } from './chart_container';
|
||||
import { getChartAnomalyTimeseries } from './helper/get_chart_anomaly_timeseries';
|
||||
import {
|
||||
expectedBoundsTitle,
|
||||
getChartAnomalyTimeseries,
|
||||
} from './helper/get_chart_anomaly_timeseries';
|
||||
import { isTimeseriesEmpty, onBrushEnd } from './helper/helper';
|
||||
import { getTimeZone } from './helper/timezone';
|
||||
|
||||
interface AnomalyTimeseries extends ServiceAnomalyTimeseries {
|
||||
color?: string;
|
||||
}
|
||||
interface Props {
|
||||
id: string;
|
||||
fetchStatus: FETCH_STATUS;
|
||||
|
@ -56,8 +66,9 @@ interface Props {
|
|||
yTickFormat?: (y: number) => string;
|
||||
showAnnotations?: boolean;
|
||||
yDomain?: YDomainRange;
|
||||
anomalyTimeseries?: ServiceAnomalyTimeseries;
|
||||
anomalyTimeseries?: AnomalyTimeseries;
|
||||
customTheme?: Record<string, unknown>;
|
||||
anomalyTimeseriesColor?: string;
|
||||
}
|
||||
export function TimeseriesChart({
|
||||
id,
|
||||
|
@ -78,6 +89,9 @@ export function TimeseriesChart({
|
|||
const { setPointerEvent, chartRef } = useChartPointerEventContext();
|
||||
const theme = useTheme();
|
||||
const chartTheme = useChartTheme();
|
||||
const {
|
||||
query: { comparisonEnabled, offset },
|
||||
} = useAnyOfApmParams('/services', '/backends/*', '/services/{serviceName}');
|
||||
|
||||
const xValues = timeseries.flatMap(({ data }) => data.map(({ x }) => x));
|
||||
|
||||
|
@ -89,19 +103,34 @@ export function TimeseriesChart({
|
|||
const anomalyChartTimeseries = getChartAnomalyTimeseries({
|
||||
anomalyTimeseries,
|
||||
theme,
|
||||
anomalyTimeseriesColor: anomalyTimeseries?.color,
|
||||
});
|
||||
|
||||
const xFormatter = niceTimeFormatter([min, max]);
|
||||
const isEmpty = isTimeseriesEmpty(timeseries);
|
||||
const annotationColor = theme.eui.euiColorSuccess;
|
||||
|
||||
const isComparingExpectedBounds =
|
||||
comparisonEnabled && isExpectedBoundsComparison(offset);
|
||||
const allSeries = [
|
||||
...timeseries,
|
||||
// TODO: re-enable anomaly boundaries when we have a fix for https://github.com/elastic/kibana/issues/100660
|
||||
// ...(anomalyChartTimeseries?.boundaries ?? []),
|
||||
...(isComparingExpectedBounds && anomalyChartTimeseries?.boundaries
|
||||
? anomalyChartTimeseries?.boundaries
|
||||
: []),
|
||||
...(anomalyChartTimeseries?.scores ?? []),
|
||||
];
|
||||
const xDomain = isEmpty ? { min: 0, max: 1 } : { min, max };
|
||||
|
||||
const legendSort = (a: SeriesIdentifier, b: SeriesIdentifier) => {
|
||||
// Using custom legendSort here when comparing expected bounds
|
||||
// because by default elastic-charts will show legends for expected bounds first
|
||||
// but for consistency, we are making `Expected bounds` last
|
||||
if ((a as XYChartSeriesIdentifier)?.specId === expectedBoundsTitle)
|
||||
return -1;
|
||||
if ((b as XYChartSeriesIdentifier)?.specId === expectedBoundsTitle)
|
||||
return -1;
|
||||
return 1;
|
||||
};
|
||||
return (
|
||||
<ChartContainer
|
||||
hasData={!isEmpty}
|
||||
|
@ -111,7 +140,7 @@ export function TimeseriesChart({
|
|||
>
|
||||
<Chart ref={chartRef} id={id}>
|
||||
<Settings
|
||||
tooltip={{ stickTo: 'top', showNullValues: true }}
|
||||
tooltip={{ stickTo: 'top', showNullValues: false }}
|
||||
onBrushEnd={(event) =>
|
||||
onBrushEnd({ x: (event as XYBrushEvent).x, history })
|
||||
}
|
||||
|
@ -129,6 +158,7 @@ export function TimeseriesChart({
|
|||
tooltip: { visible: true },
|
||||
}}
|
||||
showLegend
|
||||
legendSort={isComparingExpectedBounds ? legendSort : undefined}
|
||||
legendPosition={Position.Bottom}
|
||||
xDomain={xDomain}
|
||||
onLegendItemClick={(legend) => {
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { usePreviousPeriodLabel } from '../../../../hooks/use_previous_period_text';
|
||||
import { isTimeComparison } from '../../time_comparison/get_comparison_options';
|
||||
import { APIReturnType } from '../../../../services/rest/create_call_apm_api';
|
||||
import { asPercent } from '../../../../../common/utils/formatters';
|
||||
import { useFetcher } from '../../../../hooks/use_fetcher';
|
||||
|
@ -90,7 +92,10 @@ export function TransactionColdstartRateChart({
|
|||
start,
|
||||
end,
|
||||
transactionType,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
...(transactionName ? { transactionName } : {}),
|
||||
},
|
||||
},
|
||||
|
@ -110,6 +115,7 @@ export function TransactionColdstartRateChart({
|
|||
comparisonEnabled,
|
||||
]
|
||||
);
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
|
||||
const timeseries = [
|
||||
{
|
||||
|
@ -126,10 +132,7 @@ export function TransactionColdstartRateChart({
|
|||
data: data.previousPeriod.transactionColdstartRate,
|
||||
type: 'area',
|
||||
color: theme.eui.euiColorMediumShade,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.coldstartRate.chart.coldstartRate.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
|
|
@ -7,14 +7,23 @@
|
|||
|
||||
import moment from 'moment';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Environment } from '../../../../common/environment_rt';
|
||||
import { AnomalyDetectionJobsContextValue } from '../../../context/anomaly_detection_jobs/anomaly_detection_jobs_context';
|
||||
import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms';
|
||||
|
||||
export enum TimeRangeComparisonEnum {
|
||||
WeekBefore = 'week',
|
||||
DayBefore = 'day',
|
||||
PeriodBefore = 'period',
|
||||
ExpectedBounds = 'expected_bounds',
|
||||
}
|
||||
|
||||
export const isTimeComparison = (v: string | undefined) =>
|
||||
v !== TimeRangeComparisonEnum.ExpectedBounds;
|
||||
|
||||
export const isExpectedBoundsComparison = (v: string | undefined) =>
|
||||
v === TimeRangeComparisonEnum.ExpectedBounds;
|
||||
|
||||
export const dayAndWeekBeforeToOffset = {
|
||||
[TimeRangeComparisonEnum.DayBefore]: '1d',
|
||||
[TimeRangeComparisonEnum.WeekBefore]: '1w',
|
||||
|
@ -41,6 +50,10 @@ function formatDate({
|
|||
)} - ${previousPeriodEnd.format(dateFormat)}`;
|
||||
}
|
||||
|
||||
function isDefined<T>(argument: T | undefined | null): argument is T {
|
||||
return argument !== undefined && argument !== null;
|
||||
}
|
||||
|
||||
function getSelectOptions({
|
||||
comparisonTypes,
|
||||
start,
|
||||
|
@ -51,51 +64,61 @@ function getSelectOptions({
|
|||
start: moment.Moment;
|
||||
end: moment.Moment;
|
||||
msDiff: number;
|
||||
}) {
|
||||
return comparisonTypes.map((value) => {
|
||||
switch (value) {
|
||||
case TimeRangeComparisonEnum.DayBefore: {
|
||||
return {
|
||||
value: dayAndWeekBeforeToOffset[TimeRangeComparisonEnum.DayBefore],
|
||||
text: i18n.translate('xpack.apm.timeComparison.select.dayBefore', {
|
||||
defaultMessage: 'Day before',
|
||||
}),
|
||||
};
|
||||
}
|
||||
case TimeRangeComparisonEnum.WeekBefore: {
|
||||
return {
|
||||
value: dayAndWeekBeforeToOffset[TimeRangeComparisonEnum.WeekBefore],
|
||||
text: i18n.translate('xpack.apm.timeComparison.select.weekBefore', {
|
||||
defaultMessage: 'Week before',
|
||||
}),
|
||||
};
|
||||
}
|
||||
case TimeRangeComparisonEnum.PeriodBefore: {
|
||||
const offset = `${msDiff}ms`;
|
||||
}): Array<{ value: string; text: string; disabled?: boolean }> {
|
||||
return comparisonTypes
|
||||
.map((value) => {
|
||||
switch (value) {
|
||||
case TimeRangeComparisonEnum.DayBefore: {
|
||||
return {
|
||||
value: dayAndWeekBeforeToOffset[TimeRangeComparisonEnum.DayBefore],
|
||||
text: i18n.translate('xpack.apm.timeComparison.select.dayBefore', {
|
||||
defaultMessage: 'Day before',
|
||||
}),
|
||||
};
|
||||
}
|
||||
case TimeRangeComparisonEnum.WeekBefore: {
|
||||
return {
|
||||
value: dayAndWeekBeforeToOffset[TimeRangeComparisonEnum.WeekBefore],
|
||||
text: i18n.translate('xpack.apm.timeComparison.select.weekBefore', {
|
||||
defaultMessage: 'Week before',
|
||||
}),
|
||||
};
|
||||
}
|
||||
case TimeRangeComparisonEnum.PeriodBefore: {
|
||||
const offset = `${msDiff}ms`;
|
||||
|
||||
const { startWithOffset, endWithOffset } = getOffsetInMs({
|
||||
start: start.valueOf(),
|
||||
end: end.valueOf(),
|
||||
offset,
|
||||
});
|
||||
const { startWithOffset, endWithOffset } = getOffsetInMs({
|
||||
start: start.valueOf(),
|
||||
end: end.valueOf(),
|
||||
offset,
|
||||
});
|
||||
|
||||
return {
|
||||
value: offset,
|
||||
text: formatDate({
|
||||
currentPeriodEnd: end,
|
||||
previousPeriodStart: moment(startWithOffset),
|
||||
previousPeriodEnd: moment(endWithOffset),
|
||||
}),
|
||||
};
|
||||
return {
|
||||
value: offset,
|
||||
text: formatDate({
|
||||
currentPeriodEnd: end,
|
||||
previousPeriodStart: moment(startWithOffset),
|
||||
previousPeriodEnd: moment(endWithOffset),
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.filter(isDefined);
|
||||
}
|
||||
|
||||
export function getComparisonOptions({
|
||||
start,
|
||||
end,
|
||||
canGetJobs,
|
||||
anomalyDetectionJobsStatus,
|
||||
anomalyDetectionJobsData,
|
||||
preferredEnvironment,
|
||||
}: {
|
||||
canGetJobs?: boolean;
|
||||
anomalyDetectionJobsStatus?: AnomalyDetectionJobsContextValue['anomalyDetectionJobsStatus'];
|
||||
anomalyDetectionJobsData?: AnomalyDetectionJobsContextValue['anomalyDetectionJobsData'];
|
||||
preferredEnvironment?: Environment;
|
||||
start?: string;
|
||||
end?: string;
|
||||
}) {
|
||||
|
@ -120,10 +143,36 @@ export function getComparisonOptions({
|
|||
comparisonTypes = [TimeRangeComparisonEnum.PeriodBefore];
|
||||
}
|
||||
|
||||
return getSelectOptions({
|
||||
const hasMLJobsMatchingEnv =
|
||||
canGetJobs &&
|
||||
Array.isArray(anomalyDetectionJobsData?.jobs) &&
|
||||
anomalyDetectionJobsData?.jobs.some(
|
||||
(j) => j.environment === preferredEnvironment
|
||||
);
|
||||
|
||||
const comparisonOptions = getSelectOptions({
|
||||
comparisonTypes,
|
||||
start: momentStart,
|
||||
end: momentEnd,
|
||||
msDiff,
|
||||
});
|
||||
|
||||
if (canGetJobs) {
|
||||
const disabled =
|
||||
anomalyDetectionJobsStatus === 'success' && !hasMLJobsMatchingEnv;
|
||||
comparisonOptions.push({
|
||||
value: TimeRangeComparisonEnum.ExpectedBounds,
|
||||
text: disabled
|
||||
? i18n.translate('xpack.apm.comparison.mlExpectedBoundsDisabledText', {
|
||||
defaultMessage:
|
||||
'Expected bounds (Anomaly detection must be enabled for env)',
|
||||
})
|
||||
: i18n.translate('xpack.apm.comparison.mlExpectedBoundsText', {
|
||||
defaultMessage: 'Expected bounds',
|
||||
}),
|
||||
disabled,
|
||||
});
|
||||
}
|
||||
|
||||
return comparisonOptions;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,21 @@
|
|||
|
||||
import { EuiCheckbox, EuiSelect } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { useUiTracker } from '@kbn/observability-plugin/public';
|
||||
import { useEnvironmentsContext } from '../../../context/environments_context/use_environments_context';
|
||||
import { useAnomalyDetectionJobsContext } from '../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context';
|
||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useBreakpoints } from '../../../hooks/use_breakpoints';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
import * as urlHelpers from '../links/url_helpers';
|
||||
import { getComparisonOptions } from './get_comparison_options';
|
||||
import {
|
||||
getComparisonOptions,
|
||||
TimeRangeComparisonEnum,
|
||||
} from './get_comparison_options';
|
||||
|
||||
const PrependContainer = euiStyled.div`
|
||||
display: flex;
|
||||
|
@ -34,16 +40,48 @@ export function TimeComparison() {
|
|||
query: { rangeFrom, rangeTo, comparisonEnabled, offset },
|
||||
} = useAnyOfApmParams('/services', '/backends/*', '/services/{serviceName}');
|
||||
|
||||
const { anomalyDetectionJobsStatus, anomalyDetectionJobsData } =
|
||||
useAnomalyDetectionJobsContext();
|
||||
const { core } = useApmPluginContext();
|
||||
const { preferredEnvironment } = useEnvironmentsContext();
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const comparisonOptions = getComparisonOptions({ start, end });
|
||||
const canGetJobs = !!core.application.capabilities.ml?.canGetJobs;
|
||||
const comparisonOptions = useMemo(() => {
|
||||
const timeComparisonOptions = getComparisonOptions({
|
||||
start,
|
||||
end,
|
||||
canGetJobs,
|
||||
anomalyDetectionJobsStatus,
|
||||
anomalyDetectionJobsData,
|
||||
preferredEnvironment,
|
||||
});
|
||||
|
||||
return timeComparisonOptions;
|
||||
}, [
|
||||
canGetJobs,
|
||||
anomalyDetectionJobsStatus,
|
||||
anomalyDetectionJobsData,
|
||||
start,
|
||||
end,
|
||||
preferredEnvironment,
|
||||
]);
|
||||
|
||||
const isSelectedComparisonTypeAvailable = comparisonOptions.some(
|
||||
({ value }) => value === offset
|
||||
);
|
||||
|
||||
// Replaces type when current one is no longer available in the select options
|
||||
if (comparisonOptions.length !== 0 && !isSelectedComparisonTypeAvailable) {
|
||||
if (
|
||||
(comparisonOptions.length !== 0 && !isSelectedComparisonTypeAvailable) ||
|
||||
// If user changes environment and there's no ML jobs that match the new environment
|
||||
// then also default to first comparison option as well
|
||||
(offset === TimeRangeComparisonEnum.ExpectedBounds &&
|
||||
comparisonOptions.find(
|
||||
(d) => d.value === TimeRangeComparisonEnum.ExpectedBounds
|
||||
)?.disabled === true)
|
||||
) {
|
||||
urlHelpers.replace(history, {
|
||||
query: { offset: comparisonOptions[0].value },
|
||||
});
|
||||
|
@ -54,7 +92,7 @@ export function TimeComparison() {
|
|||
<EuiSelect
|
||||
fullWidth={isSmall}
|
||||
data-test-subj="comparisonSelect"
|
||||
disabled={!comparisonEnabled}
|
||||
disabled={comparisonEnabled === false}
|
||||
options={comparisonOptions}
|
||||
value={offset}
|
||||
prepend={
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { ValuesType } from 'utility-types';
|
||||
import { isTimeComparison } from '../time_comparison/get_comparison_options';
|
||||
import { LatencyAggregationType } from '../../../../common/latency_aggregation_types';
|
||||
import {
|
||||
asMillisecondDuration,
|
||||
|
@ -110,7 +111,9 @@ export function getColumns({
|
|||
isLoading={transactionGroupDetailedStatisticsLoading}
|
||||
series={currentTimeseries}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousTimeseries : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousTimeseries
|
||||
: undefined
|
||||
}
|
||||
valueLabel={asMillisecondDuration(latency)}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
|
@ -145,7 +148,9 @@ export function getColumns({
|
|||
isLoading={transactionGroupDetailedStatisticsLoading}
|
||||
series={currentTimeseries}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousTimeseries : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousTimeseries
|
||||
: undefined
|
||||
}
|
||||
valueLabel={asTransactionRate(throughput)}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
|
@ -202,7 +207,9 @@ export function getColumns({
|
|||
isLoading={transactionGroupDetailedStatisticsLoading}
|
||||
series={currentTimeseries}
|
||||
comparisonSeries={
|
||||
comparisonEnabled ? previousTimeseries : undefined
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? previousTimeseries
|
||||
: undefined
|
||||
}
|
||||
valueLabel={asPercent(errorRate, 1)}
|
||||
comparisonSeriesColor={previousPeriodColor}
|
||||
|
|
|
@ -30,6 +30,7 @@ import { useBreakpoints } from '../../../hooks/use_breakpoints';
|
|||
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
|
||||
import { LatencyAggregationType } from '../../../../common/latency_aggregation_types';
|
||||
import { fromQuery, toQuery } from '../links/url_helpers';
|
||||
import { isTimeComparison } from '../time_comparison/get_comparison_options';
|
||||
|
||||
type ApiResponse =
|
||||
APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>;
|
||||
|
@ -221,7 +222,10 @@ export function TransactionsTable({
|
|||
transactionNames: JSON.stringify(
|
||||
transactionGroups.map(({ name }) => name).sort()
|
||||
),
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -16,10 +16,12 @@ export const EnvironmentsContext = React.createContext<{
|
|||
environment: Environment;
|
||||
environments: Environment[];
|
||||
status: FETCH_STATUS;
|
||||
preferredEnvironment: Environment;
|
||||
}>({
|
||||
environment: ENVIRONMENT_ALL.value,
|
||||
environments: [],
|
||||
status: FETCH_STATUS.NOT_INITIATED,
|
||||
preferredEnvironment: ENVIRONMENT_ALL.value,
|
||||
});
|
||||
|
||||
export function EnvironmentsContextProvider({
|
||||
|
@ -44,6 +46,10 @@ export function EnvironmentsContextProvider({
|
|||
start,
|
||||
end,
|
||||
});
|
||||
const preferredEnvironment =
|
||||
environment === ENVIRONMENT_ALL.value && environments.length === 1
|
||||
? environments[0]
|
||||
: environment;
|
||||
|
||||
return (
|
||||
<EnvironmentsContext.Provider
|
||||
|
@ -51,6 +57,7 @@ export function EnvironmentsContextProvider({
|
|||
environment,
|
||||
environments,
|
||||
status,
|
||||
preferredEnvironment,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useEnvironmentsContext } from '../environments_context/use_environments_context';
|
||||
import { ServiceAnomalyTimeseries } from '../../../common/anomaly_detection/service_anomaly_timeseries';
|
||||
import { useApmParams } from '../../hooks/use_apm_params';
|
||||
import { FETCH_STATUS, useFetcher } from '../../hooks/use_fetcher';
|
||||
|
@ -46,13 +47,13 @@ export function ServiceAnomalyTimeseriesContextProvider({
|
|||
} = useApmParams('/services/{serviceName}');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
const { preferredEnvironment } = useEnvironmentsContext();
|
||||
|
||||
const { status, data } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!transactionType || !canGetAnomalies) {
|
||||
return;
|
||||
}
|
||||
|
||||
return callApmApi(
|
||||
'GET /internal/apm/services/{serviceName}/anomaly_charts',
|
||||
{
|
||||
|
@ -64,12 +65,20 @@ export function ServiceAnomalyTimeseriesContextProvider({
|
|||
start,
|
||||
end,
|
||||
transactionType,
|
||||
environment: preferredEnvironment,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
[serviceName, canGetAnomalies, transactionType, start, end]
|
||||
[
|
||||
serviceName,
|
||||
canGetAnomalies,
|
||||
transactionType,
|
||||
start,
|
||||
end,
|
||||
preferredEnvironment,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { isTimeComparison } from '../components/shared/time_comparison/get_comparison_options';
|
||||
import { useApmParams } from './use_apm_params';
|
||||
import { useFetcher } from './use_fetcher';
|
||||
import { useTimeRange } from './use_time_range';
|
||||
|
@ -38,7 +39,10 @@ export function useErrorGroupDistributionFetcher({
|
|||
kuery,
|
||||
start,
|
||||
end,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
groupId,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -16,13 +16,12 @@ export function usePreferredServiceAnomalyTimeseries(
|
|||
) {
|
||||
const { allAnomalyTimeseries } = useServiceAnomalyTimeseriesContext();
|
||||
|
||||
const { environment, environments } = useEnvironmentsContext();
|
||||
const { preferredEnvironment } = useEnvironmentsContext();
|
||||
|
||||
const { fallbackToTransactions } = useApmServiceContext();
|
||||
|
||||
return getPreferredServiceAnomalyTimeseries({
|
||||
environment,
|
||||
environments,
|
||||
preferredEnvironment,
|
||||
fallbackToTransactions,
|
||||
detectorType,
|
||||
allAnomalyTimeseries,
|
||||
|
|
35
x-pack/plugins/apm/public/hooks/use_previous_period_text.ts
Normal file
35
x-pack/plugins/apm/public/hooks/use_previous_period_text.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useAnyOfApmParams } from './use_apm_params';
|
||||
import { useTimeRange } from './use_time_range';
|
||||
import { getComparisonOptions } from '../components/shared/time_comparison/get_comparison_options';
|
||||
|
||||
const fallbackPreviousPeriodText = i18n.translate(
|
||||
'xpack.apm.chart.comparison.defaultPreviousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
);
|
||||
|
||||
export const usePreviousPeriodLabel = () => {
|
||||
const {
|
||||
query: { rangeFrom, rangeTo, offset },
|
||||
} = useAnyOfApmParams('/services', '/backends/*', '/services/{serviceName}');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const previousPeriodText = useMemo(() => {
|
||||
const timeComparisonOptions = getComparisonOptions({ start, end });
|
||||
const comparisonPeriodText =
|
||||
timeComparisonOptions.find(
|
||||
(d) => d.value === offset || d.value.endsWith('ms')
|
||||
)?.text ?? fallbackPreviousPeriodText;
|
||||
return comparisonPeriodText;
|
||||
}, [start, end, offset]);
|
||||
return previousPeriodText;
|
||||
};
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { usePreviousPeriodLabel } from './use_previous_period_text';
|
||||
import { isTimeComparison } from '../components/shared/time_comparison/get_comparison_options';
|
||||
import { useFetcher } from './use_fetcher';
|
||||
import { useLegacyUrlParams } from '../context/url_params_context/use_url_params';
|
||||
import { useApmServiceContext } from '../context/apm_service/use_apm_service_context';
|
||||
|
@ -53,7 +55,10 @@ export function useTransactionLatencyChartsFetcher({
|
|||
transactionType,
|
||||
transactionName,
|
||||
latencyAggregationType,
|
||||
offset: comparisonEnabled ? offset : undefined,
|
||||
offset:
|
||||
comparisonEnabled && isTimeComparison(offset)
|
||||
? offset
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -74,11 +79,13 @@ export function useTransactionLatencyChartsFetcher({
|
|||
]
|
||||
);
|
||||
|
||||
const previousPeriodLabel = usePreviousPeriodLabel();
|
||||
const memoizedData = useMemo(
|
||||
() =>
|
||||
getLatencyChartSelector({
|
||||
latencyChart: data,
|
||||
latencyAggregationType,
|
||||
previousPeriodLabel,
|
||||
}),
|
||||
// It should only update when the data has changed
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
@ -35,7 +35,9 @@ describe('getLatencyChartSelector', () => {
|
|||
|
||||
describe('without anomaly', () => {
|
||||
it('returns default values when data is undefined', () => {
|
||||
const latencyChart = getLatencyChartSelector({});
|
||||
const latencyChart = getLatencyChartSelector({
|
||||
previousPeriodLabel: 'Day before',
|
||||
});
|
||||
expect(latencyChart).toEqual({
|
||||
currentPeriod: undefined,
|
||||
previousPeriod: undefined,
|
||||
|
@ -46,6 +48,7 @@ describe('getLatencyChartSelector', () => {
|
|||
const latencyTimeseries = getLatencyChartSelector({
|
||||
latencyChart: latencyChartData,
|
||||
latencyAggregationType: LatencyAggregationType.avg,
|
||||
previousPeriodLabel: 'Week before',
|
||||
});
|
||||
expect(latencyTimeseries).toEqual({
|
||||
currentPeriod: {
|
||||
|
@ -60,7 +63,7 @@ describe('getLatencyChartSelector', () => {
|
|||
color: 'black',
|
||||
data: [{ x: 1, y: 10 }],
|
||||
type: 'area',
|
||||
title: 'Previous period',
|
||||
title: 'Week before',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -69,6 +72,7 @@ describe('getLatencyChartSelector', () => {
|
|||
const latencyTimeseries = getLatencyChartSelector({
|
||||
latencyChart: latencyChartData,
|
||||
latencyAggregationType: LatencyAggregationType.p95,
|
||||
previousPeriodLabel: 'Day before',
|
||||
});
|
||||
expect(latencyTimeseries).toEqual({
|
||||
currentPeriod: {
|
||||
|
@ -82,7 +86,7 @@ describe('getLatencyChartSelector', () => {
|
|||
data: [{ x: 1, y: 10 }],
|
||||
type: 'area',
|
||||
color: 'black',
|
||||
title: 'Previous period',
|
||||
title: 'Day before',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -91,6 +95,7 @@ describe('getLatencyChartSelector', () => {
|
|||
const latencyTimeseries = getLatencyChartSelector({
|
||||
latencyChart: latencyChartData,
|
||||
latencyAggregationType: LatencyAggregationType.p99,
|
||||
previousPeriodLabel: 'Day before',
|
||||
});
|
||||
|
||||
expect(latencyTimeseries).toEqual({
|
||||
|
@ -105,7 +110,7 @@ describe('getLatencyChartSelector', () => {
|
|||
data: [{ x: 1, y: 10 }],
|
||||
type: 'area',
|
||||
color: 'black',
|
||||
title: 'Previous period',
|
||||
title: 'Day before',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -116,6 +121,7 @@ describe('getLatencyChartSelector', () => {
|
|||
const latencyTimeseries = getLatencyChartSelector({
|
||||
latencyChart: latencyChartData,
|
||||
latencyAggregationType: LatencyAggregationType.p99,
|
||||
previousPeriodLabel: 'Previous period',
|
||||
});
|
||||
expect(latencyTimeseries).toEqual({
|
||||
currentPeriod: {
|
||||
|
|
|
@ -25,9 +25,11 @@ export interface LatencyChartData {
|
|||
export function getLatencyChartSelector({
|
||||
latencyChart,
|
||||
latencyAggregationType,
|
||||
previousPeriodLabel,
|
||||
}: {
|
||||
latencyChart?: LatencyChartsResponse;
|
||||
latencyAggregationType?: string;
|
||||
previousPeriodLabel: string;
|
||||
}): Partial<LatencyChartData> {
|
||||
if (
|
||||
!latencyChart?.currentPeriod.latencyTimeseries ||
|
||||
|
@ -43,6 +45,7 @@ export function getLatencyChartSelector({
|
|||
previousPeriod: getPreviousPeriodTimeseries({
|
||||
previousPeriod: latencyChart.previousPeriod,
|
||||
latencyAggregationType,
|
||||
previousPeriodLabel,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
@ -50,9 +53,11 @@ export function getLatencyChartSelector({
|
|||
function getPreviousPeriodTimeseries({
|
||||
previousPeriod,
|
||||
latencyAggregationType,
|
||||
previousPeriodLabel,
|
||||
}: {
|
||||
previousPeriod: LatencyChartsResponse['previousPeriod'];
|
||||
latencyAggregationType: string;
|
||||
previousPeriodLabel: string;
|
||||
}) {
|
||||
let chartType = ChartType.LATENCY_AVG;
|
||||
if (latencyAggregationType === 'p95') {
|
||||
|
@ -67,10 +72,7 @@ function getPreviousPeriodTimeseries({
|
|||
data: previousPeriod.latencyTimeseries ?? [],
|
||||
type: 'area',
|
||||
color: previousPeriodColor,
|
||||
title: i18n.translate(
|
||||
'xpack.apm.serviceOverview.latencyChartTitle.previousPeriodLabel',
|
||||
{ defaultMessage: 'Previous period' }
|
||||
),
|
||||
title: previousPeriodLabel,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,16 @@ import { getBucketSize } from '../helpers/get_bucket_size';
|
|||
export function getAnomalyResultBucketSize({
|
||||
start,
|
||||
end,
|
||||
minBucketSize,
|
||||
}: {
|
||||
start: number;
|
||||
end: number;
|
||||
minBucketSize?: number;
|
||||
}) {
|
||||
return getBucketSize({
|
||||
start,
|
||||
end,
|
||||
numBuckets: 100,
|
||||
minBucketSize,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
import type { Logger } from '@kbn/logging';
|
||||
import { compact, keyBy } from 'lodash';
|
||||
import { rangeQuery } from '@kbn/observability-plugin/server';
|
||||
import { parseInterval } from '@kbn/data-plugin/common';
|
||||
import { Environment } from '../../../common/environment_rt';
|
||||
import { apmMlAnomalyQuery } from './apm_ml_anomaly_query';
|
||||
import {
|
||||
ApmMlDetectorType,
|
||||
|
@ -29,11 +31,13 @@ export async function getAnomalyTimeseries({
|
|||
end,
|
||||
logger,
|
||||
mlSetup,
|
||||
environment: preferredEnvironment,
|
||||
}: {
|
||||
serviceName: string;
|
||||
transactionType: string;
|
||||
start: number;
|
||||
end: number;
|
||||
environment: Environment;
|
||||
logger: Logger;
|
||||
mlSetup: Required<Setup>['ml'];
|
||||
}): Promise<ServiceAnomalyTimeseries[]> {
|
||||
|
@ -41,17 +45,31 @@ export async function getAnomalyTimeseries({
|
|||
return [];
|
||||
}
|
||||
|
||||
const { intervalString } = getAnomalyResultBucketSize({
|
||||
start,
|
||||
end,
|
||||
});
|
||||
|
||||
const mlJobs = await getMlJobsWithAPMGroup(mlSetup.anomalyDetectors);
|
||||
|
||||
if (!mlJobs.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If multiple ML jobs exist
|
||||
// find the first job with valid running datafeed that matches the preferred environment
|
||||
const preferredBucketSpan = mlJobs.find(
|
||||
(j) =>
|
||||
j.datafeedState !== undefined && j.environment === preferredEnvironment
|
||||
)?.bucketSpan;
|
||||
|
||||
// If the calculated bucketSize is smaller than the bucket span interval,
|
||||
// use the original job's bucket_span
|
||||
const minBucketSize = preferredBucketSpan
|
||||
? parseInterval(preferredBucketSpan)?.asSeconds()
|
||||
: undefined;
|
||||
|
||||
const { intervalString } = getAnomalyResultBucketSize({
|
||||
start,
|
||||
end,
|
||||
minBucketSize,
|
||||
});
|
||||
|
||||
const anomaliesResponse = await anomalySearch(
|
||||
mlSetup.mlSystem.mlAnomalySearch,
|
||||
{
|
||||
|
|
|
@ -59,6 +59,7 @@ export function getMlJobsWithAPMGroup(
|
|||
version: Number(job.custom_settings?.job_tags?.apm_ml_version ?? 1),
|
||||
datafeedId: datafeedStats?.datafeed_id,
|
||||
datafeedState: datafeedStats?.state as ApmMlJob['datafeedState'],
|
||||
bucketSpan: job.analysis_config?.bucket_span,
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { getUpstreamServicesForBackend } from './get_upstream_services_for_backe
|
|||
import { getThroughputChartsForBackend } from './get_throughput_charts_for_backend';
|
||||
import { getErrorRateChartsForBackend } from './get_error_rate_charts_for_backend';
|
||||
import { ConnectionStatsItemWithImpact } from '../../../common/connections';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const topBackendsRoute = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/backends/top_backends',
|
||||
|
|
|
@ -14,7 +14,7 @@ import { environmentRt, kueryRt, rangeRt } from '../default_api_types';
|
|||
import { getErrorGroupMainStatistics } from './get_error_groups/get_error_group_main_statistics';
|
||||
import { getErrorGroupPeriods } from './get_error_groups/get_error_group_detailed_statistics';
|
||||
import { getErrorGroupSample } from './get_error_groups/get_error_group_sample';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const errorsMainStatisticsRoute = createApmServerRoute({
|
||||
endpoint:
|
||||
|
|
|
@ -18,7 +18,7 @@ import { getServiceMapServiceNodeInfo } from './get_service_map_service_node_inf
|
|||
import { createApmServerRoute } from '../apm_routes/create_apm_server_route';
|
||||
import { environmentRt, rangeRt } from '../default_api_types';
|
||||
import { getServiceGroup } from '../service_groups/get_service_group';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const serviceMapRoute = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/service-map',
|
||||
|
|
|
@ -52,7 +52,7 @@ import { ConnectionStatsItemWithImpact } from '../../../common/connections';
|
|||
import { getSortedAndFilteredServices } from './get_services/get_sorted_and_filtered_services';
|
||||
import { ServiceHealthStatus } from '../../../common/service_health_status';
|
||||
import { getServiceGroup } from '../service_groups/get_service_group';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const servicesRoute = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/services',
|
||||
|
@ -1161,7 +1161,11 @@ const serviceAnomalyChartsRoute = createApmServerRoute({
|
|||
path: t.type({
|
||||
serviceName: t.string,
|
||||
}),
|
||||
query: t.intersection([rangeRt, t.type({ transactionType: t.string })]),
|
||||
query: t.intersection([
|
||||
rangeRt,
|
||||
environmentRt,
|
||||
t.type({ transactionType: t.string }),
|
||||
]),
|
||||
}),
|
||||
options: {
|
||||
tags: ['access:apm'],
|
||||
|
@ -1181,7 +1185,7 @@ const serviceAnomalyChartsRoute = createApmServerRoute({
|
|||
|
||||
const {
|
||||
path: { serviceName },
|
||||
query: { start, end, transactionType },
|
||||
query: { start, end, transactionType, environment },
|
||||
} = resources.params;
|
||||
|
||||
try {
|
||||
|
@ -1192,6 +1196,7 @@ const serviceAnomalyChartsRoute = createApmServerRoute({
|
|||
end,
|
||||
mlSetup: setup.ml,
|
||||
logger: resources.logger,
|
||||
environment,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -22,7 +22,7 @@ import { getFailedTransactionRatePeriods } from './get_failed_transaction_rate_p
|
|||
import { getColdstartRatePeriods } from '../../lib/transaction_groups/get_coldstart_rate';
|
||||
import { createApmServerRoute } from '../apm_routes/create_apm_server_route';
|
||||
import { environmentRt, kueryRt, rangeRt } from '../default_api_types';
|
||||
import { offsetRt } from '../../../common/offset_rt';
|
||||
import { offsetRt } from '../../../common/comparison_rt';
|
||||
|
||||
const transactionGroupsMainStatisticsRoute = createApmServerRoute({
|
||||
endpoint:
|
||||
|
|
|
@ -5348,10 +5348,10 @@
|
|||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "Cette intégration n'est pas encore activée. Votre administrateur possède les autorisations requises pour l’activer.",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "Contactez votre administrateur",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.title": "Ajouter Elastic Agent",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "Envie d'en savoir plus ?",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "Lisez les documents",
|
||||
"sharedUXComponents.pageTemplate.noDataCard.description": "Continuer sans collecter de données",
|
||||
"sharedUXComponents.toolbar.buttons.addFromLibrary.libraryButtonLabel": "Ajouter depuis la bibliothèque",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "Envie d'en savoir plus ?",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "Lisez les documents",
|
||||
"telemetry.callout.appliesSettingTitle": "Les modifications apportées à ce paramètre s'appliquent dans {allOfKibanaText} et sont enregistrées automatiquement.",
|
||||
"telemetry.callout.appliesSettingTitle.allOfKibanaText": "tout Kibana",
|
||||
"telemetry.callout.clusterStatisticsDescription": "Voici un exemple des statistiques de cluster de base que nous collecterons. Cela comprend le nombre d'index, de partitions et de nœuds. Cela comprend également des statistiques d'utilisation de niveau élevé, comme l'état d'activation du monitoring.",
|
||||
|
@ -7181,12 +7181,9 @@
|
|||
"xpack.apm.backendDetailLatencyChartTitle": "Latence",
|
||||
"xpack.apm.backendDetailThroughputChartTitle": "Rendement",
|
||||
"xpack.apm.backendErrorRateChart.chartTitle": "Taux de transactions ayant échoué",
|
||||
"xpack.apm.backendErrorRateChart.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.backendInventory.dependencyTableColumn": "Dépendance",
|
||||
"xpack.apm.backendLatencyChart.chartTitle": "Latence",
|
||||
"xpack.apm.backendLatencyChart.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.backendThroughputChart.chartTitle": "Rendement",
|
||||
"xpack.apm.backendThroughputChart.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.chart.annotation.version": "Version",
|
||||
"xpack.apm.chart.cpuSeries.processAverageLabel": "Moyenne de processus",
|
||||
"xpack.apm.chart.cpuSeries.processMaxLabel": "Max de processus",
|
||||
|
@ -7197,7 +7194,6 @@
|
|||
"xpack.apm.chart.memorySeries.systemMaxLabel": "Max.",
|
||||
"xpack.apm.coldstartRate": "Taux de démarrage à froid",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate": "Taux de démarrage à froid (moy.)",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.compositeSpanCallsLabel": ", {count} appels, sur une moyenne de {duration}",
|
||||
"xpack.apm.compositeSpanDurationLabel": "Durée moyenne",
|
||||
"xpack.apm.correlations.cancelButtonTitle": "Annuler",
|
||||
|
@ -7295,7 +7291,6 @@
|
|||
"xpack.apm.errorCountAlert.name": "Seuil de nombre d'erreurs",
|
||||
"xpack.apm.errorCountAlertTrigger.errors": " erreurs",
|
||||
"xpack.apm.errorGroup.chart.ocurrences": "Occurrences",
|
||||
"xpack.apm.errorGroup.chart.ocurrences.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.errorGroupDetails.culpritLabel": "Coupable",
|
||||
"xpack.apm.errorGroupDetails.errorGroupTitle": "Groupe d'erreurs {errorGroupId}",
|
||||
"xpack.apm.errorGroupDetails.errorOccurrenceTitle": "Occurrence d'erreur",
|
||||
|
@ -7307,7 +7302,6 @@
|
|||
"xpack.apm.errorGroupDetails.viewOccurrencesInDiscoverButtonLabel": "Visualisez {occurrencesCount} {occurrencesCount, plural, one {occurrence} other {occurrences}} dans Discover.",
|
||||
"xpack.apm.errorRate": "Taux de transactions ayant échoué",
|
||||
"xpack.apm.errorRate.chart.errorRate": "Taux de transactions ayant échoué (moy.)",
|
||||
"xpack.apm.errorRate.chart.errorRate.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.errorRate.tip": "Le pourcentage de transactions ayant échoué pour le service sélectionné. Les transactions du serveur HTTP avec un code du statut 4xx (erreur du client) ne sont pas considérées comme des échecs, car l'appelant, et non le serveur, a provoqué l'échec.",
|
||||
"xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel": "Message d'erreur et coupable",
|
||||
"xpack.apm.errorsTable.groupIdColumnDescription": "Hachage de la trace de pile. Regroupe les erreurs similaires, même lorsque le message d'erreur est différent en raison des paramètres dynamiques.",
|
||||
|
@ -7480,7 +7474,6 @@
|
|||
"xpack.apm.home.serviceMapTabLabel": "Carte des services",
|
||||
"xpack.apm.inspectButtonText": "Inspecter",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend": "Instances",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend.previousPeriod": "Période précédente",
|
||||
"xpack.apm.instancesLatencyDistributionChartTitle": "Distribution de la latence des instances",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipClickToFilterDescription": "Cliquer pour filtrer par instance",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipInstancesTitle": "{instancesCount} {instancesCount, plural, one {instance} other {instances}}",
|
||||
|
@ -7727,14 +7720,12 @@
|
|||
"xpack.apm.serviceOverview.instanceTable.details.serviceTitle": "Service",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle": "Latence",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.prepend": "Indicateur",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.serviceOverview.latencyColumnAvgLabel": "Latence (moy.)",
|
||||
"xpack.apm.serviceOverview.latencyColumnDefaultLabel": "Latence",
|
||||
"xpack.apm.serviceOverview.latencyColumnP95Label": "Latence (95e)",
|
||||
"xpack.apm.serviceOverview.latencyColumnP99Label": "Latence (99e)",
|
||||
"xpack.apm.serviceOverview.loadingText": "Chargement…",
|
||||
"xpack.apm.serviceOverview.noResultsText": "Aucune instance trouvée",
|
||||
"xpack.apm.serviceOverview.throughtputChart.previousPeriodLabel": "Période précédente",
|
||||
"xpack.apm.serviceOverview.throughtputChartTitle": "Rendement",
|
||||
"xpack.apm.serviceOverview.tpmHelp": "Le rendement est mesuré en transactions par minute (tpm).",
|
||||
"xpack.apm.serviceOverview.transactionsTableColumnErrorRate": "Taux de transactions ayant échoué",
|
||||
|
|
|
@ -5450,10 +5450,10 @@
|
|||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "この統合はまだ有効ではありません。管理者にはオンにするために必要なアクセス権があります。",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "管理者にお問い合わせください",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.title": "Elasticエージェントの追加",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "詳細について",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "<b>ドキュメント</b><b>を読む</b>",
|
||||
"sharedUXComponents.pageTemplate.noDataCard.description": "データを収集せずに続行",
|
||||
"sharedUXComponents.toolbar.buttons.addFromLibrary.libraryButtonLabel": "ライブラリから追加",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "詳細について",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "<b>ドキュメント</b><b>を読む</b>",
|
||||
"telemetry.callout.appliesSettingTitle": "この設定に加えた変更は {allOfKibanaText} に適用され、自動的に保存されます。",
|
||||
"telemetry.callout.appliesSettingTitle.allOfKibanaText": "Kibana のすべて",
|
||||
"telemetry.callout.clusterStatisticsDescription": "これは収集される基本的なクラスター統計の例です。インデックス、シャード、ノードの数が含まれます。監視がオンになっているかどうかなどのハイレベルの使用統計も含まれます。",
|
||||
|
@ -7277,12 +7277,9 @@
|
|||
"xpack.apm.backendDetailLatencyChartTitle": "レイテンシ",
|
||||
"xpack.apm.backendDetailThroughputChartTitle": "スループット",
|
||||
"xpack.apm.backendErrorRateChart.chartTitle": "失敗したトランザクション率",
|
||||
"xpack.apm.backendErrorRateChart.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.backendInventory.dependencyTableColumn": "依存関係",
|
||||
"xpack.apm.backendLatencyChart.chartTitle": "レイテンシ",
|
||||
"xpack.apm.backendLatencyChart.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.backendThroughputChart.chartTitle": "スループット",
|
||||
"xpack.apm.backendThroughputChart.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.chart.annotation.version": "バージョン",
|
||||
"xpack.apm.chart.cpuSeries.processAverageLabel": "プロセス平均",
|
||||
"xpack.apm.chart.cpuSeries.processMaxLabel": "プロセス最大",
|
||||
|
@ -7293,7 +7290,6 @@
|
|||
"xpack.apm.chart.memorySeries.systemMaxLabel": "最高",
|
||||
"xpack.apm.coldstartRate": "コールドスタート率",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate": "コールドスタート率(平均)",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.compositeSpanCallsLabel": "、{count}件の呼び出し、平均{duration}",
|
||||
"xpack.apm.compositeSpanDurationLabel": "平均時間",
|
||||
"xpack.apm.correlations.cancelButtonTitle": "キャンセル",
|
||||
|
@ -7391,7 +7387,6 @@
|
|||
"xpack.apm.errorCountAlert.name": "エラー数しきい値",
|
||||
"xpack.apm.errorCountAlertTrigger.errors": " エラー",
|
||||
"xpack.apm.errorGroup.chart.ocurrences": "オカレンス",
|
||||
"xpack.apm.errorGroup.chart.ocurrences.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.errorGroupDetails.culpritLabel": "原因",
|
||||
"xpack.apm.errorGroupDetails.errorGroupTitle": "エラーグループ {errorGroupId}",
|
||||
"xpack.apm.errorGroupDetails.errorOccurrenceTitle": "エラーのオカレンス",
|
||||
|
@ -7403,7 +7398,6 @@
|
|||
"xpack.apm.errorGroupDetails.viewOccurrencesInDiscoverButtonLabel": "Discover で {occurrencesCount} {occurrencesCount, plural, other {件の発生}} を表示",
|
||||
"xpack.apm.errorRate": "失敗したトランザクション率",
|
||||
"xpack.apm.errorRate.chart.errorRate": "失敗したトランザクション率(平均)",
|
||||
"xpack.apm.errorRate.chart.errorRate.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.errorRate.tip": "選択したサービスの失敗したトランザクションの割合。4xxステータスコード(クライアントエラー)のHTTPサーバートランザクションは、サーバーではなく呼び出し側が失敗の原因であるため、失敗と見なされません。",
|
||||
"xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel": "エラーメッセージと原因",
|
||||
"xpack.apm.errorsTable.groupIdColumnDescription": "スタックトレースのハッシュ。動的パラメータのため、エラーメッセージが異なる場合でも、類似したエラーをグループ化します。",
|
||||
|
@ -7576,7 +7570,6 @@
|
|||
"xpack.apm.home.serviceMapTabLabel": "サービスマップ",
|
||||
"xpack.apm.inspectButtonText": "検査",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend": "インスタンス",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend.previousPeriod": "前の期間",
|
||||
"xpack.apm.instancesLatencyDistributionChartTitle": "インスタンスのレイテンシ分布",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipClickToFilterDescription": "クリックすると、インスタンスでフィルタリングします",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipInstancesTitle": "{instancesCount} {instancesCount, plural, other {個のインスタンス}}",
|
||||
|
@ -7821,14 +7814,12 @@
|
|||
"xpack.apm.serviceOverview.instanceTable.details.serviceTitle": "サービス",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle": "レイテンシ",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.prepend": "メトリック",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.serviceOverview.latencyColumnAvgLabel": "レイテンシ(平均)",
|
||||
"xpack.apm.serviceOverview.latencyColumnDefaultLabel": "レイテンシ",
|
||||
"xpack.apm.serviceOverview.latencyColumnP95Label": "レイテンシ(95 番目)",
|
||||
"xpack.apm.serviceOverview.latencyColumnP99Label": "レイテンシ(99 番目)",
|
||||
"xpack.apm.serviceOverview.loadingText": "読み込み中…",
|
||||
"xpack.apm.serviceOverview.noResultsText": "インスタンスが見つかりません",
|
||||
"xpack.apm.serviceOverview.throughtputChart.previousPeriodLabel": "前の期間",
|
||||
"xpack.apm.serviceOverview.throughtputChartTitle": "スループット",
|
||||
"xpack.apm.serviceOverview.tpmHelp": "スループットは1分あたりのトランザクション数(tpm)で測定されます。",
|
||||
"xpack.apm.serviceOverview.transactionsTableColumnErrorRate": "失敗したトランザクション率",
|
||||
|
|
|
@ -5461,10 +5461,10 @@
|
|||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.description": "尚未启用此集成。您的管理员具有打开它所需的权限。",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.noPermission.title": "请联系您的管理员",
|
||||
"sharedUXComponents.noDataPage.elasticAgentCard.title": "添加 Elastic 代理",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "希望了解详情?",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "阅读文档",
|
||||
"sharedUXComponents.pageTemplate.noDataCard.description": "继续,而不收集数据",
|
||||
"sharedUXComponents.toolbar.buttons.addFromLibrary.libraryButtonLabel": "从库中添加",
|
||||
"sharedUXPackages.noDataViewsPrompt.learnMore": "希望了解详情?",
|
||||
"sharedUXPackages.noDataViewsPrompt.readDocumentation": "阅读文档",
|
||||
"telemetry.callout.appliesSettingTitle": "对此设置的更改将应用到{allOfKibanaText} 且会自动保存。",
|
||||
"telemetry.callout.appliesSettingTitle.allOfKibanaText": "整个 Kibana",
|
||||
"telemetry.callout.clusterStatisticsDescription": "这是我们将收集的基本集群统计信息的示例。其包括索引、分片和节点的数目。还包括概括性的使用情况统计信息,例如监测是否打开。",
|
||||
|
@ -7294,12 +7294,9 @@
|
|||
"xpack.apm.backendDetailLatencyChartTitle": "延迟",
|
||||
"xpack.apm.backendDetailThroughputChartTitle": "吞吐量",
|
||||
"xpack.apm.backendErrorRateChart.chartTitle": "失败事务率",
|
||||
"xpack.apm.backendErrorRateChart.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.backendInventory.dependencyTableColumn": "依赖项",
|
||||
"xpack.apm.backendLatencyChart.chartTitle": "延迟",
|
||||
"xpack.apm.backendLatencyChart.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.backendThroughputChart.chartTitle": "吞吐量",
|
||||
"xpack.apm.backendThroughputChart.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.chart.annotation.version": "版本",
|
||||
"xpack.apm.chart.cpuSeries.processAverageLabel": "进程平均值",
|
||||
"xpack.apm.chart.cpuSeries.processMaxLabel": "进程最大值",
|
||||
|
@ -7310,7 +7307,6 @@
|
|||
"xpack.apm.chart.memorySeries.systemMaxLabel": "最大值",
|
||||
"xpack.apm.coldstartRate": "冷启动速率",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate": "冷启动速率(平均)",
|
||||
"xpack.apm.coldstartRate.chart.coldstartRate.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.compositeSpanCallsLabel": ",{count} 个调用,平均 {duration}",
|
||||
"xpack.apm.compositeSpanDurationLabel": "平均持续时间",
|
||||
"xpack.apm.correlations.cancelButtonTitle": "取消",
|
||||
|
@ -7408,7 +7404,6 @@
|
|||
"xpack.apm.errorCountAlert.name": "错误计数阈值",
|
||||
"xpack.apm.errorCountAlertTrigger.errors": " 错误",
|
||||
"xpack.apm.errorGroup.chart.ocurrences": "发生次数",
|
||||
"xpack.apm.errorGroup.chart.ocurrences.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.errorGroupDetails.culpritLabel": "原因",
|
||||
"xpack.apm.errorGroupDetails.errorGroupTitle": "错误组 {errorGroupId}",
|
||||
"xpack.apm.errorGroupDetails.errorOccurrenceTitle": "错误发生",
|
||||
|
@ -7420,7 +7415,6 @@
|
|||
"xpack.apm.errorGroupDetails.viewOccurrencesInDiscoverButtonLabel": "在 Discover 中查看 {occurrencesCount} 次{occurrencesCount, plural, other {发生}}",
|
||||
"xpack.apm.errorRate": "失败事务率",
|
||||
"xpack.apm.errorRate.chart.errorRate": "失败事务率(平均值)",
|
||||
"xpack.apm.errorRate.chart.errorRate.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.errorRate.tip": "选定服务的失败事务百分比。状态代码为 4xx 的 HTTP 服务器事务(客户端错误)不会视为失败,因为是调用方而不是服务器造成了失败。",
|
||||
"xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel": "错误消息和原因",
|
||||
"xpack.apm.errorsTable.groupIdColumnDescription": "堆栈跟踪的哈希。将类似错误分组在一起,即使因动态参数造成错误消息不同。",
|
||||
|
@ -7593,7 +7587,6 @@
|
|||
"xpack.apm.home.serviceMapTabLabel": "服务地图",
|
||||
"xpack.apm.inspectButtonText": "检查",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend": "实例",
|
||||
"xpack.apm.instancesLatencyDistributionChartLegend.previousPeriod": "上一时段",
|
||||
"xpack.apm.instancesLatencyDistributionChartTitle": "实例延迟分布",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipClickToFilterDescription": "单击按实例筛选",
|
||||
"xpack.apm.instancesLatencyDistributionChartTooltipInstancesTitle": "{instancesCount} 个{instancesCount, plural, other {实例}}",
|
||||
|
@ -7840,14 +7833,12 @@
|
|||
"xpack.apm.serviceOverview.instanceTable.details.serviceTitle": "服务",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle": "延迟",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.prepend": "指标",
|
||||
"xpack.apm.serviceOverview.latencyChartTitle.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.serviceOverview.latencyColumnAvgLabel": "延迟(平均值)",
|
||||
"xpack.apm.serviceOverview.latencyColumnDefaultLabel": "延迟",
|
||||
"xpack.apm.serviceOverview.latencyColumnP95Label": "延迟(第 95 个)",
|
||||
"xpack.apm.serviceOverview.latencyColumnP99Label": "延迟(第 99 个)",
|
||||
"xpack.apm.serviceOverview.loadingText": "正在加载……",
|
||||
"xpack.apm.serviceOverview.noResultsText": "未找到实例",
|
||||
"xpack.apm.serviceOverview.throughtputChart.previousPeriodLabel": "上一时段",
|
||||
"xpack.apm.serviceOverview.throughtputChartTitle": "吞吐量",
|
||||
"xpack.apm.serviceOverview.tpmHelp": "吞吐量按每分钟事务数 (tpm) 来度量。",
|
||||
"xpack.apm.serviceOverview.transactionsTableColumnErrorRate": "失败事务率",
|
||||
|
|
|
@ -10,6 +10,7 @@ import { range, omit } from 'lodash';
|
|||
import { apm, timerange } from '@elastic/apm-synthtrace';
|
||||
import { ServiceAnomalyTimeseries } from '@kbn/apm-plugin/common/anomaly_detection/service_anomaly_timeseries';
|
||||
import { ApmMlDetectorType } from '@kbn/apm-plugin/common/anomaly_detection/apm_ml_detectors';
|
||||
import { Environment } from '@kbn/apm-plugin/common/environment_rt';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { ApmApiError } from '../../common/apm_api_supertest';
|
||||
import { createAndRunApmMlJob } from '../../common/utils/create_and_run_apm_ml_job';
|
||||
|
@ -40,11 +41,13 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
end,
|
||||
transactionType,
|
||||
serviceName,
|
||||
environment,
|
||||
}: {
|
||||
start: string;
|
||||
end: string;
|
||||
transactionType: string;
|
||||
serviceName: string;
|
||||
environment: Environment;
|
||||
},
|
||||
user = apmApiClient.readUser
|
||||
) {
|
||||
|
@ -58,6 +61,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
start,
|
||||
end,
|
||||
transactionType,
|
||||
environment,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -74,6 +78,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
transactionType: 'request',
|
||||
start: '2021-01-01T00:00:00.000Z',
|
||||
end: '2021-01-01T00:15:00.000Z',
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -141,6 +146,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
transactionType: 'request',
|
||||
start,
|
||||
end,
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
},
|
||||
apmApiClient.noMlAccessUser
|
||||
)
|
||||
|
@ -156,6 +162,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
transactionType: 'request',
|
||||
start,
|
||||
end,
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -182,6 +189,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
transactionType: 'request',
|
||||
start,
|
||||
end,
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -202,6 +210,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
transactionType: 'request',
|
||||
start,
|
||||
end,
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
})
|
||||
).body.allAnomalyTimeseries;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue