Skip to content

Commit

Permalink
Merge branch 'master' into ml-migrate-router
Browse files Browse the repository at this point in the history
  • Loading branch information
walterra committed Jul 29, 2020
2 parents 5cfa29a + dd605c4 commit 7c43179
Show file tree
Hide file tree
Showing 44 changed files with 406 additions and 269 deletions.
18 changes: 0 additions & 18 deletions docs/apm/error-reports-watcher.asciidoc

This file was deleted.

3 changes: 0 additions & 3 deletions docs/apm/how-to-guides.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Learn how to perform common APM app tasks.
* <<agent-configuration>>
* <<apm-alerts>>
* <<custom-links>>
* <<errors-alerts-with-watcher>>
* <<filters>>
* <<machine-learning-integration>>
* <<advanced-queries>>
Expand All @@ -21,8 +20,6 @@ include::apm-alerts.asciidoc[]

include::custom-links.asciidoc[]

include::error-reports-watcher.asciidoc[]

include::filters.asciidoc[]

include::machine-learning.asciidoc[]
Expand Down
10 changes: 10 additions & 0 deletions docs/redirects.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ This page was deleted. See <<development-visualize-index>>.
== Developing Visualizations

This page was deleted. See <<development-visualize-index>>.

[role="exclude",id="errors-alerts-with-watcher"]
== Error reports with Watcher

deprecated::[7.9.0]

Watcher error reports have been removed and replaced with Kibana's <<apm-alerts,alerting and actions>> feature.
To create error alerts with new tool, select **Alerts** - **Create threshold alert** - **Error rate**.

More information on this new feature is available in <<apm-alerts>>.
77 changes: 69 additions & 8 deletions x-pack/plugins/infra/server/lib/alerting/common/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export const stateToAlertMessage = {
}),
};

const toNumber = (value: number | string) =>
typeof value === 'string' ? parseFloat(value) : value;

