Skip to content

Commit

Permalink
[Security Solution][Alert Details] - add general telemetry for docume…
Browse files Browse the repository at this point in the history
…nt details flyout (elastic#178683)

## Summary

Add telemetry to track basic usage of the document details flyout for
alerts and events:

- `reportDetailsFlyoutOpened` tracks opening details flyout, expanding
left section and opening a preview
- `reportDetailsFlyoutTabClicked` tracks tabs clicked

Flyout dashboard in
[staging](https://telemetry-v2-staging.elastic.dev/s/securitysolution/app/dashboards#/view/093a84d0-dfec-11ee-8356-8b8a68fd8ef2?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-3d,to:now)))

![image](https://github.com/elastic/kibana/assets/18648970/ae46388f-1d8a-4abb-9bad-60f6582d3015)

How to test 
- add `telemetry.optIn: true` to `kibana.dev.yaml`
- interact with details flyout in data table (Alerts page, Host/User
page, Cases Page)
- the data should be fed to staging every hour or so

### Checklist

- [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

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
christineweng and kibanamachine authored Mar 19, 2024
1 parent 6fdfa25 commit 9ba0dc1
Show file tree
Hide file tree
Showing 22 changed files with 203 additions and 24 deletions.
8 changes: 6 additions & 2 deletions x-pack/plugins/security_solution/public/cases/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const TimelineDetailsPanel = () => {
};

const CaseContainerComponent: React.FC = () => {
const { cases } = useKibana().services;
const { cases, telemetry } = useKibana().services;
const { getAppUrl, navigateTo } = useNavigation();
const userCasesPermissions = cases.helpers.canUseCases([APP_ID]);
const dispatch = useDispatch();
Expand Down Expand Up @@ -82,6 +82,10 @@ const CaseContainerComponent: React.FC = () => {
},
},
});
telemetry.reportDetailsFlyoutOpened({
tableId: TimelineId.casePage,
panel: 'right',
});
}
// TODO remove when https://github.com/elastic/security-team/issues/7462 is merged
// support of old flyout in cases page
Expand All @@ -98,7 +102,7 @@ const CaseContainerComponent: React.FC = () => {
);
}
},
[dispatch, isSecurityFlyoutEnabled, openFlyout]
[dispatch, isSecurityFlyoutEnabled, openFlyout, telemetry]
);

const endpointDetailsHref = (endpointId: string) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useDispatch } from 'react-redux';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { dataTableActions, TableId } from '@kbn/securitysolution-data-table';
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
import { useKibana } from '../../../lib/kibana';
import { timelineActions } from '../../../../timelines/store';
import { ENABLE_EXPANDABLE_FLYOUT_SETTING } from '../../../../../common/constants';
import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/right';
Expand Down Expand Up @@ -69,7 +70,7 @@ const RowActionComponent = ({
refetch,
}: Props) => {
const { data: timelineNonEcsData, ecs: ecsData, _id: eventId, _index: indexName } = data ?? {};

const { telemetry } = useKibana().services;
const { openFlyout } = useExpandableFlyoutApi();

const dispatch = useDispatch();
Expand Down Expand Up @@ -120,6 +121,10 @@ const RowActionComponent = ({
},
},
});
telemetry.reportDetailsFlyoutOpened({
tableId,
panel: 'right',
});
}
// TODO remove when https://github.com/elastic/security-team/issues/7462 is merged
// support of old flyout in cases page
Expand All @@ -142,7 +147,7 @@ const RowActionComponent = ({
})
);
}
}, [dispatch, eventId, indexName, openFlyout, tabType, tableId, showExpandableFlyout]);
}, [dispatch, eventId, indexName, openFlyout, tabType, tableId, showExpandableFlyout, telemetry]);

const Action = controlColumn.rowCellRender;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export enum TelemetryEventTypes {
AnomaliesCountClicked = 'Anomalies Count Clicked',
DataQualityIndexChecked = 'Data Quality Index Checked',
DataQualityCheckAllCompleted = 'Data Quality Check All Completed',
DetailsFlyoutOpened = 'Details Flyout Opened',
DetailsFlyoutTabClicked = 'Details Flyout Tabs Clicked',
}

