mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Infrastructure UI] Host limit telemetry (#155726)
closes: https://github.com/elastic/kibana/issues/155567 ## Summary This PR adds a new custom event to track the total number of hosts, as well as adjusts a few `data-test-subj` attribute values to meet the naming convention defined in the observability-dev [docs](https://github.com/elastic/observability-dev/blob/main/docs/how-we-work/telemetry/telemetry-convention.md#naming-convention) ### For Reviewers An option for not allowing yet a new custom event in FS could be triggering the new custom events only for self-managed customers, and in FS watch the element that holds the total number of hosts. But for now, I decided to allow the new custom event in FS for consistency --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
a4a9ad9f2c
commit
937912b056
15 changed files with 100 additions and 19 deletions
|
@ -20,7 +20,7 @@ const HOSTS_CHART: Omit<Props, 'loading' | 'value'> = {
|
|||
toolTip: i18n.translate('xpack.infra.hostsViewPage.metricTrend.hostCount.tooltip', {
|
||||
defaultMessage: 'The number of hosts returned by your current search criteria.',
|
||||
}),
|
||||
['data-test-subj']: 'hostsView-metricsTrend-hosts',
|
||||
['data-test-subj']: 'hostsViewKPI-hostsCount',
|
||||
};
|
||||
|
||||
export const HostsTile = () => {
|
||||
|
|
|
@ -70,7 +70,7 @@ export const KPIGrid = () => {
|
|||
direction="row"
|
||||
gutterSize="s"
|
||||
style={{ flexGrow: 0 }}
|
||||
data-test-subj="hostsView-metricsTrend"
|
||||
data-test-subj="hostsViewKPIGrid"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<HostsTile />
|
||||
|
|
|
@ -115,7 +115,7 @@ export const Tile = ({
|
|||
hasShadow={false}
|
||||
paddingSize={error ? 'm' : 'none'}
|
||||
style={{ minHeight: MIN_HEIGHT }}
|
||||
data-test-subj={`hostsView-metricsTrend-${type}`}
|
||||
data-test-subj={`hostsViewKPI-${type}`}
|
||||
>
|
||||
{error ? (
|
||||
<EuiFlexGroup
|
||||
|
@ -145,7 +145,7 @@ export const Tile = ({
|
|||
anchorClassName="eui-fullWidth"
|
||||
>
|
||||
<LensWrapper
|
||||
id={`hostViewKPIChart-${type}`}
|
||||
id={`hostsViewKPIGrid${type}Tile`}
|
||||
attributes={afterLoadedState.attributes}
|
||||
style={{ height: MIN_HEIGHT }}
|
||||
extraActions={[extraActionOptions.openInLens]}
|
||||
|
|
|
@ -77,5 +77,5 @@ const options: EuiButtonGroupOptionProps[] = HOST_LIMIT_OPTIONS.map((option) =>
|
|||
id: buildId(option),
|
||||
label: `${option}`,
|
||||
value: option,
|
||||
'data-test-subj': `hostsViewLimitSelection${option}button`,
|
||||
'data-test-subj': `hostsViewLimitSelection${option}Button`,
|
||||
}));
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useCallback, useEffect } from 'react';
|
|||
import { catchError, map, Observable, of, startWith } from 'rxjs';
|
||||
import createContainer from 'constate';
|
||||
import type { QueryDslQueryContainer, SearchResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
|
||||
import { decodeOrThrow } from '../../../../../common/runtime_types';
|
||||
import { useDataSearch, useLatestPartialDataSearchResponse } from '../../../../utils/data_search';
|
||||
import { useMetricsDataViewContext } from './use_data_view';
|
||||
|
@ -18,6 +19,9 @@ import { useUnifiedSearchContext } from './use_unified_search';
|
|||
|
||||
export const useHostCount = () => {
|
||||
const { dataView, metricAlias } = useMetricsDataViewContext();
|
||||
const {
|
||||
services: { telemetry },
|
||||
} = useKibanaContextForPlugin();
|
||||
const { buildQuery, getParsedDateRange } = useUnifiedSearchContext();
|
||||
|
||||
const { search: fetchHostCount, requests$ } = useDataSearch({
|
||||
|
@ -81,6 +85,14 @@ export const useHostCount = () => {
|
|||
fetchHostCount();
|
||||
}, [fetchHostCount]);
|
||||
|
||||
useEffect(() => {
|
||||
if (latestResponseData) {
|
||||
telemetry.reportHostsViewTotalHostCountRetrieved({
|
||||
total: latestResponseData.count.value,
|
||||
});
|
||||
}
|
||||
}, [latestResponseData, telemetry]);
|
||||
|
||||
return {
|
||||
errors: latestResponseErrors,
|
||||
isRequestRunning,
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
InfraAssetMetricType,
|
||||
} from '../../../../../common/http_api';
|
||||
import { useHostFlyoutOpen } from './use_host_flyout_open_url_state';
|
||||
import { Sorting, useHostsTableProperties } from './use_hosts_table_url_state';
|
||||
import { Sorting, useHostsTableUrlState } from './use_hosts_table_url_state';
|
||||
import { useHostsViewContext } from './use_hosts_view';
|
||||
import { useUnifiedSearchContext } from './use_unified_search';
|
||||
|
||||
|
@ -166,7 +166,7 @@ const toggleDialogActionLabel = i18n.translate(
|
|||
export const useHostsTable = () => {
|
||||
const { hostNodes } = useHostsViewContext();
|
||||
const { searchCriteria } = useUnifiedSearchContext();
|
||||
const [{ pagination, sorting }, setProperties] = useHostsTableProperties();
|
||||
const [{ pagination, sorting }, setProperties] = useHostsTableUrlState();
|
||||
const {
|
||||
services: { telemetry },
|
||||
} = useKibanaContextForPlugin();
|
||||
|
|
|
@ -37,7 +37,7 @@ const reducer = (prevState: TableProperties, params: Payload) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const useHostsTableProperties = (): [TableProperties, TablePropertiesUpdater] => {
|
||||
export const useHostsTableUrlState = (): [TableProperties, TablePropertiesUpdater] => {
|
||||
const [localStoragePageSize, setLocalStoragePageSize] = useLocalStorage<number>(
|
||||
LOCAL_STORAGE_PAGE_SIZE_KEY,
|
||||
DEFAULT_PAGE_SIZE
|
||||
|
|
|
@ -25,13 +25,14 @@ import {
|
|||
const buildQuerySubmittedPayload = (
|
||||
hostState: HostsState & { parsedDateRange: StringDateRangeTimestamp }
|
||||
) => {
|
||||
const { panelFilters, filters, parsedDateRange, query: queryObj } = hostState;
|
||||
const { panelFilters, filters, parsedDateRange, query: queryObj, limit } = hostState;
|
||||
|
||||
return {
|
||||
control_filters: panelFilters.map((filter) => JSON.stringify(filter)),
|
||||
filters: filters.map((filter) => JSON.stringify(filter)),
|
||||
interval: telemetryTimeRangeFormatter(parsedDateRange.to - parsedDateRange.from),
|
||||
query: queryObj.query,
|
||||
limit,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -12,4 +12,5 @@ export const createTelemetryClientMock = (): jest.Mocked<ITelemetryClient> => ({
|
|||
reportHostsViewQuerySubmitted: jest.fn(),
|
||||
reportHostFlyoutFilterRemoved: jest.fn(),
|
||||
reportHostFlyoutFilterAdded: jest.fn(),
|
||||
reportHostsViewTotalHostCountRetrieved: jest.fn(),
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
|
|||
import {
|
||||
HostEntryClickedParams,
|
||||
HostFlyoutFilterActionParams,
|
||||
HostsViewQueryHostsCountRetrievedParams,
|
||||
HostsViewQuerySubmittedParams,
|
||||
InfraTelemetryEventTypes,
|
||||
ITelemetryClient,
|
||||
|
@ -50,4 +51,13 @@ export class TelemetryClient implements ITelemetryClient {
|
|||
public reportHostsViewQuerySubmitted = (params: HostsViewQuerySubmittedParams) => {
|
||||
this.analytics.reportEvent(InfraTelemetryEventTypes.HOSTS_VIEW_QUERY_SUBMITTED, params);
|
||||
};
|
||||
|
||||
public reportHostsViewTotalHostCountRetrieved(
|
||||
params: HostsViewQueryHostsCountRetrievedParams
|
||||
): void {
|
||||
this.analytics.reportEvent(
|
||||
InfraTelemetryEventTypes.HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED,
|
||||
params
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,13 @@ const hostsViewQuerySubmittedEvent: InfraTelemetryEvent = {
|
|||
optional: false,
|
||||
},
|
||||
},
|
||||
limit: {
|
||||
type: 'integer',
|
||||
_meta: {
|
||||
description: 'Selected host limit',
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -78,6 +85,7 @@ const hostFlyoutRemoveFilter: InfraTelemetryEvent = {
|
|||
},
|
||||
},
|
||||
};
|
||||
|
||||
const hostFlyoutAddFilter: InfraTelemetryEvent = {
|
||||
eventType: InfraTelemetryEventTypes.HOST_FLYOUT_FILTER_ADDED,
|
||||
schema: {
|
||||
|
@ -91,9 +99,23 @@ const hostFlyoutAddFilter: InfraTelemetryEvent = {
|
|||
},
|
||||
};
|
||||
|
||||
const hostViewTotalHostCountRetrieved: InfraTelemetryEvent = {
|
||||
eventType: InfraTelemetryEventTypes.HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED,
|
||||
schema: {
|
||||
total: {
|
||||
type: 'integer',
|
||||
_meta: {
|
||||
description: 'Total number of hosts retrieved.',
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const infraTelemetryEvents = [
|
||||
hostsViewQuerySubmittedEvent,
|
||||
hostsEntryClickedEvent,
|
||||
hostFlyoutRemoveFilter,
|
||||
hostFlyoutAddFilter,
|
||||
hostViewTotalHostCountRetrieved,
|
||||
];
|
||||
|
|
|
@ -107,6 +107,7 @@ describe('TelemetryService', () => {
|
|||
filters: [],
|
||||
interval: 'interval(now-1h)',
|
||||
query: '',
|
||||
limit: 100,
|
||||
});
|
||||
|
||||
expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
|
@ -117,6 +118,7 @@ describe('TelemetryService', () => {
|
|||
filters: [],
|
||||
interval: 'interval(now-1h)',
|
||||
query: '',
|
||||
limit: 100,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -161,4 +163,24 @@ describe('TelemetryService', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reportHostsViewTotalHostCountRetrieved', () => {
|
||||
it('should report Host Flyout Filter Added click with field name', async () => {
|
||||
const setupParams = getSetupParams();
|
||||
service.setup(setupParams);
|
||||
const telemetry = service.start();
|
||||
|
||||
telemetry.reportHostsViewTotalHostCountRetrieved({
|
||||
total: 300,
|
||||
});
|
||||
|
||||
expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1);
|
||||
expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith(
|
||||
InfraTelemetryEventTypes.HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED,
|
||||
{
|
||||
total: 300,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ export enum InfraTelemetryEventTypes {
|
|||
HOSTS_ENTRY_CLICKED = 'Host Entry Clicked',
|
||||
HOST_FLYOUT_FILTER_REMOVED = 'Host Flyout Filter Removed',
|
||||
HOST_FLYOUT_FILTER_ADDED = 'Host Flyout Filter Added',
|
||||
HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED = 'Host View Total Host Count Retrieved',
|
||||
}
|
||||
|
||||
export interface HostsViewQuerySubmittedParams {
|
||||
|
@ -24,6 +25,7 @@ export interface HostsViewQuerySubmittedParams {
|
|||
filters: string[];
|
||||
interval: string;
|
||||
query: string | { [key: string]: any };
|
||||
limit: number;
|
||||
}
|
||||
|
||||
export interface HostEntryClickedParams {
|
||||
|
@ -35,15 +37,21 @@ export interface HostFlyoutFilterActionParams {
|
|||
field_name: string;
|
||||
}
|
||||
|
||||
export interface HostsViewQueryHostsCountRetrievedParams {
|
||||
total: number;
|
||||
}
|
||||
|
||||
export type InfraTelemetryEventParams =
|
||||
| HostsViewQuerySubmittedParams
|
||||
| HostEntryClickedParams
|
||||
| HostFlyoutFilterActionParams;
|
||||
| HostFlyoutFilterActionParams
|
||||
| HostsViewQueryHostsCountRetrievedParams;
|
||||
|
||||
export interface ITelemetryClient {
|
||||
reportHostEntryClicked(params: HostEntryClickedParams): void;
|
||||
reportHostFlyoutFilterRemoved(params: HostFlyoutFilterActionParams): void;
|
||||
reportHostFlyoutFilterAdded(params: HostFlyoutFilterActionParams): void;
|
||||
reportHostsViewTotalHostCountRetrieved(params: HostsViewQueryHostsCountRetrievedParams): void;
|
||||
reportHostsViewQuerySubmitted(params: HostsViewQuerySubmittedParams): void;
|
||||
}
|
||||
|
||||
|
@ -63,4 +71,8 @@ export type InfraTelemetryEvent =
|
|||
| {
|
||||
eventType: InfraTelemetryEventTypes.HOSTS_ENTRY_CLICKED;
|
||||
schema: RootSchema<HostEntryClickedParams>;
|
||||
}
|
||||
| {
|
||||
eventType: InfraTelemetryEventTypes.HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED;
|
||||
schema: RootSchema<HostsViewQueryHostsCountRetrievedParams>;
|
||||
};
|
||||
|
|
|
@ -371,7 +371,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
});
|
||||
|
||||
[
|
||||
{ metric: 'hosts', value: '6' },
|
||||
{ metric: 'hostsCount', value: '6' },
|
||||
{ metric: 'cpu', value: '0.8%' },
|
||||
{ metric: 'memory', value: '16.81%' },
|
||||
{ metric: 'tx', value: 'N/A' },
|
||||
|
@ -510,7 +510,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
it('should update the KPIs content on a search submit', async () => {
|
||||
await Promise.all(
|
||||
[
|
||||
{ metric: 'hosts', value: '3' },
|
||||
{ metric: 'hostsCount', value: '3' },
|
||||
{ metric: 'cpu', value: '0.8%' },
|
||||
{ metric: 'memory', value: '16.25%' },
|
||||
{ metric: 'tx', value: 'N/A' },
|
||||
|
|
|
@ -103,8 +103,8 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
|
|||
return cellContent.getVisibleText();
|
||||
},
|
||||
|
||||
async getKPIContainer() {
|
||||
return testSubjects.find('hostsView-metricsTrend');
|
||||
async getMetricsTrendContainer() {
|
||||
return testSubjects.find('hostsViewKPIGrid');
|
||||
},
|
||||
|
||||
async getChartsContainer() {
|
||||
|
@ -118,7 +118,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
|
|||
|
||||
async visitMetricsTab() {
|
||||
const metricsTab = await this.getMetricsTab();
|
||||
await metricsTab.click();
|
||||
return metricsTab.click();
|
||||
},
|
||||
|
||||
async getAllMetricsCharts() {
|
||||
|
@ -144,14 +144,15 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
|
|||
},
|
||||
|
||||
async getAllKPITiles() {
|
||||
const container = await this.getKPIContainer();
|
||||
return container.findAllByCssSelector('[data-test-subj*="hostsView-metricsTrend-"]');
|
||||
const container = await this.getMetricsTrendContainer();
|
||||
return container.findAllByCssSelector('[data-test-subj*="hostsViewKPI-"]');
|
||||
},
|
||||
|
||||
async getKPITileValue(type: string) {
|
||||
const element = await testSubjects.find(`hostsView-metricsTrend-${type}`);
|
||||
const container = await this.getMetricsTrendContainer();
|
||||
const element = await container.findByTestSubject(`hostsViewKPI-${type}`);
|
||||
const div = await element.findByClassName('echMetricText__value');
|
||||
return await div.getAttribute('title');
|
||||
return div.getAttribute('title');
|
||||
},
|
||||
|
||||
// Flyout Tabs
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue