mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Infra UI] Asset detail view telemetry (#166151)
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" } ```  - 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" ] } ```  --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
df08786c98
commit
39741a23c6
9 changed files with 150 additions and 8 deletions
|
@ -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'],
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -88,3 +88,8 @@ export interface RouteState {
|
|||
}
|
||||
|
||||
export type DataViewOrigin = 'logs' | 'metrics';
|
||||
|
||||
export enum INTEGRATION_NAME {
|
||||
nginx = 'nginx',
|
||||
kubernetes = 'kubernetes',
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -14,4 +14,5 @@ export const createTelemetryClientMock = (): jest.Mocked<ITelemetryClient> => ({
|
|||
reportHostFlyoutFilterAdded: jest.fn(),
|
||||
reportHostsViewTotalHostCountRetrieved: jest.fn(),
|
||||
reportAssetDetailsFlyoutViewed: jest.fn(),
|
||||
reportAssetDetailsPageViewed: jest.fn(),
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'],
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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<AssetDetailsFlyoutViewedParams>;
|
||||
}
|
||||
| {
|
||||
eventType: InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED;
|
||||
schema: RootSchema<AssetDetailsPageViewedParams>;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue