[Upgrade Assistant] Refactor telemetry (#112177)

This commit is contained in:
Alison Goryachev 2021-09-23 11:32:08 -04:00 committed by GitHub
parent ca55b003dc
commit 991d24bad2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 207 additions and 809 deletions

View file

@ -6924,44 +6924,6 @@
}
}
}
},
"ui_open": {
"properties": {
"elasticsearch": {
"type": "long",
"_meta": {
"description": "Number of times a user viewed the list of Elasticsearch deprecations."
}
},
"overview": {
"type": "long",
"_meta": {
"description": "Number of times a user viewed the Overview page."
}
},
"kibana": {
"type": "long",
"_meta": {
"description": "Number of times a user viewed the list of Kibana deprecations"
}
}
}
},
"ui_reindex": {
"properties": {
"close": {
"type": "long"
},
"open": {
"type": "long"
},
"start": {
"type": "long"
},
"stop": {
"type": "long"
}
}
}
}
},

View file

@ -226,4 +226,29 @@ This is a non-exhaustive list of different error scenarios in Upgrade Assistant.
- **Error updating deprecation logging status.** Mock a `404` status code to `PUT /api/upgrade_assistant/deprecation_logging`. Alternatively, edit [this line](https://github.com/elastic/kibana/blob/545c1420c285af8f5eee56f414bd6eca735aea11/x-pack/plugins/upgrade_assistant/public/application/lib/api.ts#L77) locally and replace `deprecation_logging` with `fake_deprecation_logging`.
- **Unauthorized error fetching ES deprecations.** Mock a `403` status code to `GET /api/upgrade_assistant/es_deprecations` with the response payload: `{ "statusCode": 403 }`
- **Partially upgraded error fetching ES deprecations.** Mock a `426` status code to `GET /api/upgrade_assistant/es_deprecations` with the response payload: `{ "statusCode": 426, "attributes": { "allNodesUpgraded": false } }`
- **Upgraded error fetching ES deprecations.** Mock a `426` status code to `GET /api/upgrade_assistant/es_deprecations` with the response payload: `{ "statusCode": 426, "attributes": { "allNodesUpgraded": true } }`
- **Upgraded error fetching ES deprecations.** Mock a `426` status code to `GET /api/upgrade_assistant/es_deprecations` with the response payload: `{ "statusCode": 426, "attributes": { "allNodesUpgraded": true } }`
### Telemetry
The Upgrade Assistant tracks several triggered events in the UI, using Kibana Usage Collection service's [UI counters](https://github.com/elastic/kibana/blob/master/src/plugins/usage_collection/README.mdx#ui-counters).
**Overview page**
- Component loaded
- Click event for "Create snapshot" button
- Click event for "View deprecation logs in Observability" link
- Click event for "Analyze logs in Discover" link
- Click event for "Reset counter" button
**ES deprecations page**
- Component loaded
- Click events for starting and stopping reindex tasks
- Click events for upgrading or deleting a Machine Learning snapshot
- Click event for deleting a deprecated index setting
**Kibana deprecations page**
- Component loaded
- Click event for "Quick resolve" button
In addition to UI counters, the Upgrade Assistant has a [custom usage collector](https://github.com/elastic/kibana/blob/master/src/plugins/usage_collection/README.mdx#custom-collector). It currently is only responsible for tracking whether the user has deprecation logging enabled or not.
For testing instructions, refer to the [Kibana Usage Collection service README](https://github.com/elastic/kibana/blob/master/src/plugins/usage_collection/README.mdx#testing).

View file

@ -138,32 +138,7 @@ export interface UIReindex {
stop: boolean;
}
export interface UpgradeAssistantTelemetrySavedObject {
ui_open: {
overview: number;
elasticsearch: number;
kibana: number;
};
ui_reindex: {
close: number;
open: number;
start: number;
stop: number;
};
}
export interface UpgradeAssistantTelemetry {
ui_open: {
overview: number;
elasticsearch: number;
kibana: number;
};
ui_reindex: {
close: number;
open: number;
start: number;
stop: number;
};
features: {
deprecation_logging: {
enabled: boolean;
@ -171,10 +146,6 @@ export interface UpgradeAssistantTelemetry {
};
}
export interface UpgradeAssistantTelemetrySavedObjectAttributes {
[key: string]: any;
}
export type MIGRATION_DEPRECATION_LEVEL = 'none' | 'info' | 'warning' | 'critical';
export interface DeprecationInfo {
level: MIGRATION_DEPRECATION_LEVEL;

View file

@ -5,8 +5,9 @@
* 2.0.
*/
import React from 'react';
import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import {
EuiButton,
EuiButtonEmpty,
@ -25,6 +26,7 @@ import {
} from '@elastic/eui';
import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types';
import type { ResponseError } from '../../../../lib/api';
import { uiMetricService, UIM_INDEX_SETTINGS_DELETE_CLICK } from '../../../../lib/ui_metric';
import type { Status } from '../../../types';
import { DeprecationBadge } from '../../../shared';
@ -107,6 +109,11 @@ export const RemoveIndexSettingsFlyout = ({
// Flag used to hide certain parts of the UI if the deprecation has been resolved or is in progress
const isResolvable = ['idle', 'error'].includes(statusType);
const onRemoveSettings = useCallback(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_INDEX_SETTINGS_DELETE_CLICK);
removeIndexSettings(index!, (correctiveAction as IndexSettingAction).deprecatedSettings);
}, [correctiveAction, index, removeIndexSettings]);
return (
<>
<EuiFlyoutHeader hasBorder>
@ -190,12 +197,7 @@ export const RemoveIndexSettingsFlyout = ({
fill
data-test-subj="deleteSettingsButton"
color="danger"
onClick={() =>
removeIndexSettings(
index!,
(correctiveAction as IndexSettingAction).deprecatedSettings
)
}
onClick={onRemoveSettings}
>
{statusType === 'error'
? i18nTexts.retryRemoveButtonLabel

View file

@ -7,6 +7,7 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import {
EuiButton,
@ -24,6 +25,11 @@ import {
} from '@elastic/eui';
import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import {
uiMetricService,
UIM_ML_SNAPSHOT_UPGRADE_CLICK,
UIM_ML_SNAPSHOT_DELETE_CLICK,
} from '../../../../lib/ui_metric';
import { DeprecationBadge } from '../../../shared';
import { MlSnapshotContext } from './context';
import { SnapshotState } from './use_snapshot_state';
@ -143,11 +149,13 @@ export const FixSnapshotsFlyout = ({
const isResolved = snapshotState.status === 'complete';
const onUpgradeSnapshot = () => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_ML_SNAPSHOT_UPGRADE_CLICK);
upgradeSnapshot();
closeFlyout();
};
const onDeleteSnapshot = () => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_ML_SNAPSHOT_DELETE_CLICK);
deleteSnapshot();
closeFlyout();
};

View file

@ -42,7 +42,7 @@ exports[`ChecklistFlyout renders 1`] = `
</h3>
</EuiTitle>
<ReindexProgress
cancelReindex={[MockFunction]}
cancelReindex={[Function]}
reindexState={
Object {
"errorMessage": null,
@ -83,7 +83,7 @@ exports[`ChecklistFlyout renders 1`] = `
disabled={false}
fill={true}
isLoading={false}
onClick={[MockFunction]}
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Run reindex"

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { Fragment } from 'react';
import React, { Fragment, useCallback } from 'react';
import {
EuiButton,
@ -19,8 +19,14 @@ import {
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { METRIC_TYPE } from '@kbn/analytics';
import { ReindexStatus } from '../../../../../../../common/types';
import {
uiMetricService,
UIM_REINDEX_START_CLICK,
UIM_REINDEX_STOP_CLICK,
} from '../../../../../lib/ui_metric';
import { LoadingState } from '../../../../types';
import type { ReindexState } from '../use_reindex_state';
import { ReindexProgress } from './progress';
@ -71,6 +77,16 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
const { loadingState, status, hasRequiredPrivileges } = reindexState;
const loading = loadingState === LoadingState.Loading || status === ReindexStatus.inProgress;
const onStartReindex = useCallback(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_REINDEX_START_CLICK);
startReindex();
}, [startReindex]);
const onStopReindex = useCallback(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_REINDEX_STOP_CLICK);
cancelReindex();
}, [cancelReindex]);
return (
<Fragment>
<EuiFlyoutBody>
@ -124,7 +140,7 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
/>
</h3>
</EuiTitle>
<ReindexProgress reindexState={reindexState} cancelReindex={cancelReindex} />
<ReindexProgress reindexState={reindexState} cancelReindex={onStopReindex} />
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
@ -142,7 +158,7 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
fill
color={status === ReindexStatus.paused ? 'warning' : 'primary'}
iconType={status === ReindexStatus.paused ? 'play' : undefined}
onClick={startReindex}
onClick={onStartReindex}
isLoading={loading}
disabled={loading || !hasRequiredPrivileges}
>

View file

@ -7,9 +7,15 @@
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
import { useAppContext } from '../../../../app_context';
import {
uiMetricService,
UIM_REINDEX_CLOSE_FLYOUT_CLICK,
UIM_REINDEX_OPEN_FLYOUT_CLICK,
} from '../../../../lib/ui_metric';
import { DeprecationTableColumns } from '../../../types';
import { EsDeprecationsTableCells } from '../../es_deprecations_table_cells';
import { ReindexResolutionCell } from './resolution_table_cell';
@ -29,9 +35,6 @@ const ReindexTableRowCells: React.FunctionComponent<TableRowProps> = ({
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const reindexState = useReindexContext();
const {
services: { api },
} = useAppContext();
const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout } =
useGlobalFlyout();
@ -39,8 +42,8 @@ const ReindexTableRowCells: React.FunctionComponent<TableRowProps> = ({
const closeFlyout = useCallback(async () => {
removeContentFromGlobalFlyout('reindexFlyout');
setShowFlyout(false);
await api.sendReindexTelemetryData({ close: true });
}, [api, removeContentFromGlobalFlyout]);
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_REINDEX_CLOSE_FLYOUT_CLICK);
}, [removeContentFromGlobalFlyout]);
useEffect(() => {
if (showFlyout) {
@ -64,13 +67,9 @@ const ReindexTableRowCells: React.FunctionComponent<TableRowProps> = ({
useEffect(() => {
if (showFlyout) {
async function sendTelemetry() {
await api.sendReindexTelemetryData({ open: true });
}
sendTelemetry();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_REINDEX_OPEN_FLYOUT_CLICK);
}
}, [showFlyout, api]);
}, [showFlyout]);
return (
<>

View file

@ -131,8 +131,6 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A
cancelLoadingState: undefined,
});
api.sendReindexTelemetryData({ start: true });
const { data, error } = await api.startReindexTask(indexName);
if (error) {
@ -149,8 +147,6 @@ export const useReindexStatus = ({ indexName, api }: { indexName: string; api: A
}, [api, indexName, reindexState, updateStatus]);
const cancelReindex = useCallback(async () => {
api.sendReindexTelemetryData({ stop: true });
const { error } = await api.cancelReindexTask(indexName);
setReindexState({

View file

@ -10,10 +10,12 @@ import { withRouter, RouteComponentProps } from 'react-router-dom';
import { EuiPageHeader, EuiSpacer, EuiPageContent } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { EnrichedDeprecationInfo } from '../../../../common/types';
import { SectionLoading } from '../../../shared_imports';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_ES_DEPRECATIONS_PAGE_LOAD } from '../../lib/ui_metric';
import { getEsDeprecationError } from '../../lib/get_es_deprecation_error';
import { DeprecationsPageLoadingError, NoDeprecationsPrompt, DeprecationCount } from '../shared';
import { EsDeprecationsTable } from './es_deprecations_table';
@ -54,13 +56,7 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => {
services: { api, breadcrumbs },
} = useAppContext();
const {
data: esDeprecations,
isLoading,
error,
resendRequest,
isInitialRequest,
} = api.useLoadEsDeprecations();
const { data: esDeprecations, isLoading, error, resendRequest } = api.useLoadEsDeprecations();
const deprecationsCountByLevel: {
warningDeprecations: number;
@ -75,16 +71,8 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => {
}, [breadcrumbs]);
useEffect(() => {
if (isLoading === false && isInitialRequest) {
async function sendTelemetryData() {
await api.sendPageTelemetryData({
elasticsearch: true,
});
}
sendTelemetryData();
}
}, [api, isLoading, isInitialRequest]);
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_ES_DEPRECATIONS_PAGE_LOAD);
}, []);
if (error) {
return (

View file

@ -5,9 +5,10 @@
* 2.0.
*/
import React from 'react';
import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { METRIC_TYPE } from '@kbn/analytics';
import {
EuiButtonEmpty,
@ -24,6 +25,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { uiMetricService, UIM_KIBANA_QUICK_RESOLVE_CLICK } from '../../lib/ui_metric';
import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations';
import { DeprecationBadge } from '../shared';
@ -134,6 +136,11 @@ export const DeprecationDetailsFlyout = ({
const isCurrent = deprecationResolutionState?.id === deprecation.id;
const isResolved = isCurrent && deprecationResolutionState?.resolveDeprecationStatus === 'ok';
const onResolveDeprecation = useCallback(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_KIBANA_QUICK_RESOLVE_CLICK);
resolveDeprecation(deprecation);
}, [deprecation, resolveDeprecation]);
return (
<>
<EuiFlyoutHeader hasBorder>
@ -225,7 +232,7 @@ export const DeprecationDetailsFlyout = ({
<EuiButton
fill
data-test-subj="resolveButton"
onClick={() => resolveDeprecation(deprecation)}
onClick={onResolveDeprecation}
isLoading={Boolean(
deprecationResolutionState?.resolveDeprecationStatus === 'in_progress'
)}

View file

@ -11,10 +11,12 @@ import { withRouter, RouteComponentProps } from 'react-router-dom';
import { EuiPageContent, EuiPageHeader, EuiSpacer, EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { METRIC_TYPE } from '@kbn/analytics';
import type { DomainDeprecationDetails } from 'kibana/public';
import { SectionLoading, GlobalFlyout } from '../../../shared_imports';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_KIBANA_DEPRECATIONS_PAGE_LOAD } from '../../lib/ui_metric';
import { DeprecationsPageLoadingError, NoDeprecationsPrompt, DeprecationCount } from '../shared';
import { KibanaDeprecationsTable } from './kibana_deprecations_table';
import {
@ -116,7 +118,6 @@ export const KibanaDeprecations = withRouter(({ history }: RouteComponentProps)
services: {
core: { deprecations },
breadcrumbs,
api,
},
} = useAppContext();
@ -225,14 +226,8 @@ export const KibanaDeprecations = withRouter(({ history }: RouteComponentProps)
]);
useEffect(() => {
async function sendTelemetryData() {
await api.sendPageTelemetryData({
kibana: true,
});
}
sendTelemetryData();
}, [api]);
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_KIBANA_DEPRECATIONS_PAGE_LOAD);
}, []);
useEffect(() => {
breadcrumbs.setBreadcrumbs('kibanaDeprecations');

View file

@ -9,6 +9,7 @@ import React, { useEffect } from 'react';
import moment from 'moment-timezone';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import {
EuiLoadingContent,
EuiFlexGroup,
@ -21,6 +22,7 @@ import {
} from '@elastic/eui';
import { useAppContext } from '../../../app_context';
import { uiMetricService, UIM_BACKUP_DATA_CLOUD_CLICK } from '../../../lib/ui_metric';
interface Props {
cloudSnapshotsUrl: string;
@ -128,11 +130,13 @@ export const CloudBackup: React.FunctionComponent<Props> = ({
return (
<>
{statusMessage}
<EuiSpacer size="s" />
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
<EuiButton
href={cloudSnapshotsUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_BACKUP_DATA_CLOUD_CLICK);
}}
data-test-subj="cloudSnapshotsLink"
target="_blank"
iconType="popout"

View file

@ -8,9 +8,11 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { EuiText, EuiButton, EuiSpacer } from '@elastic/eui';
import { useAppContext } from '../../../app_context';
import { uiMetricService, UIM_BACKUP_DATA_ON_PREM_CLICK } from '../../../lib/ui_metric';
const SnapshotRestoreAppLink: React.FunctionComponent = () => {
const {
@ -22,7 +24,14 @@ const SnapshotRestoreAppLink: React.FunctionComponent = () => {
?.useUrl({ page: 'snapshots' });
return (
<EuiButton href={snapshotRestoreUrl} data-test-subj="snapshotRestoreLink">
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiButton
href={snapshotRestoreUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_BACKUP_DATA_ON_PREM_CLICK);
}}
data-test-subj="snapshotRestoreLink"
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.snapshotRestoreLink"
defaultMessage="Create snapshot"

View file

@ -8,10 +8,12 @@
import React, { FunctionComponent, useEffect } from 'react';
import moment from 'moment-timezone';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiButton, EuiLoadingContent } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { uiMetricService, UIM_RESET_LOGS_COUNTER_CLICK } from '../../../../lib/ui_metric';
const i18nTexts = {
calloutTitle: (warningsCount: number, previousCheck: string) => (
@ -71,6 +73,7 @@ export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
const onResetClick = () => {
const now = moment().toISOString();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_RESET_LOGS_COUNTER_CLICK);
setCheckpoint(now);
};

View file

@ -9,10 +9,17 @@ import { encode } from 'rison-node';
import React, { FunctionComponent, useState, useEffect } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { METRIC_TYPE } from '@kbn/analytics';
import { EuiLink, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel, EuiText } from '@elastic/eui';
import { useAppContext } from '../../../app_context';
import { DataPublicPluginStart } from '../../../../shared_imports';
import { useAppContext } from '../../../app_context';
import {
uiMetricService,
UIM_OBSERVABILITY_CLICK,
UIM_DISCOVER_CLICK,
} from '../../../lib/ui_metric';
import {
DEPRECATION_LOGS_INDEX_PATTERN,
DEPRECATION_LOGS_SOURCE_ID,
@ -73,7 +80,14 @@ const DiscoverAppLink: FunctionComponent<Props> = ({ checkpoint }) => {
}, [dataService, checkpoint, share.url.locators]);
return (
<EuiLink href={discoveryUrl} data-test-subj="viewDiscoverLogs">
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink
href={discoveryUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_DISCOVER_CLICK);
}}
data-test-subj="viewDiscoverLogs"
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewDiscoverResultsAction"
defaultMessage="Analyze logs in Discover"
@ -95,7 +109,14 @@ const ObservabilityAppLink: FunctionComponent<Props> = ({ checkpoint }) => {
);
return (
<EuiLink href={logStreamUrl} data-test-subj="viewObserveLogs">
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink
href={logStreamUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_OBSERVABILITY_CLICK);
}}
data-test-subj="viewObserveLogs"
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewObservabilityResultsAction"
defaultMessage="View deprecation logs in Observability"

View file

@ -18,9 +18,11 @@ import {
EuiPageContent,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { FormattedMessage } from '@kbn/i18n/react';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_OVERVIEW_PAGE_LOAD } from '../../lib/ui_metric';
import { getBackupStep } from './backup_step';
import { getFixIssuesStep } from './fix_issues_step';
import { getFixLogsStep } from './fix_logs_step';
@ -33,21 +35,14 @@ export const Overview: FunctionComponent = () => {
kibanaVersionInfo: { nextMajor },
services: {
breadcrumbs,
api,
core: { docLinks },
},
plugins: { cloud },
} = useAppContext();
useEffect(() => {
async function sendTelemetryData() {
await api.sendPageTelemetryData({
overview: true,
});
}
sendTelemetryData();
}, [api]);
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_OVERVIEW_PAGE_LOAD);
}, []);
useEffect(() => {
breadcrumbs.setBreadcrumbs('overview');

View file

@ -65,16 +65,6 @@ export class ApiService {
});
}
public async sendPageTelemetryData(telemetryData: { [tabName: string]: boolean }) {
const result = await this.sendRequest({
path: `${API_BASE_PATH}/stats/ui_open`,
method: 'put',
body: JSON.stringify(telemetryData),
});
return result;
}
public useLoadDeprecationLogging() {
return this.useRequest<{
isDeprecationLogIndexingEnabled: boolean;
@ -150,16 +140,6 @@ export class ApiService {
});
}
public async sendReindexTelemetryData(telemetryData: { [key: string]: boolean }) {
const result = await this.sendRequest({
path: `${API_BASE_PATH}/stats/ui_reindex`,
method: 'put',
body: JSON.stringify(telemetryData),
});
return result;
}
public async getReindexStatus(indexName: string) {
return await this.sendRequest({
path: `${API_BASE_PATH}/reindex/${indexName}`,

View file

@ -0,0 +1,49 @@
/*
* 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 { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
export const UIM_APP_NAME = 'upgrade_assistant';
export const UIM_ES_DEPRECATIONS_PAGE_LOAD = 'es_deprecations_page_load';
export const UIM_KIBANA_DEPRECATIONS_PAGE_LOAD = 'kibana_deprecations_page_load';
export const UIM_OVERVIEW_PAGE_LOAD = 'overview_page_load';
export const UIM_REINDEX_OPEN_FLYOUT_CLICK = 'reindex_open_flyout_click';
export const UIM_REINDEX_CLOSE_FLYOUT_CLICK = 'reindex_close_flyout_click';
export const UIM_REINDEX_START_CLICK = 'reindex_start_click';
export const UIM_REINDEX_STOP_CLICK = 'reindex_stop_click';
export const UIM_BACKUP_DATA_CLOUD_CLICK = 'backup_data_cloud_click';
export const UIM_BACKUP_DATA_ON_PREM_CLICK = 'backup_data_on_prem_click';
export const UIM_RESET_LOGS_COUNTER_CLICK = 'reset_logs_counter_click';
export const UIM_OBSERVABILITY_CLICK = 'observability_click';
export const UIM_DISCOVER_CLICK = 'discover_click';
export const UIM_ML_SNAPSHOT_UPGRADE_CLICK = 'ml_snapshot_upgrade_click';
export const UIM_ML_SNAPSHOT_DELETE_CLICK = 'ml_snapshot_delete_click';
export const UIM_INDEX_SETTINGS_DELETE_CLICK = 'index_settings_delete_click';
export const UIM_KIBANA_QUICK_RESOLVE_CLICK = 'kibana_quick_resolve_click';
export class UiMetricService {
private usageCollection: UsageCollectionSetup | undefined;
public setup(usageCollection: UsageCollectionSetup) {
this.usageCollection = usageCollection;
}
private track(metricType: UiCounterMetricType, eventName: string | string[]) {
if (!this.usageCollection) {
// Usage collection might be disabled in Kibana config.
return;
}
return this.usageCollection.reportUiCounter(UIM_APP_NAME, metricType, eventName);
}
public trackUiMetric(metricType: UiCounterMetricType, eventName: string | string[]) {
return this.track(metricType, eventName);
}
}
export const uiMetricService = new UiMetricService();

View file

@ -11,6 +11,7 @@ import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/public';
import { apiService } from './application/lib/api';
import { breadcrumbService } from './application/lib/breadcrumbs';
import { uiMetricService } from './application/lib/ui_metric';
import { SetupDependencies, StartDependencies, AppDependencies } from './types';
import { Config } from '../common/config';
@ -18,7 +19,10 @@ export class UpgradeAssistantUIPlugin
implements Plugin<void, void, SetupDependencies, StartDependencies>
{
constructor(private ctx: PluginInitializerContext) {}
setup(coreSetup: CoreSetup<StartDependencies>, { management, cloud, share }: SetupDependencies) {
setup(
coreSetup: CoreSetup<StartDependencies>,
{ management, cloud, share, usageCollection }: SetupDependencies
) {
const { readonly } = this.ctx.config.get<Config>();
const appRegistrar = management.sections.section.stack;
@ -34,6 +38,10 @@ export class UpgradeAssistantUIPlugin
defaultMessage: 'Upgrade Assistant',
});
if (usageCollection) {
uiMetricService.setup(usageCollection);
}
appRegistrar.registerApp({
id: 'upgrade_assistant',
title: pluginName,

View file

@ -10,6 +10,7 @@ import { ManagementSetup } from 'src/plugins/management/public';
import { DataPublicPluginStart } from 'src/plugins/data/public';
import { SharePluginSetup } from 'src/plugins/share/public';
import { CoreStart } from 'src/core/public';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
import { CloudSetup } from '../../cloud/public';
import { LicensingPluginStart } from '../../licensing/public';
import { BreadcrumbService } from './application/lib/breadcrumbs';
@ -25,6 +26,7 @@ export interface SetupDependencies {
management: ManagementSetup;
share: SharePluginSetup;
cloud?: CloudSetup;
usageCollection?: UsageCollectionSetup;
}
export interface StartDependencies {

View file

@ -1,48 +0,0 @@
/*
* 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 { savedObjectsRepositoryMock } from 'src/core/server/mocks';
import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../common/types';
import { upsertUIOpenOption } from './es_ui_open_apis';
/**
* Since these route callbacks are so thin, these serve simply as integration tests
* to ensure they're wired up to the lib functions correctly. Business logic is tested
* more thoroughly in the lib/telemetry tests.
*/
describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => {
describe('Upsert UIOpen Option', () => {
it('call saved objects internal repository with the correct info', async () => {
const internalRepo = savedObjectsRepositoryMock.create();
await upsertUIOpenOption({
overview: true,
elasticsearch: true,
kibana: true,
savedObjects: { createInternalRepository: () => internalRepo } as any,
});
expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(3);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
['ui_open.overview']
);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
['ui_open.elasticsearch']
);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
['ui_open.kibana']
);
});
});
});

View file

@ -1,57 +0,0 @@
/*
* 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 { SavedObjectsServiceStart } from 'src/core/server';
import {
UIOpen,
UIOpenOption,
UPGRADE_ASSISTANT_DOC_ID,
UPGRADE_ASSISTANT_TYPE,
} from '../../../common/types';
interface IncrementUIOpenDependencies {
uiOpenOptionCounter: UIOpenOption;
savedObjects: SavedObjectsServiceStart;
}
async function incrementUIOpenOptionCounter({
savedObjects,
uiOpenOptionCounter,
}: IncrementUIOpenDependencies) {
const internalRepository = savedObjects.createInternalRepository();
await internalRepository.incrementCounter(UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, [
`ui_open.${uiOpenOptionCounter}`,
]);
}
type UpsertUIOpenOptionDependencies = UIOpen & { savedObjects: SavedObjectsServiceStart };
export async function upsertUIOpenOption({
overview,
elasticsearch,
savedObjects,
kibana,
}: UpsertUIOpenOptionDependencies): Promise<UIOpen> {
if (overview) {
await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'overview' });
}
if (elasticsearch) {
await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'elasticsearch' });
}
if (kibana) {
await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'kibana' });
}
return {
overview,
elasticsearch,
kibana,
};
}

View file

@ -1,52 +0,0 @@
/*
* 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 { savedObjectsRepositoryMock } from 'src/core/server/mocks';
import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../common/types';
import { upsertUIReindexOption } from './es_ui_reindex_apis';
/**
* Since these route callbacks are so thin, these serve simply as integration tests
* to ensure they're wired up to the lib functions correctly. Business logic is tested
* more thoroughly in the lib/telemetry tests.
*/
describe('Upgrade Assistant Telemetry SavedObject UIReindex', () => {
describe('Upsert UIReindex Option', () => {
it('call saved objects internal repository with the correct info', async () => {
const internalRepo = savedObjectsRepositoryMock.create();
await upsertUIReindexOption({
close: true,
open: true,
start: true,
stop: true,
savedObjects: { createInternalRepository: () => internalRepo } as any,
});
expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(4);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
[`ui_reindex.close`]
);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
[`ui_reindex.open`]
);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
[`ui_reindex.start`]
);
expect(internalRepo.incrementCounter).toHaveBeenCalledWith(
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID,
[`ui_reindex.stop`]
);
});
});
});

View file

@ -1,63 +0,0 @@
/*
* 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 { SavedObjectsServiceStart } from 'src/core/server';
import {
UIReindex,
UIReindexOption,
UPGRADE_ASSISTANT_DOC_ID,
UPGRADE_ASSISTANT_TYPE,
} from '../../../common/types';
interface IncrementUIReindexOptionDependencies {
uiReindexOptionCounter: UIReindexOption;
savedObjects: SavedObjectsServiceStart;
}
async function incrementUIReindexOptionCounter({
savedObjects,
uiReindexOptionCounter,
}: IncrementUIReindexOptionDependencies) {
const internalRepository = savedObjects.createInternalRepository();
await internalRepository.incrementCounter(UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, [
`ui_reindex.${uiReindexOptionCounter}`,
]);
}
type UpsertUIReindexOptionDepencies = UIReindex & { savedObjects: SavedObjectsServiceStart };
export async function upsertUIReindexOption({
start,
close,
open,
stop,
savedObjects,
}: UpsertUIReindexOptionDepencies): Promise<UIReindex> {
if (close) {
await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'close' });
}
if (open) {
await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'open' });
}
if (start) {
await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'start' });
}
if (stop) {
await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'stop' });
}
return {
close,
open,
start,
stop,
};
}

View file

@ -47,26 +47,6 @@ describe('Upgrade Assistant Usage Collector', () => {
};
dependencies = {
usageCollection,
savedObjects: {
createInternalRepository: jest.fn().mockImplementation(() => {
return {
get: () => {
return {
attributes: {
'ui_open.overview': 10,
'ui_open.elasticsearch': 20,
'ui_open.kibana': 15,
'ui_reindex.close': 1,
'ui_reindex.open': 4,
'ui_reindex.start': 2,
'ui_reindex.stop': 1,
'ui_reindex.not_defined': 1,
},
};
},
};
}),
},
elasticsearch: {
client: clusterClient,
},
@ -91,17 +71,6 @@ describe('Upgrade Assistant Usage Collector', () => {
callClusterStub
);
expect(upgradeAssistantStats).toEqual({
ui_open: {
overview: 10,
elasticsearch: 20,
kibana: 15,
},
ui_reindex: {
close: 1,
open: 4,
start: 2,
stop: 1,
},
features: {
deprecation_logging: {
enabled: true,

View file

@ -5,43 +5,14 @@
* 2.0.
*/
import { get } from 'lodash';
import {
ElasticsearchClient,
ElasticsearchServiceStart,
ISavedObjectsRepository,
SavedObjectsServiceStart,
} from 'src/core/server';
import { ElasticsearchClient, ElasticsearchServiceStart } from 'src/core/server';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import {
UPGRADE_ASSISTANT_DOC_ID,
UPGRADE_ASSISTANT_TYPE,
UpgradeAssistantTelemetry,
UpgradeAssistantTelemetrySavedObject,
UpgradeAssistantTelemetrySavedObjectAttributes,
} from '../../../common/types';
import { UpgradeAssistantTelemetry } from '../../../common/types';
import {
isDeprecationLogIndexingEnabled,
isDeprecationLoggingEnabled,
} from '../es_deprecation_logging_apis';
async function getSavedObjectAttributesFromRepo(
savedObjectsRepository: ISavedObjectsRepository,
docType: string,
docID: string
) {
try {
return (
await savedObjectsRepository.get<UpgradeAssistantTelemetrySavedObjectAttributes>(
docType,
docID
)
).attributes;
} catch (e) {
return null;
}
}
async function getDeprecationLoggingStatusValue(esClient: ElasticsearchClient): Promise<boolean> {
try {
const { body: loggerDeprecationCallResult } = await esClient.cluster.getSettings({
@ -57,58 +28,14 @@ async function getDeprecationLoggingStatusValue(esClient: ElasticsearchClient):
}
}
export async function fetchUpgradeAssistantMetrics(
{ client: esClient }: ElasticsearchServiceStart,
savedObjects: SavedObjectsServiceStart
): Promise<UpgradeAssistantTelemetry> {
const savedObjectsRepository = savedObjects.createInternalRepository();
const upgradeAssistantSOAttributes = await getSavedObjectAttributesFromRepo(
savedObjectsRepository,
UPGRADE_ASSISTANT_TYPE,
UPGRADE_ASSISTANT_DOC_ID
);
export async function fetchUpgradeAssistantMetrics({
client: esClient,
}: ElasticsearchServiceStart): Promise<UpgradeAssistantTelemetry> {
const deprecationLoggingStatusValue = await getDeprecationLoggingStatusValue(
esClient.asInternalUser
);
const getTelemetrySavedObject = (
upgradeAssistantTelemetrySavedObjectAttrs: UpgradeAssistantTelemetrySavedObjectAttributes | null
): UpgradeAssistantTelemetrySavedObject => {
const defaultTelemetrySavedObject = {
ui_open: {
overview: 0,
elasticsearch: 0,
kibana: 0,
},
ui_reindex: {
close: 0,
open: 0,
start: 0,
stop: 0,
},
};
if (!upgradeAssistantTelemetrySavedObjectAttrs) {
return defaultTelemetrySavedObject;
}
return {
ui_open: {
overview: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.overview', 0),
elasticsearch: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.elasticsearch', 0),
kibana: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.kibana', 0),
},
ui_reindex: {
close: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.close', 0),
open: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.open', 0),
start: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.start', 0),
stop: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.stop', 0),
},
} as UpgradeAssistantTelemetrySavedObject;
};
return {
...getTelemetrySavedObject(upgradeAssistantSOAttributes),
features: {
deprecation_logging: {
enabled: deprecationLoggingStatusValue,
@ -119,14 +46,12 @@ export async function fetchUpgradeAssistantMetrics(
interface Dependencies {
elasticsearch: ElasticsearchServiceStart;
savedObjects: SavedObjectsServiceStart;
usageCollection: UsageCollectionSetup;
}
export function registerUpgradeAssistantUsageCollector({
elasticsearch,
usageCollection,
savedObjects,
}: Dependencies) {
const upgradeAssistantUsageCollector =
usageCollection.makeUsageCollector<UpgradeAssistantTelemetry>({
@ -143,34 +68,8 @@ export function registerUpgradeAssistantUsageCollector({
},
},
},
ui_open: {
elasticsearch: {
type: 'long',
_meta: {
description: 'Number of times a user viewed the list of Elasticsearch deprecations.',
},
},
overview: {
type: 'long',
_meta: {
description: 'Number of times a user viewed the Overview page.',
},
},
kibana: {
type: 'long',
_meta: {
description: 'Number of times a user viewed the list of Kibana deprecations',
},
},
},
ui_reindex: {
close: { type: 'long' },
open: { type: 'long' },
start: { type: 'long' },
stop: { type: 'long' },
},
},
fetch: async () => fetchUpgradeAssistantMetrics(elasticsearch, savedObjects),
fetch: async () => fetchUpgradeAssistantMetrics(elasticsearch),
});
usageCollection.registerCollector(upgradeAssistantUsageCollector);

View file

@ -142,11 +142,10 @@ export class UpgradeAssistantServerPlugin implements Plugin {
registerRoutes(dependencies, this.getWorker.bind(this));
if (usageCollection) {
getStartServices().then(([{ savedObjects: savedObjectsService, elasticsearch }]) => {
getStartServices().then(([{ elasticsearch }]) => {
registerUpgradeAssistantUsageCollector({
elasticsearch,
usageCollection,
savedObjects: savedObjectsService,
});
});
}

View file

@ -12,7 +12,6 @@ import { registerCloudBackupStatusRoutes } from './cloud_backup_status';
import { registerESDeprecationRoutes } from './es_deprecations';
import { registerDeprecationLoggingRoutes } from './deprecation_logging';
import { registerReindexIndicesRoutes } from './reindex_indices';
import { registerTelemetryRoutes } from './telemetry';
import { registerUpdateSettingsRoute } from './update_index_settings';
import { registerMlSnapshotRoutes } from './ml_snapshots';
import { ReindexWorker } from '../lib/reindexing';
@ -24,7 +23,6 @@ export function registerRoutes(dependencies: RouteDependencies, getWorker: () =>
registerESDeprecationRoutes(dependencies);
registerDeprecationLoggingRoutes(dependencies);
registerReindexIndicesRoutes(dependencies, getWorker);
registerTelemetryRoutes(dependencies);
registerUpdateSettingsRoute(dependencies);
registerMlSnapshotRoutes(dependencies);
// Route for cloud to retrieve the upgrade status for ES and Kibana

View file

@ -1,187 +0,0 @@
/*
* 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 { kibanaResponseFactory } from 'src/core/server';
import { savedObjectsServiceMock } from 'src/core/server/mocks';
import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock';
import { createRequestMock } from './__mocks__/request.mock';
jest.mock('../lib/telemetry/es_ui_open_apis', () => ({
upsertUIOpenOption: jest.fn(),
}));
jest.mock('../lib/telemetry/es_ui_reindex_apis', () => ({
upsertUIReindexOption: jest.fn(),
}));
import { upsertUIOpenOption } from '../lib/telemetry/es_ui_open_apis';
import { upsertUIReindexOption } from '../lib/telemetry/es_ui_reindex_apis';
import { registerTelemetryRoutes } from './telemetry';
/**
* Since these route callbacks are so thin, these serve simply as integration tests
* to ensure they're wired up to the lib functions correctly. Business logic is tested
* more thoroughly in the lib/telemetry tests.
*/
describe('Upgrade Assistant Telemetry API', () => {
let routeDependencies: any;
let mockRouter: MockRouter;
beforeEach(() => {
mockRouter = createMockRouter();
routeDependencies = {
getSavedObjectsService: () => savedObjectsServiceMock.create(),
router: mockRouter,
};
registerTelemetryRoutes(routeDependencies);
});
afterEach(() => jest.clearAllMocks());
describe('PUT /api/upgrade_assistant/stats/ui_open', () => {
it('returns correct payload with single option', async () => {
const returnPayload = {
overview: true,
elasticsearch: false,
kibana: false,
};
(upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload);
const resp = await routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_open',
})(
routeHandlerContextMock,
createRequestMock({ body: returnPayload }),
kibanaResponseFactory
);
expect(resp.payload).toEqual(returnPayload);
});
it('returns correct payload with multiple option', async () => {
const returnPayload = {
overview: true,
elasticsearch: true,
kibana: true,
};
(upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload);
const resp = await routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_open',
})(
routeHandlerContextMock,
createRequestMock({
body: {
overview: true,
elasticsearch: true,
kibana: true,
},
}),
kibanaResponseFactory
);
expect(resp.payload).toEqual(returnPayload);
});
it('returns an error if it throws', async () => {
(upsertUIOpenOption as jest.Mock).mockRejectedValue(new Error(`scary error!`));
await expect(
routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_open',
})(
routeHandlerContextMock,
createRequestMock({
body: {
overview: false,
},
}),
kibanaResponseFactory
)
).rejects.toThrowError('scary error!');
});
});
describe('PUT /api/upgrade_assistant/stats/ui_reindex', () => {
it('returns correct payload with single option', async () => {
const returnPayload = {
close: false,
open: false,
start: true,
stop: false,
};
(upsertUIReindexOption as jest.Mock).mockResolvedValue(returnPayload);
const resp = await routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_reindex',
})(
routeHandlerContextMock,
createRequestMock({
body: {
overview: false,
},
}),
kibanaResponseFactory
);
expect(resp.payload).toEqual(returnPayload);
});
it('returns correct payload with multiple option', async () => {
const returnPayload = {
close: true,
open: true,
start: true,
stop: true,
};
(upsertUIReindexOption as jest.Mock).mockResolvedValue(returnPayload);
const resp = await routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_reindex',
})(
routeHandlerContextMock,
createRequestMock({
body: {
close: true,
open: true,
start: true,
stop: true,
},
}),
kibanaResponseFactory
);
expect(resp.payload).toEqual(returnPayload);
});
it('returns an error if it throws', async () => {
(upsertUIReindexOption as jest.Mock).mockRejectedValue(new Error(`scary error!`));
await expect(
routeDependencies.router.getHandler({
method: 'put',
pathPattern: '/api/upgrade_assistant/stats/ui_reindex',
})(
routeHandlerContextMock,
createRequestMock({
body: {
start: false,
},
}),
kibanaResponseFactory
)
).rejects.toThrowError('scary error!');
});
});
});

View file

@ -1,64 +0,0 @@
/*
* 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 { schema } from '@kbn/config-schema';
import { API_BASE_PATH } from '../../common/constants';
import { upsertUIOpenOption } from '../lib/telemetry/es_ui_open_apis';
import { upsertUIReindexOption } from '../lib/telemetry/es_ui_reindex_apis';
import { RouteDependencies } from '../types';
export function registerTelemetryRoutes({ router, getSavedObjectsService }: RouteDependencies) {
router.put(
{
path: `${API_BASE_PATH}/stats/ui_open`,
validate: {
body: schema.object({
overview: schema.boolean({ defaultValue: false }),
elasticsearch: schema.boolean({ defaultValue: false }),
kibana: schema.boolean({ defaultValue: false }),
}),
},
},
async (ctx, request, response) => {
const { elasticsearch, overview, kibana } = request.body;
return response.ok({
body: await upsertUIOpenOption({
savedObjects: getSavedObjectsService(),
elasticsearch,
overview,
kibana,
}),
});
}
);
router.put(
{
path: `${API_BASE_PATH}/stats/ui_reindex`,
validate: {
body: schema.object({
close: schema.boolean({ defaultValue: false }),
open: schema.boolean({ defaultValue: false }),
start: schema.boolean({ defaultValue: false }),
stop: schema.boolean({ defaultValue: false }),
}),
},
},
async (ctx, request, response) => {
const { close, open, start, stop } = request.body;
return response.ok({
body: await upsertUIReindexOption({
savedObjects: getSavedObjectsService(),
close,
open,
start,
stop,
}),
});
}
);
}

View file

@ -15,42 +15,6 @@ export const telemetrySavedObjectType: SavedObjectsType = {
namespaceType: 'agnostic',
mappings: {
properties: {
ui_open: {
properties: {
overview: {
type: 'long',
null_value: 0,
},
elasticsearch: {
type: 'long',
null_value: 0,
},
kibana: {
type: 'long',
null_value: 0,
},
},
},
ui_reindex: {
properties: {
close: {
type: 'long',
null_value: 0,
},
open: {
type: 'long',
null_value: 0,
},
start: {
type: 'long',
null_value: 0,
},
stop: {
type: 'long',
null_value: 0,
},
},
},
features: {
properties: {
deprecation_logging: {