const comparatorToI18n = (comparator: Comparator, threshold: number[], currentValue: number) => {
const gtText = i18n.translate('xpack.infra.metrics.alerting.threshold.gtComparator', {
defaultMessage: 'greater than',
Expand All @@ -54,10 +57,11 @@ const comparatorToI18n = (comparator: Comparator, threshold: number[], currentVa
case Comparator.LT:
return ltText;
case Comparator.GT_OR_EQ:
case Comparator.LT_OR_EQ:
case Comparator.LT_OR_EQ: {
if (threshold[0] === currentValue) return eqText;
else if (threshold[0] < currentValue) return ltText;
return gtText;
}
}
};

Expand Down Expand Up @@ -88,7 +92,7 @@ const recoveredComparatorToI18n = (
}
};

const thresholdToI18n = ([a, b]: number[]) => {
const thresholdToI18n = ([a, b]: Array<number | string>) => {
if (typeof b === 'undefined') return a;
return i18n.translate('xpack.infra.metrics.alerting.threshold.thresholdRange', {
defaultMessage: '{a} and {b}',
Expand All @@ -99,15 +103,15 @@ const thresholdToI18n = ([a, b]: number[]) => {
export const buildFiredAlertReason: (alertResult: {
metric: string;
comparator: Comparator;
threshold: number[];
currentValue: number;
threshold: Array<number | string>;
currentValue: number | string;
}) => string = ({ metric, comparator, threshold, currentValue }) =>
i18n.translate('xpack.infra.metrics.alerting.threshold.firedAlertReason', {
defaultMessage:
'{metric} is {comparator} a threshold of {threshold} (current value is {currentValue})',
values: {
metric,
comparator: comparatorToI18n(comparator, threshold, currentValue),
comparator: comparatorToI18n(comparator, threshold.map(toNumber), toNumber(currentValue)),
threshold: thresholdToI18n(threshold),
currentValue,
},
Expand All @@ -116,15 +120,19 @@ export const buildFiredAlertReason: (alertResult: {
export const buildRecoveredAlertReason: (alertResult: {
metric: string;
comparator: Comparator;
threshold: number[];
currentValue: number;
threshold: Array<number | string>;
currentValue: number | string;
}) => string = ({ metric, comparator, threshold, currentValue }) =>
i18n.translate('xpack.infra.metrics.alerting.threshold.recoveredAlertReason', {
defaultMessage:
'{metric} is now {comparator} a threshold of {threshold} (current value is {currentValue})',
values: {
metric,
comparator: recoveredComparatorToI18n(comparator, threshold, currentValue),
comparator: recoveredComparatorToI18n(
comparator,
threshold.map(toNumber),
toNumber(currentValue)
),
threshold: thresholdToI18n(threshold),
currentValue,
},
Expand All @@ -150,3 +158,56 @@ export const buildErrorAlertReason = (metric: string) =>
metric,
},
});

export const groupActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.groupActionVariableDescription',
{
defaultMessage: 'Name of the group reporting data',
}
);

export const alertStateActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.alertStateActionVariableDescription',
{
defaultMessage: 'Current state of the alert',
}
);

export const reasonActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.reasonActionVariableDescription',
{
defaultMessage:
'A description of why the alert is in this state, including which metrics have crossed which thresholds',
}
);

export const timestampActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.timestampDescription',
{
defaultMessage: 'A timestamp of when the alert was detected.',
}
);

export const valueActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.valueActionVariableDescription',
{
defaultMessage:
'The value of the metric in the specified condition. Usage: (ctx.value.condition0, ctx.value.condition1, etc...).',
}
);

export const metricActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.metricActionVariableDescription',
{
defaultMessage:
'The metric name in the specified condition. Usage: (ctx.metric.condition0, ctx.metric.condition1, etc...).',
}
);

export const thresholdActionVariableDescription = i18n.translate(
'xpack.infra.metrics.alerting.thresholdActionVariableDescription',
{
defaultMessage:
'The threshold value of the metric for the specified condition. Usage: (ctx.threshold.condition0, ctx.threshold.condition1, etc...).',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ const getData = async (
try {
const { nodes } = await snapshot.getNodes(esClient, options);

if (!nodes.length) return { [UNGROUPED_FACTORY_KEY]: null }; // No Data state

return nodes.reduce((acc, n) => {
const nodePathItem = last(n.path) as any;
const m = first(n.metrics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
const resultWithVerboseMetricName = {
...result[item],
metric: toMetricOpt(result[item].metric)?.text || result[item].metric,
currentValue: formatMetric(result[item].metric, result[item].currentValue),
};
return buildFiredAlertReason(resultWithVerboseMetricName);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { schema } from '@kbn/config-schema';
import {
createInventoryMetricThresholdExecutor,
Expand All @@ -12,6 +11,15 @@ import {
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types';
import { InfraBackendLibs } from '../../infra_types';
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
import {
groupActionVariableDescription,
alertStateActionVariableDescription,
reasonActionVariableDescription,
timestampActionVariableDescription,
valueActionVariableDescription,
metricActionVariableDescription,
thresholdActionVariableDescription,
} from '../common/messages';

const condition = schema.object({
threshold: schema.arrayOf(schema.number()),
Expand Down Expand Up @@ -44,45 +52,13 @@ export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs
executor: createInventoryMetricThresholdExecutor(libs),
actionVariables: {
context: [
{
name: 'group',
description: i18n.translate(
'xpack.infra.metrics.alerting.threshold.alerting.groupActionVariableDescription',
{
defaultMessage: 'Name of the group reporting data',
}
),
},
{
name: 'valueOf',
description: i18n.translate(
'xpack.infra.metrics.alerting.threshold.alerting.valueOfActionVariableDescription',
{
defaultMessage:
'Record of the current value of the watched metric; grouped by condition, i.e valueOf.condition0, valueOf.condition1, etc.',
}
),
},
{
name: 'thresholdOf',
description: i18n.translate(
'xpack.infra.metrics.alerting.threshold.alerting.thresholdOfActionVariableDescription',
{
defaultMessage:
'Record of the alerting threshold; grouped by condition, i.e thresholdOf.condition0, thresholdOf.condition1, etc.',
}
),
},
{
name: 'metricOf',
description: i18n.translate(
'xpack.infra.metrics.alerting.threshold.alerting.metricOfActionVariableDescription',
{
defaultMessage:
'Record of the watched metric; grouped by condition, i.e metricOf.condition0, metricOf.condition1, etc.',
}
),
},
{ name: 'group', description: groupActionVariableDescription },
{ name: 'alertState', description: alertStateActionVariableDescription },
{ name: 'reason', description: reasonActionVariableDescription },
{ name: 'timestamp', description: timestampActionVariableDescription },
{ name: 'value', description: valueActionVariableDescription },
{ name: 'metric', description: metricActionVariableDescription },
{ name: 'threshold', description: thresholdActionVariableDescription },
],
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ export const evaluateAlert = (
currentValue: Array.isArray(points) ? last(points)?.value : NaN,
timestamp: Array.isArray(points) ? last(points)?.key : NaN,
shouldFire: Array.isArray(points)
? points.map((point) => comparisonFunction(point.value, threshold))
? points.map(
(point) =>
typeof point.value === 'number' && comparisonFunction(point.value, threshold)
)
: [false],
isNoData: points === null,
isError: isNaN(points),
isNoData: (Array.isArray(points) ? last(points)?.value : points) === null,
isError: isNaN(Array.isArray(points) ? last(points)?.value : points),
};
});
})
Expand Down Expand Up @@ -172,7 +175,7 @@ const getValuesFromAggregations = (
}
return buckets.map((bucket) => ({
key: bucket.key_as_string,
value: bucket.aggregatedValue.value,
value: bucket.aggregatedValue?.value ?? null,
}));
} catch (e) {
return NaN; // Error state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,31 @@ describe('The metric threshold alert type', () => {
});
});

describe("querying a rate-aggregated metric that hasn't reported data", () => {
const instanceID = '*';
const execute = () =>
executor({
services,
params: {
criteria: [
{
...baseCriterion,
comparator: Comparator.GT,
threshold: 1,
metric: 'test.metric.3',
aggType: 'rate',
},
],
alertOnNoData: true,
},
});
test('sends a No Data alert', async () => {
await execute();
expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id);
expect(getState(instanceID).alertState).toBe(AlertStates.NO_DATA);
});
});

// describe('querying a metric that later recovers', () => {
// const instanceID = '*';
// const execute = (threshold: number[]) =>
Expand Down Expand Up @@ -401,7 +426,9 @@ services.callCluster.mockImplementation(async (_: string, { body, index }: any)
if (metric === 'test.metric.2') {
return mocks.alternateMetricResponse;
} else if (metric === 'test.metric.3') {
return mocks.emptyMetricResponse;
return body.aggs.aggregatedIntervals.aggregations.aggregatedValue_max
? mocks.emptyRateResponse
: mocks.emptyMetricResponse;
}
return mocks.basicMetricResponse;
});
Expand Down
Loading

0 comments on commit 7c43179

Please sign in to comment.