diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 8531f4a2bb706..bbf00572935fa 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -268,7 +268,8 @@ export class ActionsPlugin implements Plugin { test('getTotalCount should replace first symbol . to __ for action types names', async () => { @@ -604,4 +604,102 @@ Object { } `); }); + + test('getExecutionsTotalCount', async () => { + const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; + mockEsClient.search.mockReturnValueOnce( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + totalExecutions: { + byConnectorTypeId: { + value: { + connectorTypes: { + '.slack': 100, + '.server-log': 20, + }, + total: 120, + }, + }, + }, + failedExecutions: { + refs: { + byConnectorTypeId: { + value: { + connectorTypes: { + '.slack': 7, + }, + total: 7, + }, + }, + }, + }, + avgDuration: { value: 10 }, + avgDurationByType: { + doc_count: 216, + actionSavedObjects: { + doc_count: 108, + byTypeId: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.server-log', + doc_count: 99, + refs: { + doc_count: 99, + avgDuration: { + value: 919191.9191919192, + }, + }, + }, + { + key: '.email', + doc_count: 9, + refs: { + doc_count: 9, + avgDuration: { + value: 4.196666666666667e8, + }, + }, + }, + ], + }, + }, + }, + }, + }) + ); + + // for .slack connectors + mockEsClient.search.mockReturnValueOnce( + // @ts-expect-error not full search response + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + avgDuration: { value: 10 }, + }, + }) + ); + const telemetry = await getExecutionsPerDayCount(mockEsClient, 'test'); + + expect(mockEsClient.search).toHaveBeenCalledTimes(1); + expect(telemetry).toStrictEqual({ + avgExecutionTime: 0, + avgExecutionTimeByType: { + '__server-log': 919191.9191919192, + __email: 419666666.6666667, + }, + + countByType: { + __slack: 100, + + '__server-log': 20, + }, + countFailed: 7, + countFailedByType: { + __slack: 7, + }, + countTotal: 120, + }); + }); }); diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.ts index ab72352d460e3..d288611af5e21 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.ts @@ -379,4 +379,184 @@ function replaceFirstAndLastDotSymbols(strToReplace: string) { return hasLastSymbolDot ? `${appliedString.slice(0, -1)}__` : appliedString; } -// TODO: Implement executions count telemetry with eventLog, when it will write to index +export async function getExecutionsPerDayCount( + esClient: ElasticsearchClient, + eventLogIndex: string +): Promise<{ + countTotal: number; + countByType: Record; + countFailed: number; + countFailedByType: Record; + avgExecutionTime: number; + avgExecutionTimeByType: Record; +}> { + const scriptedMetric = { + scripted_metric: { + init_script: 'state.connectorTypes = [:]; state.total = 0;', + map_script: ` + if (doc['kibana.saved_objects.type'].value == 'action') { + String connectorType = doc['kibana.saved_objects.type_id'].value; + state.connectorTypes.put(connectorType, state.connectorTypes.containsKey(connectorType) ? state.connectorTypes.get(connectorType) + 1 : 1); + state.total++; + } + `, + // Combine script is executed per cluster, but we already have a key-value pair per cluster. + // Despite docs that say this is optional, this script can't be blank. + combine_script: 'return state', + // Reduce script is executed across all clusters, so we need to add up all the total from each cluster + // This also needs to account for having no data + reduce_script: ` + Map connectorTypes = [:]; + long total = 0; + for (state in states) { + if (state !== null) { + total += state.total; + for (String k : state.connectorTypes.keySet()) { + connectorTypes.put(k, connectorTypes.containsKey(k) ? connectorTypes.get(k) + state.connectorTypes.get(k) : state.connectorTypes.get(k)); + } + } + } + Map result = new HashMap(); + result.total = total; + result.connectorTypes = connectorTypes; + return result; + `, + }, + }; + + const { body: actionResults } = await esClient.search({ + index: eventLogIndex, + size: 0, + body: { + query: { + bool: { + filter: { + bool: { + must: [ + { + term: { 'event.action': 'execute' }, + }, + { + term: { 'event.provider': 'actions' }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d', + }, + }, + }, + ], + }, + }, + }, + }, + aggs: { + totalExecutions: { + nested: { + path: 'kibana.saved_objects', + }, + aggs: { + byConnectorTypeId: scriptedMetric, + }, + }, + failedExecutions: { + filter: { + bool: { + filter: [ + { + term: { + 'event.outcome': 'failure', + }, + }, + ], + }, + }, + aggs: { + refs: { + nested: { + path: 'kibana.saved_objects', + }, + aggs: { + byConnectorTypeId: scriptedMetric, + }, + }, + }, + }, + avgDuration: { avg: { field: 'event.duration' } }, + avgDurationByType: { + nested: { + path: 'kibana.saved_objects', + }, + aggs: { + actionSavedObjects: { + filter: { term: { 'kibana.saved_objects.type': 'action' } }, + aggs: { + byTypeId: { + terms: { + field: 'kibana.saved_objects.type_id', + }, + aggs: { + refs: { + reverse_nested: {}, + aggs: { + avgDuration: { avg: { field: 'event.duration' } }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }); + + // @ts-expect-error aggegation type is not specified + const aggsExecutions = actionResults.aggregations.totalExecutions?.byConnectorTypeId.value; + // convert nanoseconds to milliseconds + const aggsAvgExecutionTime = Math.round( + // @ts-expect-error aggegation type is not specified + actionResults.aggregations.avgDuration.value / (1000 * 1000) + ); + const aggsFailedExecutions = + // @ts-expect-error aggegation type is not specified + actionResults.aggregations.failedExecutions?.refs?.byConnectorTypeId.value; + + const avgDurationByType = + // @ts-expect-error aggegation type is not specified + actionResults.aggregations.avgDurationByType?.actionSavedObjects?.byTypeId?.buckets; + + const avgExecutionTimeByType: Record = avgDurationByType.reduce( + // @ts-expect-error aggegation type is not specified + (res: Record, bucket) => { + res[replaceFirstAndLastDotSymbols(bucket.key)] = bucket?.refs.avgDuration.value; + return res; + }, + {} + ); + + return { + countTotal: aggsExecutions.total, + countByType: Object.entries(aggsExecutions.connectorTypes).reduce( + (res: Record, [key, value]) => { + // @ts-expect-error aggegation type is not specified + res[replaceFirstAndLastDotSymbols(key)] = value; + return res; + }, + {} + ), + countFailed: aggsFailedExecutions.total, + countFailedByType: Object.entries(aggsFailedExecutions.connectorTypes).reduce( + (res: Record, [key, value]) => { + // @ts-expect-error aggegation type is not specified + res[replaceFirstAndLastDotSymbols(key)] = value; + return res; + }, + {} + ), + avgExecutionTime: aggsAvgExecutionTime, + avgExecutionTimeByType, + }; +} diff --git a/x-pack/plugins/actions/server/usage/actions_usage_collector.ts b/x-pack/plugins/actions/server/usage/actions_usage_collector.ts index 9ba9d7390a7b6..3e690d18063d6 100644 --- a/x-pack/plugins/actions/server/usage/actions_usage_collector.ts +++ b/x-pack/plugins/actions/server/usage/actions_usage_collector.ts @@ -37,8 +37,14 @@ export function createActionsUsageCollector( }, }, count_active_by_type: byTypeSchema, + count_actions_executions_per_day: { type: 'long' }, + count_actions_executions_by_type_per_day: byTypeSchema, count_active_email_connectors_by_service_type: byServiceProviderTypeSchema, count_actions_namespaces: { type: 'long' }, + count_actions_executions_failed_per_day: { type: 'long' }, + count_actions_executions_failed_by_type_per_day: byTypeSchema, + avg_execution_time_per_day: { type: 'long' }, + avg_execution_time_by_type_per_day: byTypeSchema, }, fetch: async () => { try { @@ -60,6 +66,12 @@ export function createActionsUsageCollector( count_active_by_type: {}, count_active_email_connectors_by_service_type: {}, count_actions_namespaces: 0, + count_actions_executions_per_day: 0, + count_actions_executions_by_type_per_day: {}, + count_actions_executions_failed_per_day: 0, + count_actions_executions_failed_by_type_per_day: {}, + avg_execution_time_per_day: 0, + avg_execution_time_by_type_per_day: {}, }; } }, diff --git a/x-pack/plugins/actions/server/usage/task.ts b/x-pack/plugins/actions/server/usage/task.ts index bacb9e5f72571..5ddcbab4261d1 100644 --- a/x-pack/plugins/actions/server/usage/task.ts +++ b/x-pack/plugins/actions/server/usage/task.ts @@ -7,13 +7,14 @@ import { Logger, CoreSetup } from 'kibana/server'; import moment from 'moment'; +import { IEventLogService } from '../../../event_log/server'; import { RunContext, TaskManagerSetupContract, TaskManagerStartContract, } from '../../../task_manager/server'; import { PreConfiguredAction } from '../types'; -import { getTotalCount, getInUseTotalCount } from './actions_telemetry'; +import { getTotalCount, getInUseTotalCount, getExecutionsPerDayCount } from './actions_telemetry'; export const TELEMETRY_TASK_TYPE = 'actions_telemetry'; @@ -24,9 +25,17 @@ export function initializeActionsTelemetry( taskManager: TaskManagerSetupContract, core: CoreSetup, kibanaIndex: string, - preconfiguredActions: PreConfiguredAction[] + preconfiguredActions: PreConfiguredAction[], + eventLog: IEventLogService ) { - registerActionsTelemetryTask(logger, taskManager, core, kibanaIndex, preconfiguredActions); + registerActionsTelemetryTask( + logger, + taskManager, + core, + kibanaIndex, + preconfiguredActions, + eventLog + ); } export function scheduleActionsTelemetry(logger: Logger, taskManager: TaskManagerStartContract) { @@ -38,13 +47,20 @@ function registerActionsTelemetryTask( taskManager: TaskManagerSetupContract, core: CoreSetup, kibanaIndex: string, - preconfiguredActions: PreConfiguredAction[] + preconfiguredActions: PreConfiguredAction[], + eventLog: IEventLogService ) { taskManager.registerTaskDefinitions({ [TELEMETRY_TASK_TYPE]: { title: 'Actions usage fetch task', timeout: '5m', - createTaskRunner: telemetryTaskRunner(logger, core, kibanaIndex, preconfiguredActions), + createTaskRunner: telemetryTaskRunner( + logger, + core, + kibanaIndex, + preconfiguredActions, + eventLog + ), }, }); } @@ -66,10 +82,12 @@ export function telemetryTaskRunner( logger: Logger, core: CoreSetup, kibanaIndex: string, - preconfiguredActions: PreConfiguredAction[] + preconfiguredActions: PreConfiguredAction[], + eventLog: IEventLogService ) { return ({ taskInstance }: RunContext) => { const { state } = taskInstance; + const eventLogIndex = eventLog.getIndexPattern(); const getEsClient = () => core.getStartServices().then( ([ @@ -84,8 +102,9 @@ export function telemetryTaskRunner( return Promise.all([ getTotalCount(esClient, kibanaIndex, preconfiguredActions), getInUseTotalCount(esClient, kibanaIndex, undefined, preconfiguredActions), + getExecutionsPerDayCount(esClient, eventLogIndex), ]) - .then(([totalAggegations, totalInUse]) => { + .then(([totalAggegations, totalInUse, totalExecutionsPerDay]) => { return { state: { runs: (state.runs || 0) + 1, @@ -96,6 +115,13 @@ export function telemetryTaskRunner( count_active_alert_history_connectors: totalInUse.countByAlertHistoryConnectorType, count_active_email_connectors_by_service_type: totalInUse.countEmailByService, count_actions_namespaces: totalInUse.countNamespaces, + count_actions_executions_per_day: totalExecutionsPerDay.countTotal, + count_actions_executions_by_type_per_day: totalExecutionsPerDay.countByType, + count_actions_executions_failed_per_day: totalExecutionsPerDay.countFailed, + count_actions_executions_failed_by_type_per_day: + totalExecutionsPerDay.countFailedByType, + avg_execution_time_per_day: totalExecutionsPerDay.avgExecutionTime, + avg_execution_time_by_type_per_day: totalExecutionsPerDay.avgExecutionTimeByType, }, runAt: getNextMidnight(), }; diff --git a/x-pack/plugins/actions/server/usage/types.ts b/x-pack/plugins/actions/server/usage/types.ts index 52677b35ac75b..2d041b1ba0d0e 100644 --- a/x-pack/plugins/actions/server/usage/types.ts +++ b/x-pack/plugins/actions/server/usage/types.ts @@ -16,9 +16,12 @@ export interface ActionsUsage { count_active_by_type: Record; count_active_email_connectors_by_service_type: Record; count_actions_namespaces: number; - // TODO: Implement executions count telemetry with eventLog, when it will write to index - // executions_by_type: Record; - // executions_total: number; + count_actions_executions_per_day: number; + count_actions_executions_by_type_per_day: Record; + count_actions_executions_failed_per_day: number; + count_actions_executions_failed_by_type_per_day: Record; + avg_execution_time_per_day: number; + avg_execution_time_by_type_per_day: Record; } export const byTypeSchema: MakeSchemaFrom['count_by_type'] = { diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 9834225e73723..f0703defbca3d 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -209,7 +209,13 @@ export class AlertingPlugin { usageCollection, core.getStartServices().then(([_, { taskManager }]) => taskManager) ); - initializeAlertingTelemetry(this.telemetryLogger, core, plugins.taskManager, kibanaIndex); + initializeAlertingTelemetry( + this.telemetryLogger, + core, + plugins.taskManager, + kibanaIndex, + this.eventLogService + ); } // Usage counter for telemetry diff --git a/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts b/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts index 03a96d19b8e8a..af08c8c75c144 100644 --- a/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts +++ b/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts @@ -7,7 +7,11 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks'; -import { getTotalCountAggregations, getTotalCountInUse } from './alerts_telemetry'; +import { + getTotalCountAggregations, + getTotalCountInUse, + getExecutionsPerDayCount, +} from './alerts_telemetry'; describe('alerts telemetry', () => { test('getTotalCountInUse should replace first "." symbol to "__" in alert types names', async () => { @@ -114,4 +118,74 @@ Object { } `); }); + + test('getTotalExecutionsCount should return execution aggregations for total count, count by rule type and number of failed executions', async () => { + const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; + mockEsClient.search.mockReturnValue( + // @ts-expect-error @elastic/elasticsearch Aggregate only allows unknown values + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + byRuleTypeId: { + value: { + ruleTypes: { + '.index-threshold': 2, + 'logs.alert.document.count': 1, + 'document.test.': 1, + }, + ruleTypesDuration: { + '.index-threshold': 2087868, + 'logs.alert.document.count': 1675765, + 'document.test.': 17687687, + }, + }, + }, + failuresByReason: { + value: { + reasons: { + unknown: { + '.index-threshold': 2, + 'logs.alert.document.count': 1, + 'document.test.': 1, + }, + }, + }, + }, + avgDuration: { value: 10 }, + }, + hits: { + hits: [], + }, + }) + ); + + const telemetry = await getExecutionsPerDayCount(mockEsClient, 'test'); + + expect(mockEsClient.search).toHaveBeenCalledTimes(1); + + expect(telemetry).toStrictEqual({ + avgExecutionTime: 0, + avgExecutionTimeByType: { + '__index-threshold': 1043934, + 'document.test__': 17687687, + 'logs.alert.document.count': 1675765, + }, + countByType: { + '__index-threshold': 2, + 'document.test__': 1, + 'logs.alert.document.count': 1, + }, + countFailuresByReason: { + unknown: 4, + }, + countFailuresByReasonByType: { + unknown: { + '.index-threshold': 2, + 'document.test.': 1, + 'logs.alert.document.count': 1, + }, + }, + countTotal: 4, + countTotalFailures: 4, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts b/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts index 7ff9538c1aa26..180ee4300f18c 100644 --- a/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts +++ b/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts @@ -38,6 +38,65 @@ const alertTypeMetric = { }, }; +const ruleTypeExecutionsMetric = { + scripted_metric: { + init_script: 'state.ruleTypes = [:]; state.ruleTypesDuration = [:];', + map_script: ` + String ruleType = doc['rule.category'].value; + long duration = doc['event.duration'].value / (1000 * 1000); + state.ruleTypes.put(ruleType, state.ruleTypes.containsKey(ruleType) ? state.ruleTypes.get(ruleType) + 1 : 1); + state.ruleTypesDuration.put(ruleType, state.ruleTypesDuration.containsKey(ruleType) ? state.ruleTypesDuration.get(ruleType) + duration : duration); + `, + // Combine script is executed per cluster, but we already have a key-value pair per cluster. + // Despite docs that say this is optional, this script can't be blank. + combine_script: 'return state', + // Reduce script is executed across all clusters, so we need to add up all the total from each cluster + // This also needs to account for having no data + reduce_script: ` + Map result = [:]; + for (Map m : states.toArray()) { + if (m !== null) { + for (String k : m.keySet()) { + result.put(k, result.containsKey(k) ? result.get(k) + m.get(k) : m.get(k)); + } + } + } + return result; + `, + }, +}; + +const ruleTypeFailureExecutionsMetric = { + scripted_metric: { + init_script: 'state.reasons = [:]', + map_script: ` + if (doc['event.outcome'].value == 'failure') { + String reason = doc['event.reason'].value; + String ruleType = doc['rule.category'].value; + Map ruleTypes = state.reasons.containsKey(reason) ? state.reasons.get(reason) : [:]; + ruleTypes.put(ruleType, ruleTypes.containsKey(ruleType) ? ruleTypes.get(ruleType) + 1 : 1); + state.reasons.put(reason, ruleTypes); + } + `, + // Combine script is executed per cluster, but we already have a key-value pair per cluster. + // Despite docs that say this is optional, this script can't be blank. + combine_script: 'return state', + // Reduce script is executed across all clusters, so we need to add up all the total from each cluster + // This also needs to account for having no data + reduce_script: ` + Map result = [:]; + for (Map m : states.toArray()) { + if (m !== null) { + for (String k : m.keySet()) { + result.put(k, result.containsKey(k) ? result.get(k) + m.get(k) : m.get(k)); + } + } + } + return result; + `, + }, +}; + export async function getTotalCountAggregations( esClient: ElasticsearchClient, kibanaInex: string @@ -260,4 +319,130 @@ function replaceFirstAndLastDotSymbols(strToReplace: string) { return hasLastSymbolDot ? `${appliedString.slice(0, -1)}__` : appliedString; } -// TODO: Implement executions count telemetry with eventLog, when it will write to index +export async function getExecutionsPerDayCount( + esClient: ElasticsearchClient, + eventLogIndex: string +) { + const { body: searchResult } = await esClient.search({ + index: eventLogIndex, + size: 0, + body: { + query: { + bool: { + filter: { + bool: { + must: [ + { + term: { 'event.action': 'execute' }, + }, + { + term: { 'event.provider': 'alerting' }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d', + }, + }, + }, + ], + }, + }, + }, + }, + aggs: { + byRuleTypeId: ruleTypeExecutionsMetric, + failuresByReason: ruleTypeFailureExecutionsMetric, + avgDuration: { avg: { field: 'event.duration' } }, + }, + }, + }); + + const executionsAggregations = searchResult.aggregations as { + byRuleTypeId: { + value: { ruleTypes: Record; ruleTypesDuration: Record }; + }; + }; + + const aggsAvgExecutionTime = Math.round( + // @ts-expect-error aggegation type is not specified + // convert nanoseconds to milliseconds + searchResult.aggregations.avgDuration.value / (1000 * 1000) + ); + + const executionFailuresAggregations = searchResult.aggregations as { + failuresByReason: { value: { reasons: Record> } }; + }; + + return { + countTotal: Object.keys(executionsAggregations.byRuleTypeId.value.ruleTypes).reduce( + (total: number, key: string) => + parseInt(executionsAggregations.byRuleTypeId.value.ruleTypes[key], 10) + total, + 0 + ), + countByType: Object.keys(executionsAggregations.byRuleTypeId.value.ruleTypes).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (obj: any, key: string) => ({ + ...obj, + [replaceFirstAndLastDotSymbols(key)]: + executionsAggregations.byRuleTypeId.value.ruleTypes[key], + }), + {} + ), + countTotalFailures: Object.keys( + executionFailuresAggregations.failuresByReason.value.reasons + ).reduce((total: number, reason: string) => { + const byRuleTypesRefs = executionFailuresAggregations.failuresByReason.value.reasons[reason]; + const countByRuleTypes = Object.keys(byRuleTypesRefs).reduce( + (totalByType, ruleType) => parseInt(byRuleTypesRefs[ruleType] + totalByType, 10), + 0 + ); + return countByRuleTypes + total; + }, 0), + countFailuresByReason: Object.keys( + executionFailuresAggregations.failuresByReason.value.reasons + ).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (obj: any, reason: string) => { + const byRuleTypesRefs = + executionFailuresAggregations.failuresByReason.value.reasons[reason]; + const countByRuleTypes = Object.keys(byRuleTypesRefs).reduce( + (totalByType, ruleType) => parseInt(byRuleTypesRefs[ruleType] + totalByType, 10), + 0 + ); + return { + ...obj, + [replaceFirstAndLastDotSymbols(reason)]: countByRuleTypes, + }; + }, + {} + ), + countFailuresByReasonByType: Object.keys( + executionFailuresAggregations.failuresByReason.value.reasons + ).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (obj: any, key: string) => ({ + ...obj, + [replaceFirstAndLastDotSymbols(key)]: + executionFailuresAggregations.failuresByReason.value.reasons[key], + }), + {} + ), + avgExecutionTime: aggsAvgExecutionTime, + avgExecutionTimeByType: Object.keys(executionsAggregations.byRuleTypeId.value.ruleTypes).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (obj: any, key: string) => ({ + ...obj, + [replaceFirstAndLastDotSymbols(key)]: Math.round( + executionsAggregations.byRuleTypeId.value.ruleTypesDuration[key] / + parseInt(executionsAggregations.byRuleTypeId.value.ruleTypes[key], 10) + ), + }), + {} + ), + }; +} diff --git a/x-pack/plugins/alerting/server/usage/alerts_usage_collector.ts b/x-pack/plugins/alerting/server/usage/alerts_usage_collector.ts index e9405c51dbf15..e5b25ea75fc1c 100644 --- a/x-pack/plugins/alerting/server/usage/alerts_usage_collector.ts +++ b/x-pack/plugins/alerting/server/usage/alerts_usage_collector.ts @@ -50,6 +50,26 @@ const byTypeSchema: MakeSchemaFrom['count_by_type'] = { xpack__ml__anomaly_detection_jobs_health: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention }; +const byReasonSchema: MakeSchemaFrom['count_rules_executions_failured_by_reason_per_day'] = + { + // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) + DYNAMIC_KEY: { type: 'long' }, + read: { type: 'long' }, + decrypt: { type: 'long' }, + license: { type: 'long' }, + unknown: { type: 'long' }, + }; + +const byReasonSchemaByType: MakeSchemaFrom['count_rules_executions_failured_by_reason_by_type_per_day'] = + { + // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) + DYNAMIC_KEY: byTypeSchema, + read: byTypeSchema, + decrypt: byTypeSchema, + license: byTypeSchema, + unknown: byTypeSchema, + }; + export function createAlertsUsageCollector( usageCollection: UsageCollectionSetup, taskManager: Promise @@ -92,6 +112,13 @@ export function createAlertsUsageCollector( count_active_by_type: {}, count_by_type: {}, count_rules_namespaces: 0, + count_rules_executions_per_day: 0, + count_rules_executions_by_type_per_day: {}, + count_rules_executions_failured_per_day: 0, + count_rules_executions_failured_by_reason_per_day: {}, + count_rules_executions_failured_by_reason_by_type_per_day: {}, + avg_execution_time_per_day: 0, + avg_execution_time_by_type_per_day: {}, }; } }, @@ -117,6 +144,13 @@ export function createAlertsUsageCollector( count_active_by_type: byTypeSchema, count_by_type: byTypeSchema, count_rules_namespaces: { type: 'long' }, + count_rules_executions_per_day: { type: 'long' }, + count_rules_executions_by_type_per_day: byTypeSchema, + count_rules_executions_failured_per_day: { type: 'long' }, + count_rules_executions_failured_by_reason_per_day: byReasonSchema, + count_rules_executions_failured_by_reason_by_type_per_day: byReasonSchemaByType, + avg_execution_time_per_day: { type: 'long' }, + avg_execution_time_by_type_per_day: byTypeSchema, }, }); } diff --git a/x-pack/plugins/alerting/server/usage/task.ts b/x-pack/plugins/alerting/server/usage/task.ts index 9d39b3765cb5d..2fbd56c105c31 100644 --- a/x-pack/plugins/alerting/server/usage/task.ts +++ b/x-pack/plugins/alerting/server/usage/task.ts @@ -7,13 +7,18 @@ import { Logger, CoreSetup } from 'kibana/server'; import moment from 'moment'; +import { IEventLogService } from '../../../event_log/server'; import { RunContext, TaskManagerSetupContract, TaskManagerStartContract, } from '../../../task_manager/server'; -import { getTotalCountAggregations, getTotalCountInUse } from './alerts_telemetry'; +import { + getTotalCountAggregations, + getTotalCountInUse, + getExecutionsPerDayCount, +} from './alerts_telemetry'; export const TELEMETRY_TASK_TYPE = 'alerting_telemetry'; @@ -23,9 +28,10 @@ export function initializeAlertingTelemetry( logger: Logger, core: CoreSetup, taskManager: TaskManagerSetupContract, - kibanaIndex: string + kibanaIndex: string, + eventLog: IEventLogService ) { - registerAlertingTelemetryTask(logger, core, taskManager, kibanaIndex); + registerAlertingTelemetryTask(logger, core, taskManager, kibanaIndex, eventLog); } export function scheduleAlertingTelemetry(logger: Logger, taskManager?: TaskManagerStartContract) { @@ -38,13 +44,14 @@ function registerAlertingTelemetryTask( logger: Logger, core: CoreSetup, taskManager: TaskManagerSetupContract, - kibanaIndex: string + kibanaIndex: string, + eventLog: IEventLogService ) { taskManager.registerTaskDefinitions({ [TELEMETRY_TASK_TYPE]: { title: 'Alerting usage fetch task', timeout: '5m', - createTaskRunner: telemetryTaskRunner(logger, core, kibanaIndex), + createTaskRunner: telemetryTaskRunner(logger, core, kibanaIndex, eventLog), }, }); } @@ -62,9 +69,15 @@ async function scheduleTasks(logger: Logger, taskManager: TaskManagerStartContra } } -export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex: string) { +export function telemetryTaskRunner( + logger: Logger, + core: CoreSetup, + kibanaIndex: string, + eventLog: IEventLogService +) { return ({ taskInstance }: RunContext) => { const { state } = taskInstance; + const eventLogIndex = eventLog.getIndexPattern(); const getEsClient = () => core.getStartServices().then( ([ @@ -80,8 +93,9 @@ export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex return Promise.all([ getTotalCountAggregations(esClient, kibanaIndex), getTotalCountInUse(esClient, kibanaIndex), + getExecutionsPerDayCount(esClient, eventLogIndex), ]) - .then(([totalCountAggregations, totalInUse]) => { + .then(([totalCountAggregations, totalInUse, totalExecutions]) => { return { state: { runs: (state.runs || 0) + 1, @@ -90,6 +104,15 @@ export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex count_active_total: totalInUse.countTotal, count_disabled_total: totalCountAggregations.count_total - totalInUse.countTotal, count_rules_namespaces: totalInUse.countNamespaces, + count_rules_executions_per_day: totalExecutions.countTotal, + count_rules_executions_by_type_per_day: totalExecutions.countByType, + count_rules_executions_failured_per_day: totalExecutions.countTotalFailures, + count_rules_executions_failured_by_reason_per_day: + totalExecutions.countFailuresByReason, + count_rules_executions_failured_by_reason_by_type_per_day: + totalExecutions.countFailuresByReasonByType, + avg_execution_time_per_day: totalExecutions.avgExecutionTime, + avg_execution_time_by_type_per_day: totalExecutions.avgExecutionTimeByType, }, runAt: getNextMidnight(), }; diff --git a/x-pack/plugins/alerting/server/usage/types.ts b/x-pack/plugins/alerting/server/usage/types.ts index 0e489893a1bbc..50d9b80c44b70 100644 --- a/x-pack/plugins/alerting/server/usage/types.ts +++ b/x-pack/plugins/alerting/server/usage/types.ts @@ -12,6 +12,13 @@ export interface AlertsUsage { count_by_type: Record; count_active_by_type: Record; count_rules_namespaces: number; + count_rules_executions_per_day: number; + count_rules_executions_by_type_per_day: Record; + count_rules_executions_failured_per_day: number; + count_rules_executions_failured_by_reason_per_day: Record; + count_rules_executions_failured_by_reason_by_type_per_day: Record>; + avg_execution_time_per_day: number; + avg_execution_time_by_type_per_day: Record; throttle_time: { min: number; avg: number; diff --git a/x-pack/plugins/event_log/server/event_log_service.mock.ts b/x-pack/plugins/event_log/server/event_log_service.mock.ts index a3ad81eb0e5a6..f43f3e025a7cf 100644 --- a/x-pack/plugins/event_log/server/event_log_service.mock.ts +++ b/x-pack/plugins/event_log/server/event_log_service.mock.ts @@ -17,6 +17,7 @@ const createEventLogServiceMock = () => { getProviderActions: jest.fn(), registerSavedObjectProvider: jest.fn(), getLogger: jest.fn().mockReturnValue(eventLoggerMock.create()), + getIndexPattern: jest.fn(), }; return mock; }; diff --git a/x-pack/plugins/event_log/server/event_log_service.ts b/x-pack/plugins/event_log/server/event_log_service.ts index 993631ed3ca8a..2cf22b0f20755 100644 --- a/x-pack/plugins/event_log/server/event_log_service.ts +++ b/x-pack/plugins/event_log/server/event_log_service.ts @@ -92,6 +92,10 @@ export class EventLogService implements IEventLogService { return this.savedObjectProviderRegistry.registerProvider(type, provider); } + getIndexPattern() { + return this.esContext.esNames.indexPattern; + } + getLogger(initialProperties: IEvent): IEventLogger { return new EventLogger({ esContext: this.esContext, diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index c50bed7e01dd5..6ffde7fd6dbe0 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -33,6 +33,7 @@ export interface IEventLogService { getProviderActions(): Map>; registerSavedObjectProvider(type: string, provider: SavedObjectProvider): void; getLogger(properties: IEvent): IEventLogger; + getIndexPattern(): string; } export interface IEventLogClientService { diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 2786cab4fe963..8ac619d479bef 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -100,6 +100,49 @@ } } }, + "count_actions_executions_per_day": { + "type": "long" + }, + "count_actions_executions_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__email": { + "type": "long" + }, + "__index": { + "type": "long" + }, + "__pagerduty": { + "type": "long" + }, + "__swimlane": { + "type": "long" + }, + "__server-log": { + "type": "long" + }, + "__slack": { + "type": "long" + }, + "__webhook": { + "type": "long" + }, + "__servicenow": { + "type": "long" + }, + "__jira": { + "type": "long" + }, + "__resilient": { + "type": "long" + }, + "__teams": { + "type": "long" + } + } + }, "count_active_email_connectors_by_service_type": { "properties": { "DYNAMIC_KEY": { @@ -127,6 +170,92 @@ }, "count_actions_namespaces": { "type": "long" + }, + "count_actions_executions_failed_per_day": { + "type": "long" + }, + "count_actions_executions_failed_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__email": { + "type": "long" + }, + "__index": { + "type": "long" + }, + "__pagerduty": { + "type": "long" + }, + "__swimlane": { + "type": "long" + }, + "__server-log": { + "type": "long" + }, + "__slack": { + "type": "long" + }, + "__webhook": { + "type": "long" + }, + "__servicenow": { + "type": "long" + }, + "__jira": { + "type": "long" + }, + "__resilient": { + "type": "long" + }, + "__teams": { + "type": "long" + } + } + }, + "avg_execution_time_per_day": { + "type": "long" + }, + "avg_execution_time_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__email": { + "type": "long" + }, + "__index": { + "type": "long" + }, + "__pagerduty": { + "type": "long" + }, + "__swimlane": { + "type": "long" + }, + "__server-log": { + "type": "long" + }, + "__slack": { + "type": "long" + }, + "__webhook": { + "type": "long" + }, + "__servicenow": { + "type": "long" + }, + "__jira": { + "type": "long" + }, + "__resilient": { + "type": "long" + }, + "__teams": { + "type": "long" + } + } } } }, @@ -352,6 +481,633 @@ }, "count_rules_namespaces": { "type": "long" + }, + "count_rules_executions_per_day": { + "type": "long" + }, + "count_rules_executions_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "count_rules_executions_failured_per_day": { + "type": "long" + }, + "count_rules_executions_failured_by_reason_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "read": { + "type": "long" + }, + "decrypt": { + "type": "long" + }, + "license": { + "type": "long" + }, + "unknown": { + "type": "long" + } + } + }, + "count_rules_executions_failured_by_reason_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "read": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "decrypt": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "license": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "unknown": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + } + } + }, + "avg_execution_time_per_day": { + "type": "long" + }, + "avg_execution_time_by_type_per_day": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } } } },