From 59aae058ad0891e4bbad168f3b2dedc6fa0ada12 Mon Sep 17 00:00:00 2001 From: Sergi Massaneda Date: Thu, 6 Feb 2025 11:58:17 +0100 Subject: [PATCH] implement all telemetry events --- .../telemetry/events/siem_migrations/index.ts | 55 +++++++---------- .../telemetry/events/siem_migrations/types.ts | 55 ++++++++--------- .../steps/lookups/lookups_data_input.tsx | 6 +- .../steps/macros/macros_data_input.tsx | 5 +- .../steps/rules/rules_data_input.tsx | 6 +- .../rules/service/rule_migrations_service.ts | 43 +++++++++---- .../rules/service/telemetry.ts | 60 ++++++++++--------- 7 files changed, 124 insertions(+), 106 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/index.ts b/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/index.ts index 8d6818690d914..8c0d9ebc561ad 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/index.ts @@ -71,7 +71,7 @@ const eventSchemas: SiemMigrationsTelemetryEventSchemas = { }, }, }, - [SiemMigrationsEventTypes.SetupMigrationOpenUpload]: { + [SiemMigrationsEventTypes.SetupMigrationOpenResources]: { ...migrationIdSchema, missingResourcesCount: { type: 'integer', @@ -81,25 +81,16 @@ const eventSchemas: SiemMigrationsTelemetryEventSchemas = { }, }, }, - [SiemMigrationsEventTypes.SetupRulesQueryCopied]: { - connectorId: { - type: 'keyword', - _meta: { - description: 'Connector ID', - optional: false, - }, - }, - }, - [SiemMigrationsEventTypes.SetupRulesUploaded]: { + [SiemMigrationsEventTypes.SetupMigrationCreated]: { ...baseResultActionSchema, - connectorId: { - type: 'keyword', + migrationId: { + ...migrationIdSchema.migrationId, _meta: { - description: 'Connector ID', - optional: false, + ...migrationIdSchema.migrationId._meta, + optional: true, // Error case does not have the migration ID }, }, - count: { + rulesCount: { type: 'integer', _meta: { description: 'Number of rules uploaded', @@ -107,37 +98,35 @@ const eventSchemas: SiemMigrationsTelemetryEventSchemas = { }, }, }, + [SiemMigrationsEventTypes.SetupRulesQueryCopied]: { + migrationId: { + ...migrationIdSchema.migrationId, + _meta: { + ...migrationIdSchema.migrationId._meta, + optional: true, // Migration is not usually created yet when the query is copied + }, + }, + }, [SiemMigrationsEventTypes.SetupMacrosQueryCopied]: { ...migrationIdSchema, }, - [SiemMigrationsEventTypes.SetupMacrosUploaded]: { - ...baseResultActionSchema, + [SiemMigrationsEventTypes.SetupLookupNameCopied]: { ...migrationIdSchema, - count: { - type: 'integer', - _meta: { - description: 'Number of macros uploaded', - optional: false, - }, - }, }, - [SiemMigrationsEventTypes.SetupLookupsQueryCopied]: { + [SiemMigrationsEventTypes.SetupResourcesUploaded]: { + ...baseResultActionSchema, ...migrationIdSchema, - lookupName: { + type: { type: 'keyword', _meta: { - description: 'The name of the lookup copied', + description: `Resource type, can be one of 'macro' or 'lookup'`, optional: false, }, }, - }, - [SiemMigrationsEventTypes.SetupLookupsUploaded]: { - ...baseResultActionSchema, - ...migrationIdSchema, count: { type: 'integer', _meta: { - description: 'Number of lookups uploaded', + description: 'Number of resources uploaded', optional: false, }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/types.ts b/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/types.ts index eb15223f2223d..7bb1444e1abab 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/lib/telemetry/events/siem_migrations/types.ts @@ -6,22 +6,22 @@ */ import type { RootSchema } from '@kbn/core/public'; +import type { RuleMigrationResourceType } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { SiemMigrationRetryFilter } from '../../../../../../common/siem_migrations/constants'; export enum SiemMigrationsEventTypes { - SetupConnectorSelected = '[SIEM_Migrations] Setup connector selected', - SetupMigrationOpenNew = '[SIEM_Migrations] Setup rule migration opened', - SetupMigrationOpenUpload = '[SIEM_Migrations] Setup rule migration opened upload', - SetupRulesQueryCopied = '[SIEM_Migrations] Setup rules query copied', - SetupRulesUploaded = '[SIEM_Migrations] Setup rules uploaded', - SetupMacrosQueryCopied = '[SIEM_Migrations] Setup macros query copied', - SetupMacrosUploaded = '[SIEM_Migrations] Setup macros uploaded', - SetupLookupsQueryCopied = '[SIEM_Migrations] Setup lookups query copied', - SetupLookupsUploaded = '[SIEM_Migrations] Setup lookups uploaded', - StartTranslation = '[SIEM_Migrations] Start translation', - TranslatedRuleUpdate = '[SIEM_Migrations] Translated rule update', - TranslatedRuleInstall = '[SIEM_Migrations] Translated rule install', - TranslatedRuleBulkInstall = '[SIEM_Migrations] Translated rule bulk install', + SetupConnectorSelected = 'siem_migrations_setup_connector_selected', + SetupMigrationOpenNew = 'siem_migrations_setup_rules_migration_open_new', + SetupMigrationCreated = 'siem_migrations_setup_rules_migration_created', + SetupResourcesUploaded = 'siem_migrations_setup_rules_resources_uploaded', + SetupMigrationOpenResources = 'siem_migrations_setup_rules_migration_open_resources', + SetupRulesQueryCopied = 'siem_migrations_setup_rules_query_copied', + SetupMacrosQueryCopied = 'siem_migrations_setup_rules_macros_query_copied', + SetupLookupNameCopied = 'siem_migrations_setup_rules_lookup_name_copied', + StartTranslation = 'siem_migrations_start_rules_translation', + TranslatedRuleUpdate = 'siem_migrations_translated_rule_update', + TranslatedRuleInstall = 'siem_migrations_translated_rule_install', + TranslatedRuleBulkInstall = 'siem_migrations_translated_rule_bulk_install', } export interface BaseResultActionParams { @@ -42,30 +42,26 @@ interface ReportSetupConnectorSelectedActionParams { interface ReportSetupMigrationOpenNewActionParams { isFirstMigration: boolean; } -interface ReportSetupMigrationOpenUploadActionParams { +interface ReportSetupMigrationOpenResourcesActionParams { migrationId: string; missingResourcesCount: number; } interface ReportSetupRulesQueryCopiedActionParams { - connectorId: string; + migrationId?: string; } -interface ReportSetupRulesUploadedActionParams extends BaseResultActionParams { - connectorId: string; - count: number; +interface ReportSetupMigrationCreatedActionParams extends BaseResultActionParams { + migrationId?: string; + rulesCount: number; } interface ReportSetupMacrosQueryCopiedActionParams { migrationId: string; } -interface ReportSetupMacrosUploadedActionParams extends BaseResultActionParams { - migrationId: string; - count: number; -} -interface ReportSetupLookupsQueryCopiedActionParams { +interface ReportSetupLookupNameCopiedActionParams { migrationId: string; - lookupName: string; } -interface ReportSetupLookupsUploadedActionParams extends BaseResultActionParams { +interface ReportSetupResourcesUploadedActionParams extends BaseResultActionParams { migrationId: string; + type: RuleMigrationResourceType; count: number; } @@ -103,13 +99,12 @@ interface ReportTranslatedRuleBulkInstallActionParams { export interface SiemMigrationsTelemetryEventsMap { [SiemMigrationsEventTypes.SetupConnectorSelected]: ReportSetupConnectorSelectedActionParams; [SiemMigrationsEventTypes.SetupMigrationOpenNew]: ReportSetupMigrationOpenNewActionParams; - [SiemMigrationsEventTypes.SetupMigrationOpenUpload]: ReportSetupMigrationOpenUploadActionParams; + [SiemMigrationsEventTypes.SetupMigrationOpenResources]: ReportSetupMigrationOpenResourcesActionParams; [SiemMigrationsEventTypes.SetupRulesQueryCopied]: ReportSetupRulesQueryCopiedActionParams; - [SiemMigrationsEventTypes.SetupRulesUploaded]: ReportSetupRulesUploadedActionParams; + [SiemMigrationsEventTypes.SetupMigrationCreated]: ReportSetupMigrationCreatedActionParams; [SiemMigrationsEventTypes.SetupMacrosQueryCopied]: ReportSetupMacrosQueryCopiedActionParams; - [SiemMigrationsEventTypes.SetupMacrosUploaded]: ReportSetupMacrosUploadedActionParams; - [SiemMigrationsEventTypes.SetupLookupsQueryCopied]: ReportSetupLookupsQueryCopiedActionParams; - [SiemMigrationsEventTypes.SetupLookupsUploaded]: ReportSetupLookupsUploadedActionParams; + [SiemMigrationsEventTypes.SetupLookupNameCopied]: ReportSetupLookupNameCopiedActionParams; + [SiemMigrationsEventTypes.SetupResourcesUploaded]: ReportSetupResourcesUploadedActionParams; [SiemMigrationsEventTypes.StartTranslation]: ReportStartTranslationActionParams; [SiemMigrationsEventTypes.TranslatedRuleUpdate]: ReportTranslatedRuleUpdateActionParams; [SiemMigrationsEventTypes.TranslatedRuleInstall]: ReportTranslatedRuleInstallActionParams; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index cfe88caafc652..b9b1e26e0e0d6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -15,6 +15,7 @@ import { EuiTitle, } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationResourceData, RuleMigrationTaskStats, @@ -94,6 +95,7 @@ const END = 10 as const; type SubStep = 1 | 2 | typeof END; export const LookupsDataInputSubSteps = React.memo( ({ migrationStats, missingLookups, onAllLookupsCreated }) => { + const { telemetry } = useKibana().services.siemMigrations.rules; const [subStep, setSubStep] = useState(1); const [uploadedLookups, setUploadedLookups] = useState({}); @@ -114,7 +116,9 @@ export const LookupsDataInputSubSteps = React.memo { setSubStep(2); - }, []); + telemetry.reportSetupLookupNameCopied({ migrationId: migrationStats.id }); + }, [telemetry, migrationStats.id]); + const copyStep = useMissingLookupsListStep({ status: getStatus(1, subStep), migrationStats, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index ebbffb6d7f6d6..34fc2a20c9e76 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -8,6 +8,7 @@ import type { EuiStepProps } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStepNumber, EuiTitle } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; +import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { OnResourcesCreated, OnMissingResourcesFetched } from '../../types'; import { getStatus } from '../common/get_status'; @@ -75,12 +76,14 @@ const END = 10 as const; type SubStep = 1 | 2 | 3 | typeof END; export const MacrosDataInputSubSteps = React.memo( ({ migrationStats, missingMacros, onMissingResourcesFetched }) => { + const { telemetry } = useKibana().services.siemMigrations.rules; const [subStep, setSubStep] = useState(missingMacros.length ? 1 : 3); // Copy query step const onCopied = useCallback(() => { setSubStep(2); - }, []); + telemetry.reportSetupMacrosQueryCopied({ migrationId: migrationStats.id }); + }, [telemetry, migrationStats.id]); const copyStep = useCopyExportQueryStep({ status: getStatus(1, subStep), onCopied }); // Upload macros step diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 0c919a2db7a5d..3c9d4a270b195 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -8,6 +8,7 @@ import type { EuiStepProps } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStepNumber, EuiTitle } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; +import { useKibana } from '../../../../../../common/lib/kibana'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { OnMigrationCreated, OnMissingResourcesFetched } from '../../types'; import * as i18n from './translations'; @@ -72,12 +73,15 @@ const END = 10 as const; type SubStep = 1 | 2 | 3 | typeof END; export const RulesDataInputSubSteps = React.memo( ({ migrationStats, onMigrationCreated, onMissingResourcesFetched }) => { + const { telemetry } = useKibana().services.siemMigrations.rules; const [subStep, setSubStep] = useState(migrationStats ? 3 : 1); // Copy query step const onCopied = useCallback(() => { setSubStep(2); - }, []); + telemetry.reportSetupRulesQueryCopied({ migrationId: migrationStats?.id }); + }, [telemetry, migrationStats?.id]); + const copyStep = useCopyExportQueryStep({ status: getStatus(1, subStep), onCopied }); // Upload rules step diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index f9a41521a5936..596212ea6061c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -102,30 +102,47 @@ export class SiemRulesMigrationsService { } public async createRuleMigration(body: CreateRuleMigrationRequestBody): Promise { - if (body.length === 0) { + const rulesCount = body.length; + if (rulesCount === 0) { throw new Error(i18n.EMPTY_RULES_ERROR); } - // Batching creation to avoid hitting the max payload size limit of the API - let migrationId: string | undefined; - for (let i = 0; i < body.length; i += CREATE_MIGRATION_BODY_BATCH_SIZE) { - const bodyBatch = body.slice(i, i + CREATE_MIGRATION_BODY_BATCH_SIZE); - const response = await createRuleMigration({ migrationId, body: bodyBatch }); - migrationId = response.migration_id; + + try { + let migrationId: string | undefined; + // Batching creation to avoid hitting the max payload size limit of the API + for (let i = 0; i < rulesCount; i += CREATE_MIGRATION_BODY_BATCH_SIZE) { + const bodyBatch = body.slice(i, i + CREATE_MIGRATION_BODY_BATCH_SIZE); + const response = await createRuleMigration({ migrationId, body: bodyBatch }); + migrationId = response.migration_id; + } + this.telemetry.reportSetupMigrationCreated({ migrationId, rulesCount }); + return migrationId as string; + } catch (error) { + this.telemetry.reportSetupMigrationCreated({ rulesCount, error }); + throw error; } - return migrationId as string; } public async upsertMigrationResources( migrationId: string, body: UpsertRuleMigrationResourcesRequestBody ): Promise { - if (body.length === 0) { + const count = body.length; + if (count === 0) { throw new Error(i18n.EMPTY_RULES_ERROR); } - // Batching creation to avoid hitting the max payload size limit of the API - for (let i = 0; i < body.length; i += CREATE_MIGRATION_BODY_BATCH_SIZE) { - const bodyBatch = body.slice(i, i + CREATE_MIGRATION_BODY_BATCH_SIZE); - await upsertMigrationResources({ migrationId, body: bodyBatch }); + // We assume all resources are of the same type. There is no use case for mixing types in a single upload + const type = body[0].type; + try { + // Batching creation to avoid hitting the max payload size limit of the API + for (let i = 0; i < count; i += CREATE_MIGRATION_BODY_BATCH_SIZE) { + const bodyBatch = body.slice(i, i + CREATE_MIGRATION_BODY_BATCH_SIZE); + await upsertMigrationResources({ migrationId, body: bodyBatch }); + } + this.telemetry.reportSetupResourceUploaded({ migrationId, type, count }); + } catch (error) { + this.telemetry.reportSetupResourceUploaded({ migrationId, type, count, error }); + throw error; } } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/telemetry.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/telemetry.ts index 3b1e31156b0e7..ceec2d68041fc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/telemetry.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/telemetry.ts @@ -7,7 +7,10 @@ import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; import type { SiemMigrationRetryFilter } from '../../../../common/siem_migrations/constants'; -import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import type { + RuleMigration, + RuleMigrationResourceType, +} from '../../../../common/siem_migrations/model/rule_migration.gen'; import type { TelemetryServiceStart } from '../../../common/lib/telemetry'; import type { BaseResultActionParams } from '../../../common/lib/telemetry/events/siem_migrations/types'; import { SiemMigrationsEventTypes } from '../../../common/lib/telemetry/events/siem_migrations/types'; @@ -37,46 +40,50 @@ export class SiemRulesMigrationsTelemetry { migrationId: string; missingResourcesCount: number; }) => { - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMigrationOpenUpload, params); + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMigrationOpenResources, params); }; - reportSetupRulesQueryCopied = (params: { connectorId: string }) => { - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupRulesQueryCopied, params); + reportSetupMigrationCreated = (params: { + migrationId?: string; + rulesCount: number; + error?: Error; + }) => { + const { migrationId, rulesCount, error } = params; + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMigrationCreated, { + migrationId, + rulesCount, + ...this.getBaseResultParams(error), + }); }; - reportSetupRulesUploaded = (params: { connectorId: string; count: number; error?: Error }) => { - const { connectorId, count, error } = params; - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupRulesUploaded, { - connectorId, + reportSetupResourceUploaded = (params: { + migrationId: string; + type: RuleMigrationResourceType; + count: number; + error?: Error; + }) => { + const { migrationId, type, count, error } = params; + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupResourcesUploaded, { + migrationId, count, + type, ...this.getBaseResultParams(error), }); }; - reportSetupMacrosQueryCopied = (params: { migrationId: string }) => { - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMacrosQueryCopied, params); - }; - - reportSetupMacrosUploaded = (params: { migrationId: string; count: number; error?: Error }) => { - const { migrationId, count, error } = params; - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMacrosUploaded, { + reportSetupRulesQueryCopied = (params: { migrationId?: string }) => { + const { migrationId } = params; + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupRulesQueryCopied, { migrationId, - count, - ...this.getBaseResultParams(error), }); }; - reportSetupLookupsQueryCopied = (params: { migrationId: string; lookupName: string }) => { - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupLookupsQueryCopied, params); + reportSetupMacrosQueryCopied = (params: { migrationId: string }) => { + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupMacrosQueryCopied, params); }; - reportSetupLookupsUploaded = (params: { migrationId: string; count: number; error?: Error }) => { - const { migrationId, count, error } = params; - this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupLookupsUploaded, { - migrationId, - count, - ...this.getBaseResultParams(error), - }); + reportSetupLookupNameCopied = (params: { migrationId: string }) => { + this.telemetryService.reportEvent(SiemMigrationsEventTypes.SetupLookupNameCopied, params); }; reportStartTranslation = (params: { @@ -99,7 +106,6 @@ export class SiemRulesMigrationsTelemetry { reportTranslatedRuleUpdate = (params: { ruleMigration: RuleMigration; error?: Error }) => { const { ruleMigration, error } = params; - this.telemetryService.reportEvent(SiemMigrationsEventTypes.TranslatedRuleUpdate, { migrationId: ruleMigration.migration_id, ruleMigrationId: ruleMigration.id,