export enum ML_JOB_TELEMETRY_STATUS {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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.
*/

import type { TelemetryEvent } from '../../types';
import { TelemetryEventTypes } from '../../constants';

export const DocumentDetailsFlyoutOpenedEvent: TelemetryEvent = {
eventType: TelemetryEventTypes.DetailsFlyoutOpened,
schema: {
tableId: {
type: 'text',
_meta: {
description: 'Table ID',
optional: false,
},
},
panel: {
type: 'keyword',
_meta: {
description: 'Panel (left|right|preview)',
optional: false,
},
},
},
};

export const DocumentDetailsTabClickedEvent: TelemetryEvent = {
eventType: TelemetryEventTypes.DetailsFlyoutTabClicked,
schema: {
tableId: {
type: 'text',
_meta: {
description: 'Table ID',
optional: false,
},
},
panel: {
type: 'keyword',
_meta: {
description: 'Panel (left|right)',
optional: false,
},
},
tabId: {
type: 'keyword',
_meta: {
description: 'Tab ID',
optional: false,
},
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.
*/

import type { RootSchema } from '@kbn/analytics-client';
import type { TelemetryEventTypes } from '../../constants';

export interface ReportDetailsFlyoutOpenedParams {
tableId: string;
panel: 'left' | 'right' | 'preview';
}

export interface ReportDetailsFlyoutTabClickedParams {
tableId: string;
panel: 'left' | 'right';
tabId: string;
}

export type ReportDocumentDetailsTelemetryEventParams =
| ReportDetailsFlyoutOpenedParams
| ReportDetailsFlyoutTabClickedParams;

export type DocumentDetailsTelemetryEvents =
| {
eventType: TelemetryEventTypes.DetailsFlyoutOpened;
schema: RootSchema<ReportDetailsFlyoutOpenedParams>;
}
| {
eventType: TelemetryEventTypes.DetailsFlyoutTabClicked;
schema: RootSchema<ReportDetailsFlyoutTabClickedParams>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
assistantQuickPrompt,
} from './ai_assistant';
import { dataQualityIndexCheckedEvent, dataQualityCheckAllClickedEvent } from './data_quality';
import {
DocumentDetailsFlyoutOpenedEvent,
DocumentDetailsTabClickedEvent,
} from './document_details';

const mlJobUpdateEvent: TelemetryEvent = {
eventType: TelemetryEventTypes.MLJobUpdate,
Expand Down Expand Up @@ -155,4 +159,6 @@ export const telemetryEvents = [
dataQualityIndexCheckedEvent,
dataQualityCheckAllClickedEvent,
breadCrumbClickedEvent,
DocumentDetailsFlyoutOpenedEvent,
DocumentDetailsTabClickedEvent,
];
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ export const createTelemetryClientMock = (): jest.Mocked<TelemetryClientStart> =
reportToggleRiskSummaryClicked: jest.fn(),
reportRiskInputsExpandedFlyoutOpened: jest.fn(),
reportAddRiskInputToTimelineClicked: jest.fn(),
reportDetailsFlyoutOpened: jest.fn(),
reportDetailsFlyoutTabClicked: jest.fn(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import type {
ReportAssistantSettingToggledParams,
ReportRiskInputsExpandedFlyoutOpenedParams,
ReportToggleRiskSummaryClickedParams,
ReportDetailsFlyoutOpenedParams,
ReportDetailsFlyoutTabClickedParams,
} from './types';
import { TelemetryEventTypes } from './constants';
import type { ReportAddRiskInputToTimelineClickedParams } from './events/entity_analytics/types';
Expand Down Expand Up @@ -143,4 +145,12 @@ export class TelemetryClient implements TelemetryClientStart {
title,
});
};

public reportDetailsFlyoutOpened = (params: ReportDetailsFlyoutOpenedParams) => {
this.analytics.reportEvent(TelemetryEventTypes.DetailsFlyoutOpened, params);
};

public reportDetailsFlyoutTabClicked = (params: ReportDetailsFlyoutTabClickedParams) => {
this.analytics.reportEvent(TelemetryEventTypes.DetailsFlyoutTabClicked, params);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ describe('TelemetryService', () => {
expect(telemetry).toHaveProperty('reportAlertsGroupingChanged');
expect(telemetry).toHaveProperty('reportAlertsGroupingToggled');
expect(telemetry).toHaveProperty('reportAlertsGroupingTakeAction');

expect(telemetry).toHaveProperty('reportDetailsFlyoutOpened');
expect(telemetry).toHaveProperty('reportDetailsFlyoutTabClicked');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ import type {
ReportAssistantMessageSentParams,
ReportAssistantSettingToggledParams,
} from './events/ai_assistant/types';
import type {
DocumentDetailsTelemetryEvents,
ReportDocumentDetailsTelemetryEventParams,
ReportDetailsFlyoutOpenedParams,
ReportDetailsFlyoutTabClickedParams,
} from './events/document_details/types';

export * from './events/ai_assistant/types';
export * from './events/alerts_grouping/types';
Expand All @@ -51,6 +57,7 @@ export type {
ReportToggleRiskSummaryClickedParams,
ReportAddRiskInputToTimelineClickedParams,
} from './events/entity_analytics/types';
export * from './events/document_details/types';

export interface TelemetryServiceSetupParams {
analytics: AnalyticsServiceSetup;
Expand Down Expand Up @@ -89,7 +96,8 @@ export type TelemetryEventParams =
| ReportAnomaliesCountClickedParams
| ReportDataQualityIndexCheckedParams
| ReportDataQualityCheckAllCompletedParams
| ReportBreadcrumbClickedParams;
| ReportBreadcrumbClickedParams
| ReportDocumentDetailsTelemetryEventParams;

export interface TelemetryClientStart {
reportAlertsGroupingChanged(params: ReportAlertsGroupingChangedParams): void;
Expand Down Expand Up @@ -117,13 +125,18 @@ export interface TelemetryClientStart {
reportDataQualityIndexChecked(params: ReportDataQualityIndexCheckedParams): void;
reportDataQualityCheckAllCompleted(params: ReportDataQualityCheckAllCompletedParams): void;
reportBreadcrumbClicked(params: ReportBreadcrumbClickedParams): void;

// document details flyout
reportDetailsFlyoutOpened(params: ReportDetailsFlyoutOpenedParams): void;
reportDetailsFlyoutTabClicked(params: ReportDetailsFlyoutTabClickedParams): void;
}

export type TelemetryEvent =
| AssistantTelemetryEvent
| AlertsGroupingTelemetryEvent
| EntityAnalyticsTelemetryEvent
| DataQualityTelemetryEvents
| DocumentDetailsTelemetryEvents
| {
eventType: TelemetryEventTypes.MLJobUpdate;
schema: RootSchema<ReportMLJobUpdateParams>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useShowRelatedAlertsBySession } from '../../shared/hooks/use_show_relat
import { RelatedAlertsByAncestry } from './related_alerts_by_ancestry';
import { SuppressedAlerts } from './suppressed_alerts';

export const CORRELATIONS_TAB_ID = 'correlations-details';
export const CORRELATIONS_TAB_ID = 'correlations';

/**
* Correlations displayed in the document details expandable flyout left section under the Insights tab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { UserDetails } from './user_details';
import { HostDetails } from './host_details';
import { ENTITIES_DETAILS_TEST_ID } from './test_ids';

export const ENTITIES_TAB_ID = 'entities-details';
export const ENTITIES_TAB_ID = 'entity';

/**
* Entities displayed in the document details expandable flyout left section under the Insights tab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
import { getEmptyTagValue } from '../../../../common/components/empty_value';
import { IS_OPERATOR } from '../../../../../common/types';

export const PREVALENCE_TAB_ID = 'prevalence-details';
export const PREVALENCE_TAB_ID = 'prevalence';
const DEFAULT_FROM = 'now-30d';
const DEFAULT_TO = 'now';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useThreatIntelligenceDetails } from '../hooks/use_threat_intelligence_d
import { THREAT_INTELLIGENCE_DETAILS_LOADING_TEST_ID } from './test_ids';
import { FlyoutLoading } from '../../../shared/components/flyout_loading';

export const THREAT_INTELLIGENCE_TAB_ID = 'threat-intelligence-details';
export const THREAT_INTELLIGENCE_TAB_ID = 'threatIntelligence';

/**
* Threat intelligence displayed in the document details expandable flyout left section under the Insights tab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { FC } from 'react';
import React, { memo, useMemo } from 'react';
import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { useKibana } from '../../../common/lib/kibana';
import { PanelHeader } from './header';
import { PanelContent } from './content';
import type { LeftPanelTabType } from './tabs';
Expand All @@ -35,6 +36,7 @@ export interface LeftPanelProps extends FlyoutPanelProps {
}

export const LeftPanel: FC<Partial<LeftPanelProps>> = memo(({ path }) => {
const { telemetry } = useKibana().services;
const { openLeftPanel } = useExpandableFlyoutApi();
const { eventId, indexName, scopeId, getFieldsData } = useLeftPanelContext();
const eventKind = getField(getFieldsData('event.kind'));
Expand Down Expand Up @@ -65,6 +67,11 @@ export const LeftPanel: FC<Partial<LeftPanelProps>> = memo(({ path }) => {
scopeId,
},
});
telemetry.reportDetailsFlyoutTabClicked({
tableId: scopeId,
panel: 'left',
tabId,
});
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { EuiButtonGroupOptionProps } from '@elastic/eui/src/components/butt
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { useExpandableFlyoutApi, useExpandableFlyoutState } from '@kbn/expandable-flyout';
import { useKibana } from '../../../../common/lib/kibana';
import {
INSIGHTS_TAB_BUTTON_GROUP_TEST_ID,
INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID,
Expand Down Expand Up @@ -77,6 +78,7 @@ const insightsButtons: EuiButtonGroupOptionProps[] = [
* Insights view displayed in the document details expandable flyout left section
*/
export const InsightsTab: React.FC = memo(() => {
const { telemetry } = useKibana().services;
const { eventId, indexName, scopeId, getFieldsData } = useLeftPanelContext();
const isEventKindSignal = getField(getFieldsData('event.kind')) === EventKind.signal;
const { openLeftPanel } = useExpandableFlyoutApi();
Expand Down Expand Up @@ -110,8 +112,13 @@ export const InsightsTab: React.FC = memo(() => {
scopeId,
},
});
telemetry.reportDetailsFlyoutTabClicked({
tableId: scopeId,
panel: 'left',
tabId: optionId,
});
},
[eventId, indexName, scopeId, openLeftPanel]
[eventId, indexName, scopeId, openLeftPanel, telemetry]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { RightPanelContext } from '../context';
import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data';
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import { DocumentDetailsPreviewPanelKey } from '../../preview';
import { TestProviders } from '../../../../common/mock';
import { i18n } from '@kbn/i18n';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import type { ExpandableFlyoutApi } from '@kbn/expandable-flyout';
Expand Down Expand Up @@ -63,11 +64,13 @@ const panelContextValue = (dataFormattedForFieldBrowser: TimelineEventsDetailsIt

const renderDescription = (panelContext: RightPanelContext) =>
render(
<IntlProvider locale="en">
<RightPanelContext.Provider value={panelContext}>
<AlertDescription />
</RightPanelContext.Provider>
</IntlProvider>
<TestProviders>
<IntlProvider locale="en">
<RightPanelContext.Provider value={panelContext}>
<AlertDescription />
</RightPanelContext.Provider>
</IntlProvider>
</TestProviders>
);

const NO_DATA_MESSAGE = "There's no description for this rule.";
Expand Down
Loading

0 comments on commit 9ba0dc1

Please sign in to comment.