"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateKQLStringFilter = exports.validGroupByForContext = exports.unflattenObject = exports.shouldTermsAggOnContainer = exports.oneOfLiterals = exports.isTooManyBucketsPreviewException = exports.hasAdditionalContext = exports.getIntervalInSeconds = exports.getGroupByObject = exports.getContextForRecoveredAlerts = exports.getAlertDetailsUrl = exports.getAlertDetailsPageEnabledForApp = exports.flattenObject = exports.flattenAdditionalContext = exports.doFieldsExist = exports.createScopedLogger = exports.calculateRateTimeranges = exports.UNGROUPED_FACTORY_KEY = exports.TOO_MANY_BUCKETS_PREVIEW_EXCEPTION = exports.NUMBER_OF_DOCUMENTS = exports.KUBERNETES_POD_UID = exports.INFRA_ALERT_PREVIEW_PATH = exports.CONTAINER_ID = void 0; var _lodash = require("lodash"); var _esQuery = require("@kbn/es-query"); var _i18n = require("@kbn/i18n"); var _configSchema = require("@kbn/config-schema"); var _common = require("@kbn/spaces-plugin/common"); var _fieldTypes = require("@kbn/field-types"); var _saferLodashSet = require("@kbn/safer-lodash-set"); /* * 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 ALERT_CONTEXT_CONTAINER = 'container'; const ALERT_CONTEXT_ORCHESTRATOR = 'orchestrator'; const ALERT_CONTEXT_CLOUD = 'cloud'; const ALERT_CONTEXT_HOST = 'host'; const ALERT_CONTEXT_LABELS = 'labels'; const ALERT_CONTEXT_TAGS = 'tags'; const HOST_NAME = 'host.name'; const HOST_HOSTNAME = 'host.hostname'; const HOST_ID = 'host.id'; const CONTAINER_ID = 'container.id'; exports.CONTAINER_ID = CONTAINER_ID; const SUPPORTED_ES_FIELD_TYPES = [_fieldTypes.ES_FIELD_TYPES.KEYWORD, _fieldTypes.ES_FIELD_TYPES.IP, _fieldTypes.ES_FIELD_TYPES.BOOLEAN]; const oneOfLiterals = arrayOfLiterals => _configSchema.schema.string({ validate: value => arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}` }); exports.oneOfLiterals = oneOfLiterals; const validateKQLStringFilter = value => { if (value === '') { // Allow clearing the filter. return; } try { (0, _esQuery.buildEsQuery)(undefined, [{ query: value, language: 'kuery' }], []); } catch (e) { return _i18n.i18n.translate('xpack.observability.threshold.rule.schema.invalidFilterQuery', { defaultMessage: 'filterQuery must be a valid KQL filter' }); } }; exports.validateKQLStringFilter = validateKQLStringFilter; const UNGROUPED_FACTORY_KEY = '*'; exports.UNGROUPED_FACTORY_KEY = UNGROUPED_FACTORY_KEY; const createScopedLogger = (logger, scope, alertExecutionDetails) => { const scopedLogger = logger.get(scope); const fmtMsg = msg => `[AlertId: ${alertExecutionDetails.alertId}][ExecutionId: ${alertExecutionDetails.executionId}] ${msg}`; return { ...scopedLogger, info: (msg, meta) => scopedLogger.info(fmtMsg(msg), meta), debug: (msg, meta) => scopedLogger.debug(fmtMsg(msg), meta), trace: (msg, meta) => scopedLogger.trace(fmtMsg(msg), meta), warn: (errorOrMessage, meta) => { if ((0, _lodash.isError)(errorOrMessage)) { scopedLogger.warn(errorOrMessage, meta); } else { scopedLogger.warn(fmtMsg(errorOrMessage), meta); } }, error: (errorOrMessage, meta) => { if ((0, _lodash.isError)(errorOrMessage)) { scopedLogger.error(errorOrMessage, meta); } else { scopedLogger.error(fmtMsg(errorOrMessage), meta); } }, fatal: (errorOrMessage, meta) => { if ((0, _lodash.isError)(errorOrMessage)) { scopedLogger.fatal(errorOrMessage, meta); } else { scopedLogger.fatal(fmtMsg(errorOrMessage), meta); } } }; }; exports.createScopedLogger = createScopedLogger; const getAlertDetailsPageEnabledForApp = (config, appName) => { if (!config) return false; return config[appName].enabled; }; exports.getAlertDetailsPageEnabledForApp = getAlertDetailsPageEnabledForApp; const getAlertDetailsUrl = (basePath, spaceId, alertUuid) => (0, _common.addSpaceIdToPath)(basePath.publicBaseUrl, spaceId, `/app/observability/alerts/${alertUuid}`); exports.getAlertDetailsUrl = getAlertDetailsUrl; const KUBERNETES_POD_UID = 'kubernetes.pod.uid'; exports.KUBERNETES_POD_UID = KUBERNETES_POD_UID; const NUMBER_OF_DOCUMENTS = 10; exports.NUMBER_OF_DOCUMENTS = NUMBER_OF_DOCUMENTS; const doFieldsExist = async (esClient, fields, index) => { // Get all supported fields const respMapping = await esClient.fieldCaps({ index, fields: '*' }); const fieldsExisted = {}; const acceptableFields = new Set(); Object.entries(respMapping.fields).forEach(([key, value]) => { const fieldTypes = Object.keys(value); const isSupportedType = fieldTypes.some(type => SUPPORTED_ES_FIELD_TYPES.includes(type)); // Check if fieldName is something we can aggregate on if (isSupportedType) { acceptableFields.add(key); } }); fields.forEach(field => { fieldsExisted[field] = acceptableFields.has(field); }); return fieldsExisted; }; exports.doFieldsExist = doFieldsExist; const validGroupByForContext = [HOST_NAME, HOST_HOSTNAME, HOST_ID, KUBERNETES_POD_UID, CONTAINER_ID]; exports.validGroupByForContext = validGroupByForContext; const hasAdditionalContext = (groupBy, validGroups) => { return groupBy ? Array.isArray(groupBy) ? groupBy.every(group => validGroups.includes(group)) : validGroups.includes(groupBy) : false; }; exports.hasAdditionalContext = hasAdditionalContext; const shouldTermsAggOnContainer = groupBy => { return groupBy && Array.isArray(groupBy) ? groupBy.includes(KUBERNETES_POD_UID) : groupBy === KUBERNETES_POD_UID; }; exports.shouldTermsAggOnContainer = shouldTermsAggOnContainer; const flattenAdditionalContext = additionalContext => { return additionalContext ? flattenObject(additionalContext) : {}; }; exports.flattenAdditionalContext = flattenAdditionalContext; const getContextForRecoveredAlerts = alertHitSource => { const alert = alertHitSource ? unflattenObject(alertHitSource) : undefined; return { cloud: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_CLOUD], host: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_HOST], orchestrator: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_ORCHESTRATOR], container: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_CONTAINER], labels: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_LABELS], tags: alert === null || alert === void 0 ? void 0 : alert[ALERT_CONTEXT_TAGS] }; }; exports.getContextForRecoveredAlerts = getContextForRecoveredAlerts; const unflattenObject = object => Object.entries(object).reduce((acc, [key, value]) => { (0, _saferLodashSet.set)(acc, key, value); return acc; }, {}); exports.unflattenObject = unflattenObject; const flattenObject = (obj, prefix = '') => Object.keys(obj).reduce((acc, key) => { const nextValue = obj[key]; if (nextValue) { if (typeof nextValue === 'object' && !Array.isArray(nextValue)) { const dotSuffix = '.'; if (Object.keys(nextValue).length > 0) { return { ...acc, ...flattenObject(nextValue, `${prefix}${key}${dotSuffix}`) }; } } const fullPath = `${prefix}${key}`; acc[fullPath] = nextValue; } return acc; }, {}); exports.flattenObject = flattenObject; const getGroupByObject = (groupBy, resultGroupSet) => { const groupByKeysObjectMapping = {}; if (groupBy) { resultGroupSet.forEach(groupSet => { const groupSetKeys = groupSet.split(','); groupByKeysObjectMapping[groupSet] = unflattenObject(Array.isArray(groupBy) ? groupBy.reduce((result, group, index) => { var _groupSetKeys$index; return { ...result, [group]: (_groupSetKeys$index = groupSetKeys[index]) === null || _groupSetKeys$index === void 0 ? void 0 : _groupSetKeys$index.trim() }; }, {}) : { [groupBy]: groupSet }); }); } return groupByKeysObjectMapping; }; // TO BE MOVED exports.getGroupByObject = getGroupByObject; const INFRA_ALERT_PREVIEW_PATH = '/api/infra/alerting/preview'; exports.INFRA_ALERT_PREVIEW_PATH = INFRA_ALERT_PREVIEW_PATH; const TOO_MANY_BUCKETS_PREVIEW_EXCEPTION = 'TOO_MANY_BUCKETS_PREVIEW_EXCEPTION'; exports.TOO_MANY_BUCKETS_PREVIEW_EXCEPTION = TOO_MANY_BUCKETS_PREVIEW_EXCEPTION; const isTooManyBucketsPreviewException = value => Boolean(value && value.TOO_MANY_BUCKETS_PREVIEW_EXCEPTION); exports.isTooManyBucketsPreviewException = isTooManyBucketsPreviewException; const intervalUnits = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms']; const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + intervalUnits.join('|') + ')$'); const units = { ms: 0.001, s: 1, m: 60, h: 3600, d: 86400, w: 86400 * 7, M: 86400 * 30, y: 86400 * 356 }; const getIntervalInSeconds = interval => { const matches = interval.match(INTERVAL_STRING_RE); if (matches) { return parseFloat(matches[1]) * units[matches[2]]; } throw new Error('Invalid interval string format.'); }; exports.getIntervalInSeconds = getIntervalInSeconds; const calculateRateTimeranges = timerange => { // This is the total number of milliseconds for the entire timerange const totalTime = timerange.to - timerange.from; // Halfway is the to minus half the total time; const halfway = Math.round(timerange.to - totalTime / 2); // The interval is half the total time (divided by 1000 to convert to seconds) const intervalInSeconds = Math.round(totalTime / (2 * 1000)); // The first bucket is from the beginning of the time range to the halfway point const firstBucketRange = { from: timerange.from, to: halfway }; // The second bucket is from the halfway point to the end of the timerange const secondBucketRange = { from: halfway, to: timerange.to }; return { firstBucketRange, secondBucketRange, intervalInSeconds }; }; exports.calculateRateTimeranges = calculateRateTimeranges;