Skip to content

Commit

Permalink
[Infra UI] Asset detail view telemetry (#166151)
Browse files Browse the repository at this point in the history
Closes #156698

## Summary

This PR adds a new custom event to track asset details page views. The
event will have a parameter `integrations` which will show if `nginx` or
`kubernetes` integrations are enabled ( so extra charts will be
displayed in those cases) and the same parameters as the existing flyout
event.

## Testing 

- Open hosts view flyout:
- The `Asset Details Flyout Viewed` Event type should be tracked (same
as before)
   - Event properties in this example (same as before)
   ```
   "properties":{
       "componentName":"infraAssetDetailsFlyout",
       "assetType":"host",
       "tabId":"overview"
     }
   ```

![Image](https://github.com/elastic/kibana/assets/14139027/7ab85302-1aed-487c-860c-b0a62ef06a70)

- Open asset details page for a host:
   - The `Asset Details Pade Viewed` Event type should be tracked
- The event properties should show the current enabled integrations
('nginx', 'kubernetes') if there are no integrations enabled the
integrations should not be visible in the event so in this example:
   ```
    "properties": {
       "componentName": "infraAssetDetailsPage",
       "assetType": "host",
       "tabId": "overview",
       "integrations": [
           "nginx"
       ]
   }
   ```

![Image](https://github.com/elastic/kibana/assets/14139027/bc657298-cb14-4ac2-ba46-ac42e3bd3e37)

---------

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
jennypavlova and kibanamachine authored Sep 13, 2023
1 parent df08786 commit 39741a2
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
};
Original file line number Diff line number Diff line change
Expand Up @@ -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 ? (
<EuiFlexGroup
Expand All @@ -43,6 +80,8 @@ export const Page = ({ header: { tabs = [], links = [] } }: ContentTemplateProps
offset={0}
restrictWidth={false}
style={{ minBlockSize: `calc(100vh - ${headerHeight}px)` }}
data-component-name={ASSET_DETAILS_PAGE_COMPONENT_NAME}
data-asset-type={assetType}
>
<EuiPageTemplate.Section paddingSize="none">
<EuiPageTemplate.Header
Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/infra/public/components/asset_details/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ export interface RouteState {
}

export type DataViewOrigin = 'logs' | 'metrics';

export enum INTEGRATION_NAME {
nginx = 'nginx',
kubernetes = 'kubernetes',
}
13 changes: 13 additions & 0 deletions x-pack/plugins/infra/public/components/asset_details/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* 2.0.
*/

import type { InfraMetadata } from '../../../common/http_api';
import { INTEGRATIONS } from './constants';

export const toTimestampRange = ({ from, to }: { from: string; to: string }) => {
const fromTs = new Date(from).getTime();
const toTs = new Date(to).getTime();
Expand All @@ -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);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export const createTelemetryClientMock = (): jest.Mocked<ITelemetryClient> => ({
reportHostFlyoutFilterAdded: jest.fn(),
reportHostsViewTotalHostCountRetrieved: jest.fn(),
reportAssetDetailsFlyoutViewed: jest.fn(),
reportAssetDetailsPageViewed: jest.fn(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
};
}
41 changes: 38 additions & 3 deletions x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
Expand All @@ -141,6 +175,7 @@ const assetDetailsFlyoutViewed: InfraTelemetryEvent = {

export const infraTelemetryEvents = [
assetDetailsFlyoutViewed,
assetDetailsPageViewed,
hostsViewQuerySubmittedEvent,
hostsEntryClickedEvent,
hostFlyoutRemoveFilter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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'],
}
);
});
});
});
9 changes: 9 additions & 0 deletions x-pack/plugins/infra/public/services/telemetry/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -47,6 +48,9 @@ export interface AssetDetailsFlyoutViewedParams {
componentName: string;
tabId?: string;
}
export interface AssetDetailsPageViewedParams extends AssetDetailsFlyoutViewedParams {
integrations?: string[];
}

export type InfraTelemetryEventParams =
| HostsViewQuerySubmittedParams
Expand All @@ -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 =
Expand All @@ -88,4 +93,8 @@ export type InfraTelemetryEvent =
| {
eventType: InfraTelemetryEventTypes.ASSET_DETAILS_FLYOUT_VIEWED;
schema: RootSchema<AssetDetailsFlyoutViewedParams>;
}
| {
eventType: InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED;
schema: RootSchema<AssetDetailsPageViewedParams>;
};

0 comments on commit 39741a2

Please sign in to comment.