mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Upgrade Assistant] Refactor telemetry (#112177)
This commit is contained in:
parent
ca55b003dc
commit
991d24bad2
32 changed files with 207 additions and 809 deletions
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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).
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}
|
||||
>
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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'
|
||||
)}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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}`,
|
||||
|
|
|
@ -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();
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
};
|
||||
}
|
|
@ -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`]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
};
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
}),
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue