Skip to content

Commit

Permalink
[8.x] [Cloud Security] UI counter telemetry (#194390)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[Cloud Security] UI counter
telemetry](#193721)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Ido
Cohen","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-30T09:08:49Z","message":"[Cloud
Security] UI counter
telemetry","sha":"5849c86e8d4303415f9d7b8115d3efdaa965deb9","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor"],"title":"[Cloud
Security] UI counter
telemetry","number":193721,"url":"https://github.com/elastic/kibana/pull/193721","mergeCommit":{"message":"[Cloud
Security] UI counter
telemetry","sha":"5849c86e8d4303415f9d7b8115d3efdaa965deb9"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193721","number":193721,"mergeCommit":{"message":"[Cloud
Security] UI counter
telemetry","sha":"5849c86e8d4303415f9d7b8115d3efdaa965deb9"}}]}]
BACKPORT-->

Co-authored-by: Ido Cohen <[email protected]>
  • Loading branch information
kibanamachine and CohenIdo authored Sep 30, 2024
1 parent 4e2c656 commit a2a135d
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 14 deletions.
1 change: 1 addition & 0 deletions x-pack/packages/kbn-cloud-security-posture-common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export {
buildEntityFlyoutPreviewQuery,
} from './utils/helpers';
export { getAbbreviatedNumber } from './utils/get_abbreviated_number';
export { UiMetricService } from './utils/ui_metrics';
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@
"@kbn/config-schema",
"@kbn/data-views-plugin",
"@kbn/i18n",
"@kbn/analytics",
"@kbn/usage-collection-plugin",
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 { UiCounterMetricType } from '@kbn/analytics';
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';

export const APP_NAME = 'cloud-security';

export const ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS =
'entity-flyout-misconfiguration-view-visits';
export const NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT =
'nav-to-findings-by-host-name-from-entity-flyout';
export const NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT =
'nav-to-findings-by-rule-name-from-entity-flyout';
export const CREATE_DETECTION_RULE_FROM_FLYOUT = 'create-detection-rule-from-flyout';
export const CREATE_DETECTION_FROM_TABLE_ROW_ACTION = 'create-detection-from-table-row-action';
export const VULNERABILITIES_FLYOUT_VISITS = 'vulnerabilities-flyout-visits';
export const OPEN_FINDINGS_FLYOUT = 'open-findings-flyout';
export const GROUP_BY_CLICK = 'group-by-click';
export const CHANGE_RULE_STATE = 'change-rule-state';

type CloudSecurityUiCounters =
| typeof ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS
| typeof NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT
| typeof VULNERABILITIES_FLYOUT_VISITS
| typeof NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT
| typeof OPEN_FINDINGS_FLYOUT
| typeof CREATE_DETECTION_RULE_FROM_FLYOUT
| typeof CREATE_DETECTION_FROM_TABLE_ROW_ACTION
| typeof GROUP_BY_CLICK
| typeof CHANGE_RULE_STATE;

export class UiMetricService {
private usageCollection: UsageCollectionSetup | undefined;

public setup(usageCollection: UsageCollectionSetup) {
this.usageCollection = usageCollection;
}

private track(metricType: UiCounterMetricType, eventName: CloudSecurityUiCounters) {
if (!this.usageCollection) {
// Usage collection might be disabled in Kibana config.
return;
}
return this.usageCollection.reportUiCounter(APP_NAME, metricType, eventName);
}

public trackUiMetric(metricType: UiCounterMetricType, eventName: CloudSecurityUiCounters) {
return this.track(metricType, eventName);
}
}

