mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[RAC][Uptime] Status check reason messages (#123189)
* testing out * update getStatusMessage * format interval * temp: keep only statusMessage for now * update translation message * availability check message (previous below threshold) * add availability interval * availability & status check message * i18n check * fix failing tests * fix failing tests * more failing tests * finalize reason format and continue with fixing failing tests * fix more failing tests * fix monitor_status tests * fix uptime functional tests * fix more failing tests * clean up unused stuff * fix failing tests * fix failing tests * more failing tests (pfff) * fix failing tests * move all status check translations in the translations file * a bit of refactoring * temp * rename monitor params to monitor status message params * remove unused PingType * refactoring: move getInterval to another file and create getMonitorDownStatusMessageParams * separate alerts table reason message from alert message in the rule flyout * bring back old alert message format that is used in rule flyout * fix failing tests * remove unused file * refactor status message so that an extra dot does not appear on alert connector message Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c3866c4032
commit
09aac9e42d
12 changed files with 218 additions and 104 deletions
|
@ -27162,11 +27162,8 @@
|
|||
"xpack.uptime.alerts.durationAnomaly.description": "アップタイム監視期間が異常なときにアラートを発行します。",
|
||||
"xpack.uptime.alerts.monitorExpression.label": "フィルター{title}を削除",
|
||||
"xpack.uptime.alerts.monitorStatus": "稼働状況の監視ステータス",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.availabilityMessage": "{availabilityRatio}%のしきい値を下回ります。想定される可用性は{expectedAvailability}%です",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description": "アラートによって「ダウン」と検知された一部またはすべてのモニターを示す、生成された概要。",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description": "現在ダウンしているモニターを要約する生成されたメッセージ。",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.down": "ダウン",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.downAndAvailabilityMessage": "{statusMessage}と{availabilityMessage}",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.currentTriggerStarted": "アラートがトリガーされた場合、現在のトリガー状態が開始するときを示すタイムスタンプ",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.firstCheckedAt": "このアラートが最初に確認されるときを示すタイムスタンプ",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.firstTriggeredAt": "このアラートが最初にトリガーされたときを示すタイムスタンプ",
|
||||
|
@ -27199,7 +27196,6 @@
|
|||
"xpack.uptime.alerts.monitorStatus.availability.unit.headline": "時間範囲単位を選択します",
|
||||
"xpack.uptime.alerts.monitorStatus.availability.unit.selectable": "この選択を使用して、このアラートの可用性範囲単位を設定",
|
||||
"xpack.uptime.alerts.monitorStatus.clientName": "稼働状況の監視ステータス",
|
||||
"xpack.uptime.alerts.monitorStatus.defaultActionMessage": "URL {monitorUrl}のモニター{monitorName}は{observerLocation}から{statusMessage}です。最新のエラーメッセージは{latestErrorMessage}です",
|
||||
"xpack.uptime.alerts.monitorStatus.description": "監視が停止しているか、可用性しきい値に違反したときにアラートを発行します。",
|
||||
"xpack.uptime.alerts.monitorStatus.filterBar.ariaLabel": "監視状態アラートのフィルター基準を許可するインプット",
|
||||
"xpack.uptime.alerts.monitorStatus.filters.anyLocation": "任意の場所",
|
||||
|
|
|
@ -27632,11 +27632,8 @@
|
|||
"xpack.uptime.alerts.durationAnomaly.description": "运行时间监测持续时间异常时告警。",
|
||||
"xpack.uptime.alerts.monitorExpression.label": "移除筛选 {title}",
|
||||
"xpack.uptime.alerts.monitorStatus": "运行时间监测状态",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.availabilityMessage": "低于阈值,{availabilityRatio}% 可用性应为 {expectedAvailability}%",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description": "生成的摘要,显示告警已检测为“关闭”的部分或所有监测",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description": "生成的消息,汇总当前关闭的监测",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.down": "关闭",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.downAndAvailabilityMessage": "{statusMessage} 以及 {availabilityMessage}",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.currentTriggerStarted": "表示告警触发时当前触发状况开始的时间戳",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.firstCheckedAt": "表示此告警首次检查的时间戳",
|
||||
"xpack.uptime.alerts.monitorStatus.actionVariables.state.firstTriggeredAt": "表示告警首次触发的时间戳",
|
||||
|
@ -27669,7 +27666,6 @@
|
|||
"xpack.uptime.alerts.monitorStatus.availability.unit.headline": "选择时间范围单位",
|
||||
"xpack.uptime.alerts.monitorStatus.availability.unit.selectable": "使用此选择来设置此告警的可用性范围单位",
|
||||
"xpack.uptime.alerts.monitorStatus.clientName": "运行时间监测状态",
|
||||
"xpack.uptime.alerts.monitorStatus.defaultActionMessage": "在 {observerLocation},URL 为 {monitorUrl} 的监测 {monitorName} 是 {statusMessage}。最新错误消息是 {latestErrorMessage}",
|
||||
"xpack.uptime.alerts.monitorStatus.description": "监测关闭或超出可用性阈值时告警。",
|
||||
"xpack.uptime.alerts.monitorStatus.filterBar.ariaLabel": "允许对监测状态告警使用筛选条件的输入",
|
||||
"xpack.uptime.alerts.monitorStatus.filters.anyLocation": "任意位置",
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const StatusCheckFiltersType = t.type({
|
||||
'monitor.type': t.array(t.string),
|
||||
'observer.geo.name': t.array(t.string),
|
||||
|
|
|
@ -21,11 +21,11 @@ export const VALUE_MUST_BE_AN_INTEGER = i18n.translate('xpack.uptime.settings.in
|
|||
export const MonitorStatusTranslations = {
|
||||
defaultActionMessage: i18n.translate('xpack.uptime.alerts.monitorStatus.defaultActionMessage', {
|
||||
defaultMessage:
|
||||
'Monitor {monitorName} with url {monitorUrl} is {statusMessage} from {observerLocation}. The latest error message is {latestErrorMessage}',
|
||||
'Monitor {monitorName} with url {monitorUrl} from {observerLocation} {statusMessage}. The latest error message is {latestErrorMessage}',
|
||||
values: {
|
||||
monitorName: '{{state.monitorName}}',
|
||||
monitorUrl: '{{{state.monitorUrl}}}',
|
||||
statusMessage: '{{state.statusMessage}}',
|
||||
statusMessage: '{{{state.statusMessage}}}',
|
||||
latestErrorMessage: '{{{state.latestErrorMessage}}}',
|
||||
observerLocation: '{{state.observerLocation}}',
|
||||
},
|
||||
|
|
|
@ -202,7 +202,7 @@ describe('monitor status alert type', () => {
|
|||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"defaultActionMessage": "Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}",
|
||||
"defaultActionMessage": "Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}",
|
||||
"description": "Alert when a monitor is down or an availability threshold is breached.",
|
||||
"documentationUrl": [Function],
|
||||
"format": [Function],
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('Alert Actions factory', () => {
|
|||
eventAction: 'trigger',
|
||||
severity: 'error',
|
||||
summary:
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
},
|
||||
id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9',
|
||||
},
|
||||
|
@ -75,7 +75,7 @@ describe('Alert Actions factory', () => {
|
|||
eventAction: 'trigger',
|
||||
severity: 'error',
|
||||
summary:
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
@ -93,7 +93,7 @@ describe('Alert Actions factory', () => {
|
|||
eventAction: 'trigger',
|
||||
severity: 'error',
|
||||
summary:
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
},
|
||||
id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9',
|
||||
},
|
||||
|
@ -118,7 +118,7 @@ describe('Alert Actions factory', () => {
|
|||
eventAction: 'trigger',
|
||||
severity: 'error',
|
||||
summary:
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -130,7 +130,7 @@ function getIndexActionParams(selectedMonitor: Ping, recovery = false): IndexAct
|
|||
{
|
||||
monitorName: '{{state.monitorName}}',
|
||||
monitorUrl: '{{{state.monitorUrl}}}',
|
||||
statusMessage: '{{state.statusMessage}}',
|
||||
statusMessage: '{{{state.statusMessage}}}',
|
||||
latestErrorMessage: '{{{state.latestErrorMessage}}}',
|
||||
observerLocation: '{{state.observerLocation}}',
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ const mockMonitors = [
|
|||
monitorInfo: {
|
||||
...makePing({
|
||||
id: 'first',
|
||||
name: 'First',
|
||||
location: 'harrisburg',
|
||||
url: 'localhost:8080',
|
||||
}),
|
||||
|
@ -44,6 +45,7 @@ const mockMonitors = [
|
|||
monitorInfo: {
|
||||
...makePing({
|
||||
id: 'first',
|
||||
name: 'First',
|
||||
location: 'fairbanks',
|
||||
url: 'localhost:5601',
|
||||
}),
|
||||
|
@ -66,15 +68,16 @@ const mockCommonAlertDocumentFields = (monitorInfo: GetMonitorStatusResult['moni
|
|||
|
||||
const mockStatusAlertDocument = (
|
||||
monitor: GetMonitorStatusResult,
|
||||
isAutoGenerated: boolean = false
|
||||
isAutoGenerated: boolean = false,
|
||||
count: number,
|
||||
interval: string,
|
||||
numTimes: number
|
||||
) => {
|
||||
const { monitorInfo } = monitor;
|
||||
return {
|
||||
fields: {
|
||||
...mockCommonAlertDocumentFields(monitor.monitorInfo),
|
||||
[ALERT_REASON]: `Monitor first with url ${monitorInfo?.url?.full} is down from ${
|
||||
monitorInfo.observer?.geo?.name
|
||||
}. The latest error message is ${monitorInfo.error?.message || ''}`,
|
||||
[ALERT_REASON]: `First from ${monitor.monitorInfo.observer?.geo?.name} failed ${count} times in the last ${interval}. Alert when > ${numTimes}.`,
|
||||
},
|
||||
id: getInstanceId(
|
||||
monitorInfo,
|
||||
|
@ -88,13 +91,11 @@ const mockAvailabilityAlertDocument = (monitor: GetMonitorAvailabilityResult) =>
|
|||
return {
|
||||
fields: {
|
||||
...mockCommonAlertDocumentFields(monitor.monitorInfo),
|
||||
[ALERT_REASON]: `Monitor ${monitorInfo.monitor.name || monitorInfo.monitor.id} with url ${
|
||||
monitorInfo?.url?.full
|
||||
} is below threshold with ${(monitor.availabilityRatio! * 100).toFixed(
|
||||
2
|
||||
)}% availability expected is 99.34% from ${
|
||||
[ALERT_REASON]: `${monitorInfo.monitor.name || monitorInfo.monitor.id} from ${
|
||||
monitorInfo.observer?.geo?.name
|
||||
}. The latest error message is ${monitorInfo.error?.message || ''}`,
|
||||
} 35 days availability is ${(monitor.availabilityRatio! * 100).toFixed(
|
||||
2
|
||||
)}%. Alert when < 99.34%.`,
|
||||
},
|
||||
id: getInstanceId(monitorInfo, `${monitorInfo?.monitor.id}-${monitorInfo.observer?.geo?.name}`),
|
||||
};
|
||||
|
@ -183,7 +184,12 @@ describe('status check alert', () => {
|
|||
mockGetter.mockReturnValue(mockMonitors);
|
||||
const { server, libs, plugins } = bootstrapDependencies({ getMonitorStatus: mockGetter });
|
||||
const alert = statusCheckAlertFactory(server, libs, plugins);
|
||||
const options = mockOptions();
|
||||
const options = mockOptions({
|
||||
numTimes: 5,
|
||||
count: 234,
|
||||
timerangeUnit: 'm',
|
||||
timerangeCount: 15,
|
||||
});
|
||||
const {
|
||||
services: { alertWithLifecycle },
|
||||
} = options;
|
||||
|
@ -192,7 +198,9 @@ describe('status check alert', () => {
|
|||
expect(mockGetter).toHaveBeenCalledTimes(1);
|
||||
expect(alertWithLifecycle).toHaveBeenCalledTimes(2);
|
||||
mockMonitors.forEach((monitor) => {
|
||||
expect(alertWithLifecycle).toBeCalledWith(mockStatusAlertDocument(monitor));
|
||||
expect(alertWithLifecycle).toBeCalledWith(
|
||||
mockStatusAlertDocument(monitor, false, 234, '15 mins', 5)
|
||||
);
|
||||
});
|
||||
expect(mockGetter.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
|
@ -219,13 +227,13 @@ describe('status check alert', () => {
|
|||
"lastTriggeredAt": "foo date string",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
"monitorName": "first",
|
||||
"monitorName": "First",
|
||||
"monitorType": "myType",
|
||||
"monitorUrl": "localhost:8080",
|
||||
"observerHostname": undefined,
|
||||
"observerLocation": "harrisburg",
|
||||
"reason": "Monitor first with url localhost:8080 is down from harrisburg. The latest error message is error message 1",
|
||||
"statusMessage": "down",
|
||||
"reason": "First from harrisburg failed 234 times in the last 15 mins. Alert when > 5.",
|
||||
"statusMessage": "failed 234 times in the last 15 mins. Alert when > 5.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -257,7 +265,9 @@ describe('status check alert', () => {
|
|||
expect(mockGetter).toHaveBeenCalledTimes(1);
|
||||
expect(alertWithLifecycle).toHaveBeenCalledTimes(2);
|
||||
mockMonitors.forEach((monitor) => {
|
||||
expect(alertWithLifecycle).toBeCalledWith(mockStatusAlertDocument(monitor, true));
|
||||
expect(alertWithLifecycle).toBeCalledWith(
|
||||
mockStatusAlertDocument(monitor, true, 234, '15m', 5)
|
||||
);
|
||||
});
|
||||
expect(mockGetter.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
|
@ -284,13 +294,13 @@ describe('status check alert', () => {
|
|||
"lastTriggeredAt": "foo date string",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
"monitorName": "first",
|
||||
"monitorName": "First",
|
||||
"monitorType": "myType",
|
||||
"monitorUrl": "localhost:8080",
|
||||
"observerHostname": undefined,
|
||||
"observerLocation": "harrisburg",
|
||||
"reason": "Monitor first with url localhost:8080 is down from harrisburg. The latest error message is error message 1",
|
||||
"statusMessage": "down",
|
||||
"reason": "First from harrisburg failed 234 times in the last 15m. Alert when > 5.",
|
||||
"statusMessage": "failed 234 times in the last 15m. Alert when > 5.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -314,7 +324,7 @@ describe('status check alert', () => {
|
|||
const alert = statusCheckAlertFactory(server, libs, plugins);
|
||||
const options = mockOptions({
|
||||
numTimes: 4,
|
||||
timespanRange: { from: 'now-14h', to: 'now' },
|
||||
timerange: { from: 'now-14h', to: 'now' },
|
||||
locations: ['fairbanks'],
|
||||
filters: '',
|
||||
});
|
||||
|
@ -325,7 +335,9 @@ describe('status check alert', () => {
|
|||
|
||||
const [{ value: alertInstanceMock }] = alertWithLifecycle.mock.results;
|
||||
mockMonitors.forEach((monitor) => {
|
||||
expect(alertWithLifecycle).toBeCalledWith(mockStatusAlertDocument(monitor));
|
||||
expect(alertWithLifecycle).toBeCalledWith(
|
||||
mockStatusAlertDocument(monitor, false, 234, '14h', 4)
|
||||
);
|
||||
});
|
||||
expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(2);
|
||||
expect(alertInstanceMock.replaceState.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
|
@ -340,13 +352,13 @@ describe('status check alert', () => {
|
|||
"lastTriggeredAt": "7.7 date",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
"monitorName": "first",
|
||||
"monitorName": "First",
|
||||
"monitorType": "myType",
|
||||
"monitorUrl": "localhost:8080",
|
||||
"observerHostname": undefined,
|
||||
"observerLocation": "harrisburg",
|
||||
"reason": "Monitor first with url localhost:8080 is down from harrisburg. The latest error message is error message 1",
|
||||
"statusMessage": "down",
|
||||
"reason": "First from harrisburg failed 234 times in the last 14h. Alert when > 4.",
|
||||
"statusMessage": "failed 234 times in the last 14h. Alert when > 4.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -392,7 +404,9 @@ describe('status check alert', () => {
|
|||
} = options;
|
||||
const [{ value: alertInstanceMock }] = alertWithLifecycle.mock.results;
|
||||
mockMonitors.forEach((monitor) => {
|
||||
expect(alertWithLifecycle).toBeCalledWith(mockStatusAlertDocument(monitor));
|
||||
expect(alertWithLifecycle).toBeCalledWith(
|
||||
mockStatusAlertDocument(monitor, false, 234, '15 mins', 3)
|
||||
);
|
||||
});
|
||||
expect(mockGetter).toHaveBeenCalledTimes(1);
|
||||
expect(mockGetter.mock.calls[0][0]).toEqual(
|
||||
|
@ -554,13 +568,13 @@ describe('status check alert', () => {
|
|||
"lastTriggeredAt": "foo date string",
|
||||
"latestErrorMessage": "error message 1",
|
||||
"monitorId": "first",
|
||||
"monitorName": "first",
|
||||
"monitorName": "First",
|
||||
"monitorType": "myType",
|
||||
"monitorUrl": "localhost:8080",
|
||||
"observerHostname": undefined,
|
||||
"observerLocation": "harrisburg",
|
||||
"reason": "Monitor first with url localhost:8080 is down from harrisburg. The latest error message is error message 1",
|
||||
"statusMessage": "down",
|
||||
"reason": "First from harrisburg failed 234 times in the last 15 mins. Alert when > 3.",
|
||||
"statusMessage": "failed 234 times in the last 15 mins. Alert when > 3.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -752,8 +766,8 @@ describe('status check alert', () => {
|
|||
"monitorUrl": "https://foo.com",
|
||||
"observerHostname": undefined,
|
||||
"observerLocation": "harrisburg",
|
||||
"reason": "Monitor Foo with url https://foo.com is below threshold with 99.28% availability expected is 99.34% from harrisburg. The latest error message is ",
|
||||
"statusMessage": "below threshold with 99.28% availability expected is 99.34%",
|
||||
"reason": "Foo from harrisburg 35 days availability is 99.28%. Alert when < 99.34%.",
|
||||
"statusMessage": "35 days availability is 99.28%. Alert when < 99.34%.",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -1281,15 +1295,18 @@ describe('status check alert', () => {
|
|||
describe('statusMessage', () => {
|
||||
it('creates message for down item', () => {
|
||||
expect(
|
||||
getStatusMessage(
|
||||
makePing({
|
||||
getStatusMessage({
|
||||
info: makePing({
|
||||
id: 'test-node-service',
|
||||
location: 'fairbanks',
|
||||
name: 'Test Node Service',
|
||||
url: 'http://localhost:12349',
|
||||
})
|
||||
)
|
||||
).toMatchInlineSnapshot(`"down"`);
|
||||
}),
|
||||
count: 235,
|
||||
numTimes: 10,
|
||||
interval: '30 days',
|
||||
})
|
||||
).toMatchInlineSnapshot(`"failed 235 times in the last 30 days. Alert when > 10."`);
|
||||
});
|
||||
|
||||
it('creates message for availability item', () => {
|
||||
|
@ -1315,18 +1332,23 @@ describe('status check alert', () => {
|
|||
rangeUnit: 'm',
|
||||
}
|
||||
)
|
||||
).toMatchInlineSnapshot(`"below threshold with 58.04% availability expected is 90%"`);
|
||||
).toMatchInlineSnapshot(`"5 mins availability is 58.04%. Alert when < 90%."`);
|
||||
});
|
||||
|
||||
it('creates message for down and availability item', () => {
|
||||
expect(
|
||||
getStatusMessage(
|
||||
makePing({
|
||||
id: 'test-node-service',
|
||||
location: 'fairbanks',
|
||||
name: 'Test Node Service',
|
||||
url: 'http://localhost:12349',
|
||||
}),
|
||||
{
|
||||
info: makePing({
|
||||
id: 'test-node-service',
|
||||
location: 'fairbanks',
|
||||
name: 'Test Node Service',
|
||||
url: 'http://localhost:12349',
|
||||
}),
|
||||
count: 235,
|
||||
numTimes: 10,
|
||||
interval: '30 days',
|
||||
},
|
||||
{
|
||||
monitorId: 'test-node-service',
|
||||
location: 'harrisburg',
|
||||
|
@ -1347,7 +1369,7 @@ describe('status check alert', () => {
|
|||
}
|
||||
)
|
||||
).toMatchInlineSnapshot(
|
||||
`"down and also below threshold with 58.04% availability expected is 90%"`
|
||||
`"failed 235 times in the last 30 days. Alert when > 10. The 5 mins availability is 58.04%. Alert when < 90%."`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { min } from 'lodash';
|
||||
import * as moment from 'moment';
|
||||
import momentDurationFormatSetup from 'moment-duration-format';
|
||||
import datemath from '@elastic/datemath';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -18,19 +20,27 @@ import {
|
|||
GetMonitorAvailabilityParams,
|
||||
} from '../../../common/runtime_types';
|
||||
import { MONITOR_STATUS } from '../../../common/constants/alerts';
|
||||
import { updateState, generateAlertMessage } from './common';
|
||||
import { commonMonitorStateI18, commonStateTranslations, DOWN_LABEL } from './translations';
|
||||
import { updateState } from './common';
|
||||
import {
|
||||
commonMonitorStateI18,
|
||||
commonStateTranslations,
|
||||
statusCheckTranslations,
|
||||
} from './translations';
|
||||
import { stringifyKueries, combineFiltersAndUserSearch } from '../../../common/lib';
|
||||
import { GetMonitorAvailabilityResult } from '../requests/get_monitor_availability';
|
||||
import { GetMonitorStatusResult } from '../requests/get_monitor_status';
|
||||
import {
|
||||
GetMonitorStatusResult,
|
||||
GetMonitorDownStatusMessageParams,
|
||||
getMonitorDownStatusMessageParams,
|
||||
getInterval,
|
||||
} from '../requests/get_monitor_status';
|
||||
import { UNNAMED_LOCATION } from '../../../common/constants';
|
||||
import { MonitorStatusTranslations } from '../../../common/translations';
|
||||
import { getUptimeIndexPattern, IndexPatternTitleAndFields } from '../requests/get_index_pattern';
|
||||
import { UMServerLibs, UptimeESClient, createUptimeESClient } from '../lib';
|
||||
import { ActionGroupIdsOf } from '../../../../alerting/common';
|
||||
momentDurationFormatSetup(moment);
|
||||
|
||||
export type ActionGroupIds = ActionGroupIdsOf<typeof MONITOR_STATUS>;
|
||||
|
||||
/**
|
||||
* Returns the appropriate range for filtering the documents by `@timestamp`.
|
||||
*
|
||||
|
@ -131,6 +141,8 @@ export const formatFilterString = async (
|
|||
);
|
||||
|
||||
export const getMonitorSummary = (monitorInfo: Ping, statusMessage: string) => {
|
||||
const monitorName = monitorInfo.monitor?.name ?? monitorInfo.monitor?.id;
|
||||
const observerLocation = monitorInfo.observer?.geo?.name ?? UNNAMED_LOCATION;
|
||||
const summary = {
|
||||
monitorUrl: monitorInfo.url?.full,
|
||||
monitorId: monitorInfo.monitor?.id,
|
||||
|
@ -140,13 +152,10 @@ export const getMonitorSummary = (monitorInfo: Ping, statusMessage: string) => {
|
|||
observerLocation: monitorInfo.observer?.geo?.name ?? UNNAMED_LOCATION,
|
||||
observerHostname: monitorInfo.agent?.name,
|
||||
};
|
||||
const reason = generateAlertMessage(MonitorStatusTranslations.defaultActionMessage, {
|
||||
...summary,
|
||||
statusMessage,
|
||||
});
|
||||
|
||||
return {
|
||||
...summary,
|
||||
reason,
|
||||
reason: `${monitorName} from ${observerLocation} ${statusMessage}`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -162,40 +171,32 @@ export const getMonitorAlertDocument = (monitorSummary: Record<string, string |
|
|||
});
|
||||
|
||||
export const getStatusMessage = (
|
||||
downMonInfo?: Ping,
|
||||
downMonParams?: GetMonitorDownStatusMessageParams,
|
||||
availMonInfo?: GetMonitorAvailabilityResult,
|
||||
availability?: GetMonitorAvailabilityParams
|
||||
) => {
|
||||
let statusMessage = '';
|
||||
if (downMonInfo) {
|
||||
statusMessage = DOWN_LABEL;
|
||||
if (downMonParams?.info) {
|
||||
statusMessage = `${statusCheckTranslations.downMonitorsLabel(
|
||||
downMonParams.count!,
|
||||
downMonParams.interval!,
|
||||
downMonParams.numTimes
|
||||
)}.`;
|
||||
}
|
||||
let availabilityMessage = '';
|
||||
|
||||
if (availMonInfo) {
|
||||
availabilityMessage = i18n.translate(
|
||||
'xpack.uptime.alerts.monitorStatus.actionVariables.availabilityMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'below threshold with {availabilityRatio}% availability expected is {expectedAvailability}%',
|
||||
values: {
|
||||
availabilityRatio: (availMonInfo.availabilityRatio! * 100).toFixed(2),
|
||||
expectedAvailability: availability?.threshold,
|
||||
},
|
||||
}
|
||||
);
|
||||
availabilityMessage = `${statusCheckTranslations.availabilityBreachLabel(
|
||||
(availMonInfo.availabilityRatio! * 100).toFixed(2),
|
||||
availability?.threshold!,
|
||||
getInterval(availability?.range!, availability?.rangeUnit!)
|
||||
)}.`;
|
||||
}
|
||||
if (availMonInfo && downMonInfo) {
|
||||
return i18n.translate(
|
||||
'xpack.uptime.alerts.monitorStatus.actionVariables.downAndAvailabilityMessage',
|
||||
{
|
||||
defaultMessage: '{statusMessage} and also {availabilityMessage}',
|
||||
values: {
|
||||
statusMessage,
|
||||
availabilityMessage,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (availMonInfo && downMonParams?.info) {
|
||||
return `${statusCheckTranslations.downMonitorsAndAvailabilityBreachLabel(
|
||||
statusMessage,
|
||||
availabilityMessage
|
||||
)}`;
|
||||
}
|
||||
return statusMessage + availabilityMessage;
|
||||
};
|
||||
|
@ -314,6 +315,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
isAutoGenerated,
|
||||
timerange: oldVersionTimeRange,
|
||||
} = rawParams;
|
||||
|
||||
const uptimeEsClient = createUptimeESClient({
|
||||
esClient: scopedClusterClient.asCurrentUser,
|
||||
savedObjectsClient,
|
||||
|
@ -322,7 +324,6 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
const filterString = await formatFilterString(uptimeEsClient, filters, search, libs);
|
||||
|
||||
const timespanInterval = `${String(timerangeCount)}${timerangeUnit}`;
|
||||
|
||||
// Range filter for `monitor.timespan`, the range of time the ping is valid
|
||||
const timespanRange = oldVersionTimeRange || {
|
||||
from: `now-${timespanInterval}`,
|
||||
|
@ -354,9 +355,17 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
for (const monitorLoc of downMonitorsByLocation) {
|
||||
const monitorInfo = monitorLoc.monitorInfo;
|
||||
|
||||
const statusMessage = getStatusMessage(monitorInfo);
|
||||
const monitorSummary = getMonitorSummary(monitorInfo, statusMessage);
|
||||
const monitorStatusMessageParams = getMonitorDownStatusMessageParams(
|
||||
monitorInfo,
|
||||
monitorLoc.count,
|
||||
numTimes,
|
||||
timerangeCount,
|
||||
timerangeUnit,
|
||||
oldVersionTimeRange
|
||||
);
|
||||
|
||||
const statusMessage = getStatusMessage(monitorStatusMessageParams);
|
||||
const monitorSummary = getMonitorSummary(monitorInfo, statusMessage);
|
||||
const alert = alertWithLifecycle({
|
||||
id: getInstanceId(monitorInfo, monitorLoc.location),
|
||||
fields: getMonitorAlertDocument(monitorSummary),
|
||||
|
@ -394,11 +403,27 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
|
|||
({ monitorId, location }) => getMonIdByLoc(monitorId, location) === monIdByLoc
|
||||
)?.monitorInfo;
|
||||
|
||||
const downMonCount = downMonitorsByLocation.find(
|
||||
({ monitorId, location }) => getMonIdByLoc(monitorId, location) === monIdByLoc
|
||||
)?.count;
|
||||
|
||||
const monitorInfo = downMonInfo || availMonInfo?.monitorInfo!;
|
||||
|
||||
const statusMessage = getStatusMessage(downMonInfo!, availMonInfo!, availability);
|
||||
const monitorSummary = getMonitorSummary(monitorInfo, statusMessage);
|
||||
const monitorStatusMessageParams = getMonitorDownStatusMessageParams(
|
||||
downMonInfo!,
|
||||
downMonCount!,
|
||||
numTimes,
|
||||
timerangeCount,
|
||||
timerangeUnit,
|
||||
oldVersionTimeRange
|
||||
);
|
||||
|
||||
const statusMessage = getStatusMessage(
|
||||
monitorStatusMessageParams,
|
||||
availMonInfo!,
|
||||
availability
|
||||
);
|
||||
const monitorSummary = getMonitorSummary(monitorInfo, statusMessage);
|
||||
const alert = alertWithLifecycle({
|
||||
id: getInstanceId(monitorInfo, monIdByLoc),
|
||||
fields: getMonitorAlertDocument(monitorSummary),
|
||||
|
|
|
@ -328,6 +328,39 @@ export const durationAnomalyTranslations = {
|
|||
],
|
||||
};
|
||||
|
||||
export const DOWN_LABEL = i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.down', {
|
||||
defaultMessage: 'down',
|
||||
});
|
||||
export const statusCheckTranslations = {
|
||||
downMonitorsLabel: (count: number, interval: string, numTimes: number) =>
|
||||
i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.down', {
|
||||
defaultMessage: `failed {count} times in the last {interval}. Alert when > {numTimes}`,
|
||||
values: {
|
||||
count,
|
||||
interval,
|
||||
numTimes,
|
||||
},
|
||||
}),
|
||||
availabilityBreachLabel: (
|
||||
availabilityRatio: string,
|
||||
expectedAvailability: string,
|
||||
interval: string
|
||||
) =>
|
||||
i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.availabilityMessage', {
|
||||
defaultMessage:
|
||||
'{interval} availability is {availabilityRatio}%. Alert when < {expectedAvailability}%',
|
||||
values: {
|
||||
availabilityRatio,
|
||||
expectedAvailability,
|
||||
interval,
|
||||
},
|
||||
}),
|
||||
downMonitorsAndAvailabilityBreachLabel: (
|
||||
downMonitorsMessage: string,
|
||||
availabilityBreachMessage: string
|
||||
) =>
|
||||
i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.downAndAvailabilityMessage', {
|
||||
defaultMessage: '{downMonitorsMessage} The {availabilityBreachMessage}',
|
||||
values: {
|
||||
downMonitorsMessage,
|
||||
availabilityBreachMessage,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
import { JsonObject } from '@kbn/utility-types';
|
||||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { PromiseType } from 'utility-types';
|
||||
import * as moment from 'moment';
|
||||
import momentDurationFormatSetup from 'moment-duration-format';
|
||||
import { asMutableArray } from '../../../common/utils/as_mutable_array';
|
||||
import { UMElasticsearchQueryFn } from '../adapters';
|
||||
import { Ping } from '../../../common/runtime_types/ping';
|
||||
import { createEsQuery } from '../../../common/utils/es_search';
|
||||
import { UptimeESClient } from '../lib';
|
||||
import { UNNAMED_LOCATION } from '../../../common/constants';
|
||||
momentDurationFormatSetup(moment);
|
||||
|
||||
export interface GetMonitorStatusParams {
|
||||
filters?: JsonObject;
|
||||
|
@ -31,6 +34,46 @@ export interface GetMonitorStatusResult {
|
|||
monitorInfo: Ping;
|
||||
}
|
||||
|
||||
export const getInterval = (timerangeCount: number, timerangeUnit: string): string => {
|
||||
switch (timerangeUnit) {
|
||||
case 's':
|
||||
return moment.duration(timerangeCount, 'seconds').format('s [sec]');
|
||||
case 'm':
|
||||
return moment.duration(timerangeCount, 'minutes').format('m [min]');
|
||||
case 'h':
|
||||
return moment.duration(timerangeCount, 'hours').format('h [hr]');
|
||||
case 'd':
|
||||
return moment.duration(timerangeCount, 'days').format('d [day]');
|
||||
default:
|
||||
return `${timerangeCount} ${timerangeUnit}`;
|
||||
}
|
||||
};
|
||||
|
||||
export interface GetMonitorDownStatusMessageParams {
|
||||
info: Ping;
|
||||
count: number;
|
||||
interval?: string;
|
||||
numTimes: number;
|
||||
}
|
||||
|
||||
export const getMonitorDownStatusMessageParams = (
|
||||
info: Ping,
|
||||
count: number,
|
||||
numTimes: number,
|
||||
timerangeCount: number,
|
||||
timerangeUnit: string,
|
||||
oldVersionTimeRange: { from: string; to: string }
|
||||
) => {
|
||||
return {
|
||||
info,
|
||||
count,
|
||||
interval: oldVersionTimeRange
|
||||
? oldVersionTimeRange.from.slice(-3)
|
||||
: getInterval(timerangeCount, timerangeUnit),
|
||||
numTimes,
|
||||
};
|
||||
};
|
||||
|
||||
const getLocationClause = (locations: string[]) => ({
|
||||
bool: {
|
||||
should: [
|
||||
|
|
|
@ -107,7 +107,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
group: 'xpack.uptime.alerts.actionGroups.monitorStatus',
|
||||
params: {
|
||||
message:
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
'Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} from {{state.observerLocation}} {{{state.statusMessage}}}. The latest error message is {{{state.latestErrorMessage}}}',
|
||||
},
|
||||
id: 'my-slack1',
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue