diff --git a/x-pack/plugins/infra/public/components/asset_details/constants.ts b/x-pack/plugins/infra/public/components/asset_details/constants.ts index cdd5b95082158..a689efe20d5e3 100644 --- a/x-pack/plugins/infra/public/components/asset_details/constants.ts +++ b/x-pack/plugins/infra/public/components/asset_details/constants.ts @@ -5,8 +5,17 @@ * 2.0. */ +import { INTEGRATION_NAME } from './types'; + export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout'; +export const ASSET_DETAILS_PAGE_COMPONENT_NAME = 'infraAssetDetailsPage'; + export const METRIC_CHART_HEIGHT = 300; export const APM_HOST_FILTER_FIELD = 'host.hostname'; export const ASSET_DETAILS_URL_STATE_KEY = 'assetDetails'; + +export const INTEGRATIONS = { + [INTEGRATION_NAME.nginx]: ['nginx.stubstatus', 'nginx.access'], + [INTEGRATION_NAME.kubernetes]: ['kubernetes.node'], +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/template/page.tsx b/x-pack/plugins/infra/public/components/asset_details/template/page.tsx index b08458731d813..f0a141d393f3f 100644 --- a/x-pack/plugins/infra/public/components/asset_details/template/page.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/template/page.tsx @@ -8,18 +8,55 @@ import { EuiFlexGroup, EuiPageTemplate } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { useEffect } from 'react'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useKibanaHeader } from '../../../hooks/use_kibana_header'; import { InfraLoadingPanel } from '../../loading'; +import { ASSET_DETAILS_PAGE_COMPONENT_NAME } from '../constants'; import { Content } from '../content/content'; import { useAssetDetailsRenderPropsContext } from '../hooks/use_asset_details_render_props'; +import { useMetadataStateProviderContext } from '../hooks/use_metadata_state'; import { usePageHeader } from '../hooks/use_page_header'; -import type { ContentTemplateProps } from '../types'; +import { useTabSwitcherContext } from '../hooks/use_tab_switcher'; +import { ContentTemplateProps } from '../types'; +import { getIntegrationsAvailable } from '../utils'; export const Page = ({ header: { tabs = [], links = [] } }: ContentTemplateProps) => { - const { asset, loading } = useAssetDetailsRenderPropsContext(); + const { loading } = useAssetDetailsRenderPropsContext(); + const { metadata, loading: metadataLoading } = useMetadataStateProviderContext(); const { rightSideItems, tabEntries, breadcrumbs } = usePageHeader(tabs, links); + const { asset, assetType } = useAssetDetailsRenderPropsContext(); const { headerHeight } = useKibanaHeader(); + const trackOnlyOnce = React.useRef(false); + + const { activeTabId } = useTabSwitcherContext(); + const { + services: { telemetry }, + } = useKibanaContextForPlugin(); + + useEffect(() => { + if (trackOnlyOnce.current) { + return; + } + if (!metadataLoading && metadata) { + const integrations = getIntegrationsAvailable(metadata); + const telemetryParams = { + componentName: ASSET_DETAILS_PAGE_COMPONENT_NAME, + assetType, + tabId: activeTabId, + }; + + telemetry.reportAssetDetailsPageViewed( + integrations.length > 0 + ? { + ...telemetryParams, + integrations, + } + : telemetryParams + ); + trackOnlyOnce.current = true; + } + }, [activeTabId, assetType, metadata, metadataLoading, telemetry]); return loading ? ( { const fromTs = new Date(from).getTime(); const toTs = new Date(to).getTime(); @@ -21,3 +24,13 @@ export const getDefaultDateRange = () => { to: new Date(now).toISOString(), }; }; + +export const getIntegrationsAvailable = (metadata?: InfraMetadata | null) => { + if (!metadata) { + return []; + } + + return Object.entries(INTEGRATIONS) + .filter(([_, fields]) => metadata?.features?.some((f) => fields.includes(f.name))) + .map(([name]) => name); +}; diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts index 604fdcc272493..1f354ecd1670f 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts @@ -14,4 +14,5 @@ export const createTelemetryClientMock = (): jest.Mocked => ({ reportHostFlyoutFilterAdded: jest.fn(), reportHostsViewTotalHostCountRetrieved: jest.fn(), reportAssetDetailsFlyoutViewed: jest.fn(), + reportAssetDetailsPageViewed: jest.fn(), }); diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts index 9107157c9835d..d4acc0a8bd96d 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { AssetDetailsFlyoutViewedParams, + AssetDetailsPageViewedParams, HostEntryClickedParams, HostFlyoutFilterActionParams, HostsViewQueryHostsCountRetrievedParams, @@ -65,4 +66,8 @@ export class TelemetryClient implements ITelemetryClient { public reportAssetDetailsFlyoutViewed = (params: AssetDetailsFlyoutViewedParams) => { this.analytics.reportEvent(InfraTelemetryEventTypes.ASSET_DETAILS_FLYOUT_VIEWED, params); }; + + public reportAssetDetailsPageViewed = (params: AssetDetailsPageViewedParams) => { + this.analytics.reportEvent(InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED, params); + }; } diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts index 56cce313ec219..6ce2d2b827623 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts @@ -118,21 +118,55 @@ const assetDetailsFlyoutViewed: InfraTelemetryEvent = { componentName: { type: 'keyword', _meta: { - description: 'Hostname for the clicked host.', + description: 'Name of the parent react component for the clicked asset.', optional: false, }, }, assetType: { type: 'keyword', _meta: { - description: 'Cloud provider for the clicked host.', + description: 'Asset type for the clicked asset.', optional: false, }, }, tabId: { type: 'keyword', _meta: { - description: 'Cloud provider for the clicked host.', + description: 'Tab id for the clicked asset.', + optional: true, + }, + }, + }, +}; + +const assetDetailsPageViewed: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED, + schema: { + componentName: { + type: 'keyword', + _meta: { + description: 'Name of the parent react component for the clicked asset.', + optional: false, + }, + }, + assetType: { + type: 'keyword', + _meta: { + description: 'Asset type for the clicked asset.', + optional: false, + }, + }, + tabId: { + type: 'keyword', + _meta: { + description: 'Tab id for the clicked asset.', + optional: true, + }, + }, + integrations: { + type: 'pass_through', + _meta: { + description: 'Integrations enabled for the displayed asset.', optional: true, }, }, @@ -141,6 +175,7 @@ const assetDetailsFlyoutViewed: InfraTelemetryEvent = { export const infraTelemetryEvents = [ assetDetailsFlyoutViewed, + assetDetailsPageViewed, hostsViewQuerySubmittedEvent, hostsEntryClickedEvent, hostFlyoutRemoveFilter, diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts index b3c4b02468ca6..ac450df7dd162 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts @@ -185,7 +185,7 @@ describe('TelemetryService', () => { }); describe('#reportAssetDetailsFlyoutViewed', () => { - it('should report asset details viewed with properties', async () => { + it('should report asset details viewed in flyout with properties', async () => { const setupParams = getSetupParams(); service.setup(setupParams); const telemetry = service.start(); @@ -207,4 +207,30 @@ describe('TelemetryService', () => { ); }); }); + + describe('#reportAssetDetailsPageViewed', () => { + it('should report asset details viewed in full page with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + + telemetry.reportAssetDetailsPageViewed({ + componentName: 'infraAssetDetailsPage', + assetType: 'host', + tabId: 'overview', + integrations: ['nginx'], + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED, + { + componentName: 'infraAssetDetailsPage', + assetType: 'host', + tabId: 'overview', + integrations: ['nginx'], + } + ); + }); + }); }); diff --git a/x-pack/plugins/infra/public/services/telemetry/types.ts b/x-pack/plugins/infra/public/services/telemetry/types.ts index 2ecf8115eaa58..3b1665078ee3a 100644 --- a/x-pack/plugins/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/infra/public/services/telemetry/types.ts @@ -19,6 +19,7 @@ export enum InfraTelemetryEventTypes { HOST_FLYOUT_FILTER_ADDED = 'Host Flyout Filter Added', HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED = 'Host View Total Host Count Retrieved', ASSET_DETAILS_FLYOUT_VIEWED = 'Asset Details Flyout Viewed', + ASSET_DETAILS_PAGE_VIEWED = 'Asset Details Page Viewed', } export interface HostsViewQuerySubmittedParams { @@ -47,6 +48,9 @@ export interface AssetDetailsFlyoutViewedParams { componentName: string; tabId?: string; } +export interface AssetDetailsPageViewedParams extends AssetDetailsFlyoutViewedParams { + integrations?: string[]; +} export type InfraTelemetryEventParams = | HostsViewQuerySubmittedParams @@ -62,6 +66,7 @@ export interface ITelemetryClient { reportHostsViewTotalHostCountRetrieved(params: HostsViewQueryHostsCountRetrievedParams): void; reportHostsViewQuerySubmitted(params: HostsViewQuerySubmittedParams): void; reportAssetDetailsFlyoutViewed(params: AssetDetailsFlyoutViewedParams): void; + reportAssetDetailsPageViewed(params: AssetDetailsPageViewedParams): void; } export type InfraTelemetryEvent = @@ -88,4 +93,8 @@ export type InfraTelemetryEvent = | { eventType: InfraTelemetryEventTypes.ASSET_DETAILS_FLYOUT_VIEWED; schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED; + schema: RootSchema; };