mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Stack Monitoring] Remove 'observability' and 'observabilityShared' plugin dependencies (#203492)
### Summary A recent [bug](https://github.com/elastic/kibana/issues/199902) that affected some of the pages in Stack Monitoring was caused by changes related to the locators of the logs-related apps. The goal of this PR is to reduce the number of Observability dependencies that could potentially cause issues in the app by removing the `observability` and `observabilityShared` plugin dependencies from the `monitoring` plugin. Currently, the `monitoring` plugin is [categorised as observability](https://github.com/elastic/kibana/blob/main/x-pack/plugins/monitoring/kibana.jsonc#L7) but when the dependency on the `infra` plugin is removed, it can be marked as a `platform` plugin. ### Notes for reviewers - The components used to render the header menu as well as the [use_track_metric](https://github.com/elastic/kibana/pull/203492/files#diff-7e39fc60ca80ee551d824ca97f9f879e3364a368a5736cf9178b5943a12ca7a7) hook were copied from the `observabilityShared` plugin - There should be no UX and functionality changes in the stack monitoring header - Usage collection could be verified by searching for UI counters sent by the cluster created for this PR, once telemetry has been sent ### Testing The stateful environment deployed by this PR includes logs and metrics for stack monitoring. Please make sure to select a larger time range (e.g. last 14 days). --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
305bb1b887
commit
7e2f67ebc5
15 changed files with 192 additions and 19 deletions
|
@ -10,6 +10,8 @@ import { CommonAlertParamDetail, ExpressionConfig } from './types/alerts';
|
|||
import { AlertParamType } from './enums';
|
||||
import { validateDuration } from './validate_duration';
|
||||
|
||||
export const USAGE_COLLECTION_APP_NAME = 'stack_monitoring';
|
||||
|
||||
/**
|
||||
* Helper string to add as a tag in every logging call
|
||||
*/
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
"features",
|
||||
"data",
|
||||
"navigation",
|
||||
"observability",
|
||||
"observabilityShared",
|
||||
"dataViews",
|
||||
"unifiedSearch",
|
||||
"share"
|
||||
|
@ -42,4 +40,4 @@
|
|||
"kibanaReact",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 { useEffect, useMemo } from 'react';
|
||||
import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { USAGE_COLLECTION_APP_NAME } from '../../../common/constants';
|
||||
|
||||
/**
|
||||
* Note: The usage_collection plugin will take care of sending this data to the telemetry server.
|
||||
* You can find the metrics that are collected by these hooks in Stack Telemetry.
|
||||
* Search the index `kibana-ui-counter`. You can filter for `eventName` and/or `appName`.
|
||||
*/
|
||||
|
||||
interface TrackOptions {
|
||||
metricType?: UiCounterMetricType;
|
||||
delay?: number; // in ms
|
||||
}
|
||||
type EffectDeps = unknown[];
|
||||
|
||||
interface ServiceDeps {
|
||||
usageCollection: UsageCollectionSetup; // TODO: This should really be start. Looking into it.
|
||||
}
|
||||
|
||||
export type TrackMetricOptions = TrackOptions & { metric: string };
|
||||
export type UiTracker = ReturnType<typeof useUiTracker>;
|
||||
export type TrackEvent = (options: TrackMetricOptions) => void;
|
||||
|
||||
export { METRIC_TYPE };
|
||||
|
||||
export function useUiTracker<Services extends ServiceDeps>(): TrackEvent {
|
||||
const reportUiCounter = useKibana<Services>().services?.usageCollection?.reportUiCounter;
|
||||
const trackEvent = useMemo(() => {
|
||||
return ({ metric, metricType = METRIC_TYPE.COUNT }: TrackMetricOptions) => {
|
||||
if (reportUiCounter) {
|
||||
reportUiCounter(USAGE_COLLECTION_APP_NAME, metricType, metric);
|
||||
}
|
||||
};
|
||||
}, [reportUiCounter]);
|
||||
return trackEvent;
|
||||
}
|
||||
|
||||
export function useTrackMetric<Services extends ServiceDeps>(
|
||||
{ metric, metricType = METRIC_TYPE.COUNT, delay = 0 }: TrackMetricOptions,
|
||||
effectDependencies: EffectDeps = []
|
||||
) {
|
||||
const reportUiCounter = useKibana<Services>().services?.usageCollection?.reportUiCounter;
|
||||
|
||||
useEffect(() => {
|
||||
if (!reportUiCounter) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
'usageCollection.reportUiCounter is unavailable. Ensure this is setup via <KibanaContextProvider />.'
|
||||
);
|
||||
} else {
|
||||
let decoratedMetric = metric;
|
||||
if (delay > 0) {
|
||||
decoratedMetric += `__delayed_${delay}ms`;
|
||||
}
|
||||
const id = setTimeout(
|
||||
() => reportUiCounter(USAGE_COLLECTION_APP_NAME, metricType, decoratedMetric),
|
||||
Math.max(delay, 0)
|
||||
);
|
||||
return () => clearTimeout(id);
|
||||
}
|
||||
// the dependencies are managed externally
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, effectDependencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* useTrackPageview is a convenience wrapper for tracking a pageview
|
||||
* Its metrics will be found at:
|
||||
* stack_stats.kibana.plugins.ui_metric.{app}.pageview__{path}(__delayed_{n}ms)?
|
||||
*/
|
||||
type TrackPageviewProps = TrackOptions & { path: string };
|
||||
|
||||
export function useTrackPageview<Services extends ServiceDeps>(
|
||||
{ path, ...rest }: TrackPageviewProps,
|
||||
effectDependencies: EffectDeps = []
|
||||
) {
|
||||
useTrackMetric<Services>({ ...rest, metric: `pageview__${path}` }, effectDependencies);
|
||||
}
|
|
@ -9,7 +9,6 @@ import { EuiPage, EuiPageBody, EuiPageTemplate, EuiTab, EuiTabs, EuiSpacer } fro
|
|||
import React, { useContext, useState, useEffect, useCallback, FC, PropsWithChildren } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import type { IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser';
|
||||
import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public';
|
||||
import { useTitle } from '../hooks/use_title';
|
||||
import { MonitoringToolbar } from '../../components/shared/toolbar';
|
||||
import { useMonitoringTimeContainerContext } from '../hooks/use_monitoring_time';
|
||||
|
@ -25,6 +24,7 @@ import { AlertsDropdown } from '../../alerts/alerts_dropdown';
|
|||
import { useRequestErrorHandler } from '../hooks/use_request_error_handler';
|
||||
import { SetupModeToggleButton } from '../../components/setup_mode/toggle_button';
|
||||
import { HeaderActionMenuContext } from '../contexts/header_action_menu_context';
|
||||
import { HeaderMenuPortal } from '../../components/header_menu';
|
||||
|
||||
export interface TabMenuItem {
|
||||
id: string;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import HeaderMenuPortal from './header_menu_portal';
|
||||
import { themeServiceMock } from '@kbn/core/public/mocks';
|
||||
|
||||
describe('HeaderMenuPortal', () => {
|
||||
describe('when unmounted', () => {
|
||||
it('calls setHeaderActionMenu with undefined', () => {
|
||||
const setHeaderActionMenu = jest.fn();
|
||||
const theme$ = themeServiceMock.createTheme$();
|
||||
|
||||
const { unmount } = render(
|
||||
<HeaderMenuPortal setHeaderActionMenu={setHeaderActionMenu} theme$={theme$}>
|
||||
test
|
||||
</HeaderMenuPortal>
|
||||
);
|
||||
|
||||
unmount();
|
||||
|
||||
expect(setHeaderActionMenu).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 React, { useEffect, useMemo } from 'react';
|
||||
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
|
||||
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
||||
import type { HeaderMenuPortalProps } from '../../types';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function HeaderMenuPortal({
|
||||
children,
|
||||
setHeaderActionMenu,
|
||||
theme$,
|
||||
}: HeaderMenuPortalProps) {
|
||||
const portalNode = useMemo(() => createHtmlPortalNode(), []);
|
||||
|
||||
useEffect(() => {
|
||||
setHeaderActionMenu((element) => {
|
||||
const mount = toMountPoint(<OutPortal node={portalNode} />, { theme$ });
|
||||
return mount(element);
|
||||
});
|
||||
|
||||
return () => {
|
||||
portalNode.unmount();
|
||||
setHeaderActionMenu(undefined);
|
||||
};
|
||||
}, [portalNode, setHeaderActionMenu, theme$]);
|
||||
|
||||
return <InPortal node={portalNode}>{children}</InPortal>;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 React, { lazy, Suspense } from 'react';
|
||||
import { EuiLoadingSpinner } from '@elastic/eui';
|
||||
import { HeaderMenuPortalProps } from '../../types';
|
||||
|
||||
const HeaderMenuPortalLazy = lazy(() => import('./header_menu_portal'));
|
||||
|
||||
export function HeaderMenuPortal(props: HeaderMenuPortalProps) {
|
||||
return (
|
||||
<Suspense fallback={<EuiLoadingSpinner />}>
|
||||
<HeaderMenuPortalLazy {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { EuiPage, EuiPageBody, EuiPageTemplate, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useTrackPageview } from '@kbn/observability-shared-plugin/public';
|
||||
import { useTrackPageview } from '../../application/hooks/use_track_metric';
|
||||
|
||||
function PageLoadingUI() {
|
||||
return (
|
||||
|
@ -29,8 +29,8 @@ const PageLoadingTracking: React.FunctionComponent<{ pageViewTitle: string }> =
|
|||
pageViewTitle,
|
||||
}) => {
|
||||
const path = pageViewTitle.toLowerCase().replace(/-/g, '').replace(/\s+/g, '_');
|
||||
useTrackPageview({ app: 'stack_monitoring', path });
|
||||
useTrackPageview({ app: 'stack_monitoring', path, delay: 15000 });
|
||||
useTrackPageview({ path });
|
||||
useTrackPageview({ path, delay: 15000 });
|
||||
return <PageLoadingUI />;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
import React from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { METRIC_TYPE, useUiTracker } from '@kbn/observability-shared-plugin/public';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { TELEMETRY_METRIC_BUTTON_CLICK } from '../../../common/constants';
|
||||
import { SetupModeExitButton } from './exit_button';
|
||||
import { useUiTracker } from '../../application/hooks/use_track_metric';
|
||||
|
||||
export interface SetupModeToggleButtonProps {
|
||||
enabled: boolean;
|
||||
|
@ -21,7 +22,7 @@ export const SetupModeToggleButton: React.FC<SetupModeToggleButtonProps> = (
|
|||
props: SetupModeToggleButtonProps
|
||||
) => {
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const trackStat = useUiTracker({ app: 'stack_monitoring' });
|
||||
const trackStat = useUiTracker();
|
||||
|
||||
function toggleSetupMode(enabled: boolean, stat: string) {
|
||||
setIsLoading(true);
|
||||
|
|
|
@ -17,6 +17,7 @@ import { DashboardStart } from '@kbn/dashboard-plugin/public';
|
|||
import { FleetStart } from '@kbn/fleet-plugin/public';
|
||||
import type { InfraClientStartExports } from '@kbn/infra-plugin/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface MonitoringStartPluginDependencies {
|
||||
navigation: NavigationStart;
|
||||
|
@ -43,3 +44,9 @@ export type LegacyMonitoringStartPluginDependencies = MonitoringStartPluginDepen
|
|||
LegacyStartDependencies;
|
||||
|
||||
export type MonitoringStartServices = CoreStart & MonitoringStartPluginDependencies;
|
||||
|
||||
export interface HeaderMenuPortalProps {
|
||||
children: ReactNode;
|
||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||
theme$: AppMountParameters['theme$'];
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
"@kbn/dashboard-plugin",
|
||||
"@kbn/fleet-plugin",
|
||||
"@kbn/shared-ux-router",
|
||||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/alerts-as-data-utils",
|
||||
"@kbn/rule-data-utils",
|
||||
|
@ -48,6 +47,7 @@
|
|||
"@kbn/ui-theme",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
"@kbn/share-plugin",
|
||||
"@kbn/analytics",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -75,12 +75,7 @@ export type HasData<T extends ObservabilityFetchDataPlugins> = (
|
|||
|
||||
export type ObservabilityFetchDataPlugins = Exclude<
|
||||
ObservabilityApp,
|
||||
| 'observability-overview'
|
||||
| 'stack_monitoring'
|
||||
| 'fleet'
|
||||
| 'synthetics'
|
||||
| 'profiling'
|
||||
| 'observability-onboarding'
|
||||
'observability-overview' | 'fleet' | 'synthetics' | 'profiling' | 'observability-onboarding'
|
||||
>;
|
||||
|
||||
export interface DataHandler<
|
||||
|
|
|
@ -80,7 +80,7 @@ export type HasData<T extends ObservabilityFetchDataPlugins> = (
|
|||
|
||||
export type ObservabilityFetchDataPlugins = Exclude<
|
||||
ObservabilityApp,
|
||||
'observability-overview' | 'stack_monitoring' | 'fleet' | 'synthetics'
|
||||
'observability-overview' | 'fleet' | 'synthetics'
|
||||
>;
|
||||
|
||||
export interface DataHandler<
|
||||
|
|
|
@ -15,7 +15,6 @@ export type ObservabilityApp =
|
|||
| 'uptime'
|
||||
| 'synthetics'
|
||||
| 'observability-overview'
|
||||
| 'stack_monitoring'
|
||||
| 'ux'
|
||||
| 'fleet'
|
||||
| 'universal_profiling';
|
||||
|
|
|
@ -13,7 +13,6 @@ export type ObservabilityApp =
|
|||
| 'uptime'
|
||||
| 'synthetics'
|
||||
| 'observability-overview'
|
||||
| 'stack_monitoring'
|
||||
| 'ux'
|
||||
| 'fleet'
|
||||
| 'profiling'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue