"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.uptimeRuleTypeFieldMap = exports.updateState = exports.setRecoveredAlertsContext = exports.hasFilters = exports.getViewInAppUrl = exports.getRelativeViewInAppUrl = exports.getFullViewInAppMessage = exports.getErrorDuration = exports.getAlertDetailsUrl = exports.generateFilterDSL = exports.generateAlertMessage = exports.formatFilterString = exports.UptimeRuleTypeAlertDefinition = exports.RECOVERED_LABEL = void 0; var _moment = _interopRequireDefault(require("moment")); var _Either = require("fp-ts/lib/Either"); var _mustache = _interopRequireDefault(require("mustache")); var _common = require("@kbn/spaces-plugin/common"); var _i18n = require("@kbn/i18n"); var _esQuery = require("@kbn/es-query"); var _alertsAsDataUtils = require("@kbn/alerts-as-data-utils"); var _lib = require("../../common/lib"); var _synthetics_alerts = require("../../common/constants/synthetics_alerts"); var _uptime_rule_field_map = require("../../common/rules/uptime_rule_field_map"); var _get_index_pattern = require("../legacy_uptime/lib/requests/get_index_pattern"); var _message_utils = require("./status_rule/message_utils"); var _common2 = require("../../common/runtime_types/alert_rules/common"); var _get_synthetics_monitor_url = require("../../common/utils/get_synthetics_monitor_url"); var _action_variables = require("./action_variables"); /* * 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. */ const updateState = (state, isTriggeredNow, meta) => { const now = new Date().toISOString(); const decoded = _common2.SyntheticsCommonStateCodec.decode(state); if (!(0, _Either.isRight)(decoded)) { const triggerVal = isTriggeredNow ? now : undefined; return { firstCheckedAt: now, firstTriggeredAt: triggerVal, isTriggered: isTriggeredNow, lastTriggeredAt: triggerVal, lastCheckedAt: now, lastResolvedAt: undefined, meta: {} }; } const { firstCheckedAt, firstTriggeredAt, lastTriggeredAt, // this is the stale trigger status, we're naming it `wasTriggered` // to differentiate it from the `isTriggeredNow` param isTriggered: wasTriggered, lastResolvedAt } = decoded.right; return { meta, firstCheckedAt: firstCheckedAt !== null && firstCheckedAt !== void 0 ? firstCheckedAt : now, firstTriggeredAt: isTriggeredNow && !firstTriggeredAt ? now : firstTriggeredAt, lastCheckedAt: now, lastTriggeredAt: isTriggeredNow ? now : lastTriggeredAt, lastResolvedAt: !isTriggeredNow && wasTriggered ? now : lastResolvedAt, isTriggered: isTriggeredNow }; }; exports.updateState = updateState; const generateAlertMessage = (messageTemplate, fields) => { return _mustache.default.render(messageTemplate, { context: { ...fields }, state: { ...fields } }); }; exports.generateAlertMessage = generateAlertMessage; const getFullViewInAppMessage = (basePath, spaceId, relativeViewInAppUrl) => { const relativeLinkLabel = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.relativeLink.label', { defaultMessage: `- Relative link` }); const absoluteLinkLabel = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.absoluteLink.label', { defaultMessage: `- Link` }); if (basePath.publicBaseUrl) { return `${absoluteLinkLabel}: ${getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl)}`; } else { return `${relativeLinkLabel}: ${getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl)}`; } }; exports.getFullViewInAppMessage = getFullViewInAppMessage; const getViewInAppUrl = (basePath, spaceId, relativeViewInAppUrl) => (0, _common.addSpaceIdToPath)(basePath.publicBaseUrl, spaceId, relativeViewInAppUrl); exports.getViewInAppUrl = getViewInAppUrl; const getAlertDetailsUrl = (basePath, spaceId, alertUuid) => (0, _common.addSpaceIdToPath)(basePath.publicBaseUrl, spaceId, `/app/observability/alerts/${alertUuid}`); exports.getAlertDetailsUrl = getAlertDetailsUrl; const getRelativeViewInAppUrl = ({ configId, stateId, locationId }) => { const relativeViewInAppUrl = (0, _get_synthetics_monitor_url.getSyntheticsErrorRouteFromMonitorId)({ configId, stateId, locationId }); return relativeViewInAppUrl; }; exports.getRelativeViewInAppUrl = getRelativeViewInAppUrl; const getErrorDuration = (startedAt, endsAt) => { const diffInDays = endsAt.diff(startedAt, 'days'); if (diffInDays > 1) { return _i18n.i18n.translate('xpack.synthetics.errorDetails.errorDuration.days', { defaultMessage: '{value} days', values: { value: diffInDays } }); } const diffInHours = endsAt.diff(startedAt, 'hours'); if (diffInHours > 1) { return _i18n.i18n.translate('xpack.synthetics.errorDetails.errorDuration.hours', { defaultMessage: '{value} hours', values: { value: diffInHours } }); } const diffInMinutes = endsAt.diff(startedAt, 'minutes'); return _i18n.i18n.translate('xpack.synthetics.errorDetails.errorDuration.mins', { defaultMessage: '{value} mins', values: { value: diffInMinutes } }); }; exports.getErrorDuration = getErrorDuration; const setRecoveredAlertsContext = ({ alertFactory, basePath, getAlertUuid, spaceId, staleDownConfigs, upConfigs, dateFormat, tz }) => { const { getRecoveredAlerts } = alertFactory.done(); for (const alert of getRecoveredAlerts()) { const recoveredAlertId = alert.getId(); const alertUuid = (getAlertUuid === null || getAlertUuid === void 0 ? void 0 : getAlertUuid(recoveredAlertId)) || undefined; const state = alert.getState(); let recoveryReason = ''; let recoveryStatus = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.defaultRecovery.status', { defaultMessage: `has recovered` }); let isUp = false; let linkMessage = ''; let monitorSummary = null; let lastErrorMessage; if (state !== null && state !== void 0 && state.idWithLocation && staleDownConfigs[state.idWithLocation]) { const { idWithLocation, locationId } = state; const downConfig = staleDownConfigs[idWithLocation]; const { ping, configId } = downConfig; monitorSummary = (0, _message_utils.getMonitorSummary)(ping, RECOVERED_LABEL, locationId, configId, dateFormat, tz); lastErrorMessage = monitorSummary.lastErrorMessage; if (downConfig.isDeleted) { recoveryStatus = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.deleteMonitor.status', { defaultMessage: `has been deleted` }); recoveryReason = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.deleteMonitor.reason', { defaultMessage: `the monitor has been deleted` }); } else if (downConfig.isLocationRemoved) { recoveryStatus = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.removedLocation.status', { defaultMessage: `has recovered` }); recoveryReason = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.removedLocation.reason', { defaultMessage: `this location has been removed from the monitor` }); } } if (state !== null && state !== void 0 && state.idWithLocation && upConfigs[state.idWithLocation]) { var _ping$state, _ping$state$ends; const { idWithLocation, configId, locationId } = state; // pull the last error from state, since it is not available on the up ping lastErrorMessage = state.lastErrorMessage; const upConfig = upConfigs[idWithLocation]; isUp = Boolean(upConfig) || false; const ping = upConfig.ping; monitorSummary = (0, _message_utils.getMonitorSummary)(ping, RECOVERED_LABEL, locationId, configId, dateFormat, tz); // When alert is flapping, the stateId is not available on ping.state.ends.id, use state instead const stateId = ((_ping$state = ping.state) === null || _ping$state === void 0 ? void 0 : (_ping$state$ends = _ping$state.ends) === null || _ping$state$ends === void 0 ? void 0 : _ping$state$ends.id) || state.stateId; const upTimestamp = ping['@timestamp']; const checkedAt = (0, _moment.default)(upTimestamp).tz(tz).format(dateFormat); recoveryStatus = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.upCheck.status', { defaultMessage: `is now up` }); recoveryReason = _i18n.i18n.translate('xpack.synthetics.alerts.monitorStatus.upCheck.reasonWithoutDuration', { defaultMessage: `the monitor is now up again. It ran successfully at {checkedAt}`, values: { checkedAt } }); if (basePath && spaceId && stateId) { const relativeViewInAppUrl = getRelativeViewInAppUrl({ configId, locationId, stateId }); linkMessage = getFullViewInAppMessage(basePath, spaceId, relativeViewInAppUrl); } } alert.setContext({ ...state, ...(monitorSummary ? monitorSummary : {}), lastErrorMessage, recoveryStatus, linkMessage, ...(isUp ? { status: 'up' } : {}), ...(recoveryReason ? { [_action_variables.RECOVERY_REASON]: recoveryReason } : {}), ...(basePath && spaceId && alertUuid ? { [_action_variables.ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid) } : {}) }); } }; exports.setRecoveredAlertsContext = setRecoveredAlertsContext; const RECOVERED_LABEL = _i18n.i18n.translate('xpack.synthetics.monitorStatus.recoveredLabel', { defaultMessage: 'recovered' }); exports.RECOVERED_LABEL = RECOVERED_LABEL; const formatFilterString = async (uptimeEsClient, filters, search) => await generateFilterDSL(() => (0, _get_index_pattern.getUptimeIndexPattern)({ uptimeEsClient }), filters, search); exports.formatFilterString = formatFilterString; const hasFilters = filters => { if (!filters) return false; for (const list of Object.values(filters)) { if (list.length > 0) { return true; } } return false; }; exports.hasFilters = hasFilters; const generateFilterDSL = async (getIndexPattern, filters, search) => { const filtersExist = hasFilters(filters); if (!filtersExist && !search) return undefined; let filterString = ''; if (filtersExist) { filterString = (0, _lib.stringifyKueries)(new Map(Object.entries(filters !== null && filters !== void 0 ? filters : {}))); } const combinedString = (0, _lib.combineFiltersAndUserSearch)(filterString, search); return (0, _esQuery.toElasticsearchQuery)((0, _esQuery.fromKueryExpression)(combinedString !== null && combinedString !== void 0 ? combinedString : ''), await getIndexPattern()); }; exports.generateFilterDSL = generateFilterDSL; const uptimeRuleTypeFieldMap = { ..._uptime_rule_field_map.uptimeRuleFieldMap, ..._alertsAsDataUtils.legacyExperimentalFieldMap }; exports.uptimeRuleTypeFieldMap = uptimeRuleTypeFieldMap; const UptimeRuleTypeAlertDefinition = { context: _synthetics_alerts.SYNTHETICS_RULE_TYPES_ALERT_CONTEXT, mappings: { fieldMap: uptimeRuleTypeFieldMap }, useLegacyAlerts: true }; exports.UptimeRuleTypeAlertDefinition = UptimeRuleTypeAlertDefinition;