Skip to content

Commit

Permalink
[SecuritySolution] Generic reportEvents for EBT Telemetry (#197079)
Browse files Browse the repository at this point in the history
## Summary

1. Removing the custom EBT events:
https://github.com/elastic/kibana/pull/197079/files#diff-7beaf4f2d7c25c8913607b5dbc6e1ad0027f6ffacddafe4c675c775c3e7ae903L55
2. Use `reportEvent` for all the Security Solution EBT events.

### Checklist

Delete any items that are not applicable to this PR.


- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
  • Loading branch information
angorayc authored Nov 11, 2024
1 parent aeef51f commit 3b0c380
Show file tree
Hide file tree
Showing 97 changed files with 883 additions and 1,223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { StartServices } from '../../types';
import { enhanceActionWithTelemetry } from './telemetry';
import { createAction } from '@kbn/ui-actions-plugin/public';
import type { CellActionExecutionContext } from '@kbn/cell-actions';
import { AppEventTypes } from '../../common/lib/telemetry';

const actionId = 'test_action_id';
const displayName = 'test-actions';
Expand All @@ -29,13 +30,13 @@ const context = {

describe('enhanceActionWithTelemetry', () => {
it('calls telemetry report when the action is executed', () => {
const telemetry = { reportCellActionClicked: jest.fn() };
const telemetry = { reportEvent: jest.fn() };
const services = { telemetry } as unknown as StartServices;

const enhancedAction = enhanceActionWithTelemetry(action, services);
enhancedAction.execute(context);

expect(telemetry.reportCellActionClicked).toHaveBeenCalledWith({
expect(telemetry.reportEvent).toHaveBeenCalledWith(AppEventTypes.CellActionClicked, {
displayName,
actionId,
fieldName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { CellAction, CellActionExecutionContext } from '@kbn/cell-actions';
import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
import type { StartServices } from '../../types';
import type { SecurityCellActionExecutionContext } from './types';
import { AppEventTypes } from '../../common/lib/telemetry';

export const enhanceActionWithTelemetry = (
action: CellAction<CellActionExecutionContext>,
Expand All @@ -19,7 +20,7 @@ export const enhanceActionWithTelemetry = (
const enhancedExecute = (
context: ActionExecutionContext<SecurityCellActionExecutionContext>
): Promise<void> => {
telemetry.reportCellActionClicked({
telemetry.reportEvent(AppEventTypes.CellActionClicked, {
actionId: rest.id,
displayName: rest.getDisplayName(context),
fieldName: context.data.map(({ field }) => field.name).join(', '),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { useAssistantTelemetry } from '.';
import { BASE_SECURITY_CONVERSATIONS } from '../content/conversations';
import { createTelemetryServiceMock } from '../../common/lib/telemetry/telemetry_service.mock';
import { AssistantEventTypes } from '../../common/lib/telemetry';

const customId = `My Convo`;
const mockedConversations = {
Expand All @@ -20,15 +21,9 @@ const mockedConversations = {
messages: [],
},
};
const reportAssistantInvoked = jest.fn();
const reportAssistantMessageSent = jest.fn();
const reportAssistantQuickPrompt = jest.fn();

const mockedTelemetry = {
...createTelemetryServiceMock(),
reportAssistantInvoked,
reportAssistantMessageSent,
reportAssistantQuickPrompt,
reportAssistantSettingToggled: () => {},
};

jest.mock('../../common/lib/kibana', () => {
Expand All @@ -55,9 +50,9 @@ jest.mock('@kbn/elastic-assistant', () => ({
}));

const trackingFns = [
'reportAssistantInvoked',
'reportAssistantMessageSent',
'reportAssistantQuickPrompt',
{ name: 'reportAssistantInvoked', eventType: AssistantEventTypes.AssistantInvoked },
{ name: 'reportAssistantMessageSent', eventType: AssistantEventTypes.AssistantMessageSent },
{ name: 'reportAssistantQuickPrompt', eventType: AssistantEventTypes.AssistantQuickPrompt },
];

describe('useAssistantTelemetry', () => {
Expand All @@ -67,7 +62,7 @@ describe('useAssistantTelemetry', () => {
it('should return the expected telemetry object with tracking functions', () => {
const { result } = renderHook(() => useAssistantTelemetry());
trackingFns.forEach((fn) => {
expect(result.current).toHaveProperty(fn);
expect(result.current).toHaveProperty(fn.name);
});
});

Expand All @@ -76,11 +71,11 @@ describe('useAssistantTelemetry', () => {
const { result } = renderHook(() => useAssistantTelemetry());
const validId = Object.keys(mockedConversations)[0];
// @ts-ignore
const trackingFn = result.current[fn];
const trackingFn = result.current[fn.name];
await trackingFn({ conversationId: validId, invokedBy: 'shortcut' });
// @ts-ignore
const trackingMockedFn = mockedTelemetry[fn];
expect(trackingMockedFn).toHaveBeenCalledWith({
const trackingMockedFn = mockedTelemetry.reportEvent;
expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, {
conversationId: validId,
invokedBy: 'shortcut',
});
Expand All @@ -89,11 +84,11 @@ describe('useAssistantTelemetry', () => {
it('Should call tracking with "Custom" id when tracking is called with an isDefault=false conversation id', async () => {
const { result } = renderHook(() => useAssistantTelemetry());
// @ts-ignore
const trackingFn = result.current[fn];
const trackingFn = result.current[fn.name];
await trackingFn({ conversationId: customId, invokedBy: 'shortcut' });
// @ts-ignore
const trackingMockedFn = mockedTelemetry[fn];
expect(trackingMockedFn).toHaveBeenCalledWith({
const trackingMockedFn = mockedTelemetry.reportEvent;
expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, {
conversationId: 'Custom',
invokedBy: 'shortcut',
});
Expand All @@ -102,11 +97,11 @@ describe('useAssistantTelemetry', () => {
it('Should call tracking with "Custom" id when tracking is called with an unknown conversation id', async () => {
const { result } = renderHook(() => useAssistantTelemetry());
// @ts-ignore
const trackingFn = result.current[fn];
const trackingFn = result.current[fn.name];
await trackingFn({ conversationId: '123', invokedBy: 'shortcut' });
// @ts-ignore
const trackingMockedFn = mockedTelemetry[fn];
expect(trackingMockedFn).toHaveBeenCalledWith({
const trackingMockedFn = mockedTelemetry.reportEvent;
expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, {
conversationId: 'Custom',
invokedBy: 'shortcut',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import { type AssistantTelemetry } from '@kbn/elastic-assistant';
import { useCallback } from 'react';
import { useKibana } from '../../common/lib/kibana';
import { useBaseConversations } from '../use_conversation_store';

import type {
ReportAssistantInvokedParams,
ReportAssistantMessageSentParams,
ReportAssistantQuickPromptParams,
ReportAssistantSettingToggledParams,
} from '../../common/lib/telemetry';
import { AssistantEventTypes } from '../../common/lib/telemetry';
export const useAssistantTelemetry = (): AssistantTelemetry => {
const {
services: { telemetry },
Expand All @@ -27,27 +33,30 @@ export const useAssistantTelemetry = (): AssistantTelemetry => {

const reportTelemetry = useCallback(
async ({
fn,
eventType,
params: { conversationId, ...rest },
}: // eslint-disable-next-line @typescript-eslint/no-explicit-any
any): Promise<{
fn: keyof AssistantTelemetry;
params: AssistantTelemetry[keyof AssistantTelemetry];
}> =>
fn({
}: {
eventType: AssistantEventTypes;
params:
| ReportAssistantInvokedParams
| ReportAssistantMessageSentParams
| ReportAssistantQuickPromptParams;
}) =>
telemetry.reportEvent(eventType, {
...rest,
conversationId: await getAnonymizedConversationTitle(conversationId),
}),
[getAnonymizedConversationTitle]
[getAnonymizedConversationTitle, telemetry]
);

return {
reportAssistantInvoked: (params) =>
reportTelemetry({ fn: telemetry.reportAssistantInvoked, params }),
reportAssistantMessageSent: (params) =>
reportTelemetry({ fn: telemetry.reportAssistantMessageSent, params }),
reportAssistantQuickPrompt: (params) =>
reportTelemetry({ fn: telemetry.reportAssistantQuickPrompt, params }),
reportAssistantSettingToggled: (params) => telemetry.reportAssistantSettingToggled(params),
reportAssistantInvoked: (params: ReportAssistantInvokedParams) =>
reportTelemetry({ eventType: AssistantEventTypes.AssistantInvoked, params }),
reportAssistantMessageSent: (params: ReportAssistantMessageSentParams) =>
reportTelemetry({ eventType: AssistantEventTypes.AssistantMessageSent, params }),
reportAssistantQuickPrompt: (params: ReportAssistantQuickPromptParams) =>
reportTelemetry({ eventType: AssistantEventTypes.AssistantQuickPrompt, params }),
reportAssistantSettingToggled: (params: ReportAssistantSettingToggledParams) =>
telemetry.reportEvent(AssistantEventTypes.AssistantSettingToggled, params),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import * as timelineMarkdownPlugin from '../../common/components/markdown_editor
import { useFetchAlertData } from './use_fetch_alert_data';
import { useUpsellingMessage } from '../../common/hooks/use_upselling';
import { useFetchNotes } from '../../notes/hooks/use_fetch_notes';
import { DocumentEventTypes } from '../../common/lib/telemetry';

const CaseContainerComponent: React.FC = () => {
const { cases, telemetry } = useKibana().services;
Expand All @@ -47,7 +48,7 @@ const CaseContainerComponent: React.FC = () => {
},
},
});
telemetry.reportDetailsFlyoutOpened({
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, {
location: TimelineId.casePage,
panel: 'right',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type { ColumnHeaderOptions, OnRowSelected } from '../../../../../common/t
import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features';
import { useTourContext } from '../../guided_onboarding_tour';
import { AlertsCasesTourSteps, SecurityStepId } from '../../guided_onboarding_tour/tour_config';
import { NotesEventTypes, DocumentEventTypes } from '../../../lib/telemetry';
import { getMappedNonEcsValue } from '../../../utils/get_mapped_non_ecs_value';

export type RowActionProps = EuiDataGridCellValueElementProps & {
Expand Down Expand Up @@ -109,7 +110,7 @@ const RowActionComponent = ({
},
},
});
telemetry.reportDetailsFlyoutOpened({
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, {
location: tableId,
panel: 'right',
});
Expand Down Expand Up @@ -137,10 +138,10 @@ const RowActionComponent = ({
},
},
});
telemetry.reportOpenNoteInExpandableFlyoutClicked({
telemetry.reportEvent(NotesEventTypes.OpenNoteInExpandableFlyoutClicked, {
location: tableId,
});
telemetry.reportDetailsFlyoutOpened({
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, {
location: tableId,
panel: 'left',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
import type { HostsTableType } from '../../../explore/hosts/store/model';
import type { UsersTableType } from '../../../explore/users/store/model';
import { useGetSecuritySolutionLinkProps, withSecuritySolutionLink } from './link_props';
import { EntityEventTypes } from '../../lib/telemetry';

export { useSecuritySolutionLinkProps, type GetSecuritySolutionLinkProps } from './link_props';
export { LinkButton, LinkAnchor } from './helpers';
Expand Down Expand Up @@ -94,7 +95,7 @@ const UserDetailsLinkComponent: React.FC<{

const onClick = useCallback(
(e: SyntheticEvent) => {
telemetry.reportEntityDetailsClicked({ entity: 'user' });
telemetry.reportEvent(EntityEventTypes.EntityDetailsClicked, { entity: 'user' });
const callback = onClickParam ?? goToUsersDetails;
callback(e);
},
Expand Down Expand Up @@ -171,7 +172,7 @@ const HostDetailsLinkComponent: React.FC<HostDetailsLinkProps> = ({

const onClick = useCallback(
(e: SyntheticEvent) => {
telemetry.reportEntityDetailsClicked({ entity: 'host' });
telemetry.reportEvent(EntityEventTypes.EntityDetailsClicked, { entity: 'host' });

const callback = onClickParam ?? goToHostDetails;
callback(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { TestProviders } from '../../../mock';

import type { SecurityJob } from '../types';
import { createTelemetryServiceMock } from '../../../lib/telemetry/telemetry_service.mock';
import { ML_JOB_TELEMETRY_STATUS } from '../../../lib/telemetry';
import { ML_JOB_TELEMETRY_STATUS, EntityEventTypes } from '../../../lib/telemetry';

const wrapper = ({ children }: { children: React.ReactNode }) => (
<TestProviders>{children}</TestProviders>
Expand Down Expand Up @@ -188,14 +188,14 @@ describe('useSecurityJobsHelpers', () => {
await result.current.enableDatafeed(JOB, TIMESTAMP);
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.moduleInstalled,
isElasticJob: true,
jobId,
moduleId,
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.started,
isElasticJob: true,
jobId,
Expand All @@ -211,7 +211,7 @@ describe('useSecurityJobsHelpers', () => {
await result.current.enableDatafeed({ ...JOB, isInstalled: true }, TIMESTAMP);
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.startError,
errorMessage: 'Start job failure - test_error',
isElasticJob: true,
Expand All @@ -228,7 +228,7 @@ describe('useSecurityJobsHelpers', () => {
await result.current.enableDatafeed(JOB, TIMESTAMP);
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.installationError,
errorMessage: 'Create job failure - test_error',
isElasticJob: true,
Expand Down Expand Up @@ -295,7 +295,7 @@ describe('useSecurityJobsHelpers', () => {
await result.current.disableDatafeed({ ...JOB, isInstalled: true });
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.stopped,
isElasticJob: true,
jobId,
Expand All @@ -311,7 +311,7 @@ describe('useSecurityJobsHelpers', () => {
await result.current.disableDatafeed({ ...JOB, isInstalled: true });
});

expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({
expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, {
status: ML_JOB_TELEMETRY_STATUS.stopError,
errorMessage: 'Stop job failure - test_error',
isElasticJob: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
METRIC_TYPE,
ML_JOB_TELEMETRY_STATUS,
TELEMETRY_EVENT,
EntityEventTypes,
track,
} from '../../../lib/telemetry';

Expand Down Expand Up @@ -43,7 +44,7 @@ export const useEnableDataFeed = () => {
jobIdErrorFilter: [job.id],
groups: job.groups,
});
telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
moduleId: job.moduleId,
Expand All @@ -52,7 +53,7 @@ export const useEnableDataFeed = () => {
} catch (error) {
setIsLoading(false);
addError(error, { title: i18n.CREATE_JOB_FAILURE });
telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
moduleId: job.moduleId,
Expand Down Expand Up @@ -82,7 +83,7 @@ export const useEnableDataFeed = () => {
throw new Error(response[datafeedId].error);
}

telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.started,
Expand All @@ -92,7 +93,7 @@ export const useEnableDataFeed = () => {
} catch (error) {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE);
addError(error, { title: i18n.START_JOB_FAILURE });
telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.startError,
Expand Down Expand Up @@ -124,7 +125,7 @@ export const useEnableDataFeed = () => {
throw new Error(response.error);
}

telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopped,
Expand All @@ -134,7 +135,7 @@ export const useEnableDataFeed = () => {
} catch (error) {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE);
addError(error, { title: i18n.STOP_JOB_FAILURE });
telemetry.reportMLJobUpdate({
telemetry.reportEvent(EntityEventTypes.MLJobUpdate, {
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopError,
Expand Down
Loading

0 comments on commit 3b0c380

Please sign in to comment.