export const uiMetricService = new UiMetricService();
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { isNoneGroup, useGrouping } from '@kbn/grouping';
import * as uuid from 'uuid';
import type { DataView } from '@kbn/data-views-plugin/common';
import { GroupOption, GroupPanelRenderer, GetGroupStats } from '@kbn/grouping/src';
import {
GROUP_BY_CLICK,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';

import { useUrlQuery } from '../../common/hooks/use_url_query';

Expand Down Expand Up @@ -73,6 +78,7 @@ export const useCloudSecurityGrouping = ({
setUrlQuery({
groupBy: groupByFields,
});
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, GROUP_BY_CLICK);
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import React, { useCallback, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiLink, EuiLoadingSpinner, EuiSkeletonText, EuiText } from '@elastic/eui';
import type { HttpSetup } from '@kbn/core/public';
import {
CREATE_DETECTION_RULE_FROM_FLYOUT,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';
import { useHistory } from 'react-router-dom';
import useSessionStorage from 'react-use/lib/useSessionStorage';
import { useQueryClient } from '@tanstack/react-query';
Expand Down Expand Up @@ -62,6 +67,7 @@ export const DetectionRuleCounter = ({ tags, createRuleFn }: DetectionRuleCounte
}, [history]);

const createDetectionRuleOnClick = useCallback(async () => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, CREATE_DETECTION_RULE_FROM_FLYOUT);
const startServices = { analytics, notifications, i18n, theme };
setIsCreateRuleLoading(true);
const ruleResponse = await createRuleFn(http);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ import type { HttpSetup } from '@kbn/core/public';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n as kbnI18n } from '@kbn/i18n';
import { QueryClient, useMutation, useQueryClient } from '@tanstack/react-query';
import {
CREATE_DETECTION_FROM_TABLE_ROW_ACTION,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';
import type { RuleResponse } from '../common/types';
import { CREATE_RULE_ACTION_SUBJ, TAKE_ACTION_SUBJ } from './test_subjects';
import { useKibana } from '../common/hooks/use_kibana';
Expand Down Expand Up @@ -239,7 +244,10 @@ const CreateDetectionRule = ({
<EuiContextMenuItem
key="createRule"
disabled={isCreateDetectionRuleDisabled}
onClick={() => mutate()}
onClick={() => {
mutate();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, CREATE_DETECTION_FROM_TABLE_ROW_ACTION);
}}
data-test-subj={CREATE_RULE_ACTION_SUBJ}
>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { i18n } from '@kbn/i18n';
import { EuiDataGridCellValueElementProps, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import type { CspFinding } from '@kbn/cloud-security-posture-common';
import { CspEvaluationBadge } from '@kbn/cloud-security-posture';
import {
OPEN_FINDINGS_FLYOUT,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';
import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name';
import * as TEST_SUBJECTS from '../test_subjects';
import { FindingsDistributionBar } from '../layout/findings_distribution_bar';
Expand Down Expand Up @@ -49,7 +54,7 @@ const getCspFinding = (source: Record<string, any> | undefined): CspFinding | un
const flyoutComponent = (row: DataTableRecord, onCloseFlyout: () => void): JSX.Element => {
const finding = row.raw._source;
if (!finding || !isCspFinding(finding)) return <></>;

uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, OPEN_FINDINGS_FLYOUT);
return <FindingsRuleFlyout finding={finding} onClose={onCloseFlyout} />;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import {
EuiTableSortingType,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import {
CHANGE_RULE_STATE,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { uniqBy } from 'lodash';
import { ColumnNameWithTooltip } from '../../components/column_name_with_tooltip';
import type { CspBenchmarkRulesWithStates, RulesState } from './rules_container';
Expand Down Expand Up @@ -281,6 +286,7 @@ const RuleStateSwitch = ({ rule }: { rule: CspBenchmarkRulesWithStates }) => {
};
const changeCspRuleStateFn = async () => {
if (rule?.metadata.benchmark.rule_number) {
uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, CHANGE_RULE_STATE);
mutateRulesStates({
newState: nextRuleState,
ruleIds: [rulesObjectRequest],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ import {
VectorScoreBase,
CspVulnerabilityFinding,
} from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import { METRIC_TYPE } from '@kbn/analytics';

import {
VULNERABILITIES_FLYOUT_VISITS,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name';
import { CspFlyoutMarkdown } from '../../configurations/findings_flyout/findings_flyout';
import { NvdLogo } from '../../../assets/icons/nvd_logo_svg';
Expand Down Expand Up @@ -218,6 +224,8 @@ const VulnerabilityOverviewTiles = ({ vulnerabilityRecord }: VulnerabilityTabPro

export const VulnerabilityOverviewTab = ({ vulnerabilityRecord }: VulnerabilityTabProps) => {
const { vulnerability } = vulnerabilityRecord;
uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, VULNERABILITIES_FLYOUT_VISITS);

const emptyFixesMessageState = i18n.translate(
'xpack.csp.vulnerabilities.vulnerabilityOverviewTab.emptyFixesMessage',
{
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/cloud_security_posture/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import type { CspClientPluginStartDeps } from '@kbn/cloud-security-posture';
import { uiMetricService } from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { CspLoadingState } from './components/csp_loading_state';
import type { CspRouterProps } from './application/csp_router';
import type { CspClientPluginSetup, CspClientPluginStart, CspClientPluginSetupDeps } from './types';
Expand Down Expand Up @@ -47,6 +48,9 @@ export class CspPlugin
plugins: CspClientPluginSetupDeps
): CspClientPluginSetup {
this.isCloudEnabled = plugins.cloud.isCloudEnabled;

if (plugins.usageCollection) uiMetricService.setup(plugins.usageCollection);

// Return methods that should be available to other plugins
return {};
}
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/cloud_security_posture/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
"@kbn/react-kibana-mount",
"@kbn/spaces-plugin",
"@kbn/cloud-security-posture-common",
"@kbn/cloud-security-posture"
"@kbn/cloud-security-posture",
"@kbn/analytics"
],
"exclude": ["target/**/*"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import { DistributionBar } from '@kbn/security-solution-distribution-bar';
import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings';
import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common/schema/rules/latest';
import { CspEvaluationBadge } from '@kbn/cloud-security-posture';
import {
NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT,
NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';

type MisconfigurationFindingDetailFields = Pick<CspFinding, 'result' | 'rule' | 'resource'>;

Expand Down Expand Up @@ -107,6 +113,10 @@ export const MisconfigurationFindingsDetailsTable = memo(
};

const navToFindingsByName = (name: string, queryField: 'host.name' | 'user.name') => {
uiMetricService.trackUiMetric(
METRIC_TYPE.CLICK,
NAV_TO_FINDINGS_BY_RULE_NAME_FRPOM_ENTITY_FLYOUT
);
navToFindings({ [queryField]: name }, ['rule.name']);
};

Expand Down Expand Up @@ -154,6 +164,10 @@ export const MisconfigurationFindingsDetailsTable = memo(
<EuiPanel hasShadow={false}>
<EuiLink
onClick={() => {
uiMetricService.trackUiMetric(
METRIC_TYPE.CLICK,
NAV_TO_FINDINGS_BY_HOST_NAME_FRPOM_ENTITY_FLYOUT
);
navToFindingsByName(queryName, fieldName);
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import {
ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { METRIC_TYPE } from '@kbn/analytics';
import { EntityDetailsLeftPanelTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import { PREFIX } from '../../../flyout/shared/test_ids';
import type { RiskInputsTabProps } from './tabs/risk_inputs/risk_inputs_tab';
Expand Down Expand Up @@ -34,14 +39,18 @@ export const getInsightsInputTab = ({
}: {
name: string;
fieldName: 'host.name' | 'user.name';
}) => ({
id: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
'data-test-subj': INSIGHTS_TAB_TEST_ID,
name: (
<FormattedMessage
id="xpack.securitySolution.flyout.entityDetails.insightsDetails.insights.tabLabel"
defaultMessage="Insights"
/>
),
content: <InsightsTabCsp name={name} fieldName={fieldName} />,
});
}) => {
uiMetricService.trackUiMetric(METRIC_TYPE.COUNT, ENTITY_FLYOUT_MISCONFIGURATION_VIEW_VISITS);

return {
id: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
'data-test-subj': INSIGHTS_TAB_TEST_ID,
name: (
<FormattedMessage
id="xpack.securitySolution.flyout.entityDetails.insightsDetails.insights.tabLabel"
defaultMessage="Insights"
/>
),
content: <InsightsTabCsp name={name} fieldName={fieldName} />,
};
};
4 changes: 4 additions & 0 deletions x-pack/plugins/security_solution/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public';
import { uiMetricService } from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { getLazyCloudSecurityPosturePliAuthBlockExtension } from './cloud_security_posture/lazy_cloud_security_posture_pli_auth_block_extension';
import { getLazyEndpointAgentTamperProtectionExtension } from './management/pages/policy/view/ingest_manager_integration/lazy_endpoint_agent_tamper_protection_extension';
import type {
Expand Down Expand Up @@ -107,6 +108,9 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
return { renderApp, subPlugins, store, services };
};

// register cloud security ui metrics
if (plugins.usageCollection) uiMetricService.setup(plugins.usageCollection);

// Register main Security Solution plugin
core.application.register({
id: APP_UI_ID,
Expand Down

0 comments on commit a2a135d

Please sign in to comment.