diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/alert_details_app_section.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/alert_details_app_section.tsx
index 92cd229333062..3bf792840ab71 100644
--- a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/alert_details_app_section.tsx
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/alert_details_app_section.tsx
@@ -12,9 +12,13 @@ import { i18n } from '@kbn/i18n';
import { EuiPanel } from '@elastic/eui';
import { EuiTitle } from '@elastic/eui';
import { EuiIconTip } from '@elastic/eui';
-import { ALERT_DURATION, ALERT_END } from '@kbn/rule-data-utils';
+import {
+ ALERT_DURATION,
+ ALERT_END,
+ ALERT_EVALUATION_THRESHOLD,
+ ALERT_RULE_TYPE_ID,
+} from '@kbn/rule-data-utils';
import moment from 'moment';
-import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values';
import { getTransactionType } from '../../../../context/apm_service/apm_service_context';
import { useServiceAgentFetcher } from '../../../../context/apm_service/use_service_agent_fetcher';
import { useServiceTransactionTypesFetcher } from '../../../../context/apm_service/use_service_transaction_types_fetcher';
@@ -41,9 +45,16 @@ import {
SERVICE_NAME,
TRANSACTION_TYPE,
} from './types';
-import { getAggsTypeFromRule } from './helpers';
+import { getAggsTypeFromRule, isLatencyThresholdRuleType } from './helpers';
import { filterNil } from '../../../shared/charts/latency_chart';
import { errorRateI18n } from '../../../shared/charts/failed_transaction_rate_chart';
+import {
+ AlertActiveRect,
+ AlertAnnotation,
+ AlertThresholdRect,
+ AlertThresholdAnnotation,
+} from './latency_chart_components';
+import { SERVICE_ENVIRONMENT } from '../../../../../common/es_fields/apm';
export function AlertDetailsAppSection({
rule,
@@ -51,10 +62,8 @@ export function AlertDetailsAppSection({
timeZone,
}: AlertDetailsAppSectionProps) {
const params = rule.params;
- const environment = String(params.environment) || ENVIRONMENT_ALL.value;
- const latencyAggregationType = getAggsTypeFromRule(
- params.aggregationType as string
- );
+ const environment = alert.fields[SERVICE_ENVIRONMENT];
+ const latencyAggregationType = getAggsTypeFromRule(params.aggregationType);
// duration is us, convert it to MS
const alertDurationMS = alert.fields[ALERT_DURATION]! / 1000;
@@ -103,7 +112,7 @@ export function AlertDetailsAppSection({
});
const transactionType = getTransactionType({
- transactionType: String(alert.fields[TRANSACTION_TYPE]),
+ transactionType: alert.fields[TRANSACTION_TYPE],
transactionTypes,
agentName,
});
@@ -289,9 +298,32 @@ export function AlertDetailsAppSection({
}),
},
];
-
/* Error Rate */
+ const getLatencyChartAdditionalData = () => {
+ if (isLatencyThresholdRuleType(alert.fields[ALERT_RULE_TYPE_ID])) {
+ return [
+ ,
+ ,
+ ,
+ ,
+ ];
+ }
+ };
+
return (
@@ -313,6 +345,7 @@ export function AlertDetailsAppSection({
+ ruleTypeId === 'apm.transaction_duration';
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_active_rect.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_active_rect.tsx
new file mode 100644
index 0000000000000..ff6d76165c1fa
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_active_rect.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 { RectAnnotation } from '@elastic/charts';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+
+export function AlertActiveRect({ alertStarted }: { alertStarted: number }) {
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_annotation.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_annotation.tsx
new file mode 100644
index 0000000000000..27354ea2ac3b8
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_annotation.tsx
@@ -0,0 +1,47 @@
+/*
+ * 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 React from 'react';
+import {
+ AnnotationDomainType,
+ LineAnnotation,
+ Position,
+} from '@elastic/charts';
+import moment from 'moment';
+import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { DEFAULT_DATE_FORMAT } from '../constants';
+
+export function AlertAnnotation({ alertStarted }: { alertStarted: number }) {
+ return (
+ }
+ markerPosition={Position.Top}
+ />
+ );
+}
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_annotation.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_annotation.tsx
new file mode 100644
index 0000000000000..c1c6ddefd32f1
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_annotation.tsx
@@ -0,0 +1,37 @@
+/*
+ * 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 React from 'react';
+import { AnnotationDomainType, LineAnnotation } from '@elastic/charts';
+
+export function AlertThresholdAnnotation({
+ threshold,
+}: {
+ threshold?: number;
+}) {
+ if (!threshold) return <>>;
+
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_rect.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_rect.tsx
new file mode 100644
index 0000000000000..24897dce1f63c
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/alert_threshold_rect.tsx
@@ -0,0 +1,39 @@
+/*
+ * 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 { RectAnnotation } from '@elastic/charts';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+
+export function AlertThresholdRect({
+ threshold,
+ alertStarted,
+}: {
+ threshold?: number;
+ alertStarted: number;
+}) {
+ if (!threshold) return <>>;
+
+ return (
+
+ );
+}
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/index.ts b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/index.ts
new file mode 100644
index 0000000000000..a5d53b0ee3766
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/latency_chart_components/index.ts
@@ -0,0 +1,11 @@
+/*
+ * 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.
+ */
+
+export { AlertAnnotation } from './alert_annotation';
+export { AlertThresholdRect } from './alert_threshold_rect';
+export { AlertActiveRect } from './alert_active_rect';
+export { AlertThresholdAnnotation } from './alert_threshold_annotation';
diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/types.ts b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/types.ts
index 0094d9332009a..99fafb00bcac0 100644
--- a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/types.ts
+++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/types.ts
@@ -8,17 +8,21 @@
import { Rule } from '@kbn/alerting-plugin/common';
import { TopAlert } from '@kbn/observability-plugin/public/pages/alerts';
import { TIME_UNITS } from '@kbn/triggers-actions-ui-plugin/public';
-import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
+import { SERVICE_ENVIRONMENT } from '../../../../../common/es_fields/apm';
export const SERVICE_NAME = 'service.name' as const;
export const TRANSACTION_TYPE = 'transaction.type' as const;
export interface AlertDetailsAppSectionProps {
rule: Rule<{
environment: string;
- aggregationType: LatencyAggregationType;
+ aggregationType: string;
windowSize: number;
windowUnit: TIME_UNITS;
}>;
- alert: TopAlert<{ [SERVICE_NAME]: string; [TRANSACTION_TYPE]: string }>;
+ alert: TopAlert<{
+ [SERVICE_NAME]: string;
+ [TRANSACTION_TYPE]: string;
+ [SERVICE_ENVIRONMENT]: string;
+ }>;
timeZone: string;
}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
index 59d52658682d5..6f5bf5819e240 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
@@ -6,7 +6,6 @@
*/
import {
- AnnotationDomainType,
AreaSeries,
Axis,
BarSeries,
@@ -26,12 +25,11 @@ import {
} from '@elastic/charts';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import React from 'react';
+import React, { ReactElement } from 'react';
import { useHistory } from 'react-router-dom';
import { useChartTheme } from '@kbn/observability-plugin/public';
import { isExpectedBoundsComparison } from '../time_comparison/get_comparison_options';
-import { asAbsoluteDateTime } from '../../../../common/utils/formatters';
-import { useAnnotationsContext } from '../../../context/annotations/use_annotations_context';
+
import { useChartPointerEventContext } from '../../../context/chart_pointer_event/use_chart_pointer_event_context';
import { useTheme } from '../../../hooks/use_theme';
import { unit } from '../../../utils/style';
@@ -51,6 +49,9 @@ interface TimeseriesChartProps extends TimeseriesChartWithContextProps {
comparisonEnabled: boolean;
offset?: string;
timeZone: string;
+ annotations?: Array<
+ ReactElement
+ >;
}
export function TimeseriesChart({
id,
@@ -67,9 +68,9 @@ export function TimeseriesChart({
comparisonEnabled,
offset,
timeZone,
+ annotations,
}: TimeseriesChartProps) {
const history = useHistory();
- const { annotations } = useAnnotationsContext();
const { chartRef, updatePointerEvent } = useChartPointerEventContext();
const theme = useTheme();
const chartTheme = useChartTheme();
@@ -79,7 +80,6 @@ export function TimeseriesChart({
anomalyTimeseriesColor: anomalyTimeseries?.color,
});
const isEmpty = isTimeseriesEmpty(timeseries);
- const annotationColor = theme.eui.euiColorSuccess;
const isComparingExpectedBounds =
comparisonEnabled && isExpectedBoundsComparison(offset);
const allSeries = [
@@ -219,26 +219,7 @@ export function TimeseriesChart({
tickFormat={yTickFormat ? yTickFormat : yLabelFormat}
labelFormat={yLabelFormat}
/>
-
- {showAnnotations && (
- ({
- dataValue: annotation['@timestamp'],
- header: asAbsoluteDateTime(annotation['@timestamp']),
- details: `${i18n.translate('xpack.apm.chart.annotation.version', {
- defaultMessage: 'Version',
- })} ${annotation.text}`,
- }))}
- style={{
- line: { strokeWidth: 1, stroke: annotationColor, opacity: 1 },
- }}
- marker={}
- markerPosition={Position.Top}
- />
- )}
-
+ {showAnnotations && annotations}
-
{allSeries.map((serie) => {
const Series = getChartType(serie.type);
diff --git a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart_with_context.tsx b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart_with_context.tsx
index 5c9aac5d28bdf..101fe2b9c8967 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart_with_context.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart_with_context.tsx
@@ -5,8 +5,18 @@
* 2.0.
*/
-import { LegendItemListener, YDomainRange } from '@elastic/charts';
+import {
+ AnnotationDomainType,
+ LegendItemListener,
+ LineAnnotation,
+ Position,
+ YDomainRange,
+} from '@elastic/charts';
import React from 'react';
+import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { asAbsoluteDateTime } from '../../../../common/utils/formatters';
+import { useAnnotationsContext } from '../../../context/annotations/use_annotations_context';
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
import { ServiceAnomalyTimeseries } from '../../../../common/anomaly_detection/service_anomaly_timeseries';
import { Coordinate, TimeSeries } from '../../../../typings/timeseries';
@@ -15,6 +25,7 @@ import { FETCH_STATUS } from '../../../hooks/use_fetcher';
import { unit } from '../../../utils/style';
import { getTimeZone } from './helper/timezone';
import { TimeseriesChart } from './timeseries_chart';
+import { useTheme } from '../../../hooks/use_theme';
interface AnomalyTimeseries extends ServiceAnomalyTimeseries {
color?: string;
@@ -62,7 +73,28 @@ export function TimeseriesChartWithContext({
);
const { core } = useApmPluginContext();
const timeZone = getTimeZone(core.uiSettings);
+ const theme = useTheme();
+ const annotationColor = theme.eui.euiColorSuccess;
+ const { annotations } = useAnnotationsContext();
+ const getAnnotations = () => (
+ ({
+ dataValue: annotation['@timestamp'],
+ header: asAbsoluteDateTime(annotation['@timestamp']),
+ details: `${i18n.translate('xpack.apm.chart.annotation.version', {
+ defaultMessage: 'Version',
+ })} ${annotation.text}`,
+ }))}
+ style={{
+ line: { strokeWidth: 1, stroke: annotationColor, opacity: 1 },
+ }}
+ marker={}
+ markerPosition={Position.Top}
+ />
+ );
return (