mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[APM] Add storage summary stats to report (#163309)
Closes https://github.com/elastic/kibana/issues/160013
This commit is contained in:
parent
f4e62c1c74
commit
863ea15bde
3 changed files with 91 additions and 42 deletions
|
@ -19,18 +19,26 @@ import {
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||||
import { IndexLifecyclePhaseSelect } from './index_lifecycle_phase_select';
|
import { IndexLifecyclePhaseSelect } from './index_lifecycle_phase_select';
|
||||||
import { ServicesTable } from './services_table';
|
import { ServicesTable } from './services_table';
|
||||||
import { SearchBar } from '../../shared/search_bar/search_bar';
|
import { SearchBar } from '../../shared/search_bar/search_bar';
|
||||||
import { StorageChart } from './storage_chart';
|
import { StorageChart } from './storage_chart';
|
||||||
import { PermissionDenied } from './prompts/permission_denied';
|
import { PermissionDenied } from './prompts/permission_denied';
|
||||||
import { useFetcher, FETCH_STATUS } from '../../../hooks/use_fetcher';
|
import {
|
||||||
|
useFetcher,
|
||||||
|
FETCH_STATUS,
|
||||||
|
isPending,
|
||||||
|
} from '../../../hooks/use_fetcher';
|
||||||
import { SummaryStats } from './summary_stats';
|
import { SummaryStats } from './summary_stats';
|
||||||
import { ApmEnvironmentFilter } from '../../shared/environment_filter';
|
import { ApmEnvironmentFilter } from '../../shared/environment_filter';
|
||||||
import { TipsAndResources } from './resources/tips_and_resources';
|
import { TipsAndResources } from './resources/tips_and_resources';
|
||||||
import { useLocalStorage } from '../../../hooks/use_local_storage';
|
import { useLocalStorage } from '../../../hooks/use_local_storage';
|
||||||
import { getKibanaAdvancedSettingsHref } from './get_storage_explorer_links';
|
import { getKibanaAdvancedSettingsHref } from './get_storage_explorer_links';
|
||||||
|
import { useProgressiveFetcher } from '../../../hooks/use_progressive_fetcher';
|
||||||
|
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||||
|
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||||
|
|
||||||
type CalloutType = 'crossClusterSearch' | 'optimizePerformance';
|
type CalloutType = 'crossClusterSearch' | 'optimizePerformance';
|
||||||
|
|
||||||
|
@ -48,6 +56,11 @@ const dismissButtonText = i18n.translate(
|
||||||
|
|
||||||
export function StorageExplorer() {
|
export function StorageExplorer() {
|
||||||
const { core } = useApmPluginContext();
|
const { core } = useApmPluginContext();
|
||||||
|
const {
|
||||||
|
query: { rangeFrom, rangeTo, environment, kuery, indexLifecyclePhase },
|
||||||
|
} = useApmParams('/storage-explorer');
|
||||||
|
|
||||||
|
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||||
|
|
||||||
const [calloutDismissed, setCalloutDismissed] = useLocalStorage(
|
const [calloutDismissed, setCalloutDismissed] = useLocalStorage(
|
||||||
'apm.storageExplorer.calloutDismissed',
|
'apm.storageExplorer.calloutDismissed',
|
||||||
|
@ -72,6 +85,28 @@ export function StorageExplorer() {
|
||||||
[calloutDismissed]
|
[calloutDismissed]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { data: summaryStatsData, status: summaryStatsStatus } =
|
||||||
|
useProgressiveFetcher(
|
||||||
|
(callApmApi) => {
|
||||||
|
return callApmApi('GET /internal/apm/storage_explorer_summary_stats', {
|
||||||
|
params: {
|
||||||
|
query: {
|
||||||
|
indexLifecyclePhase,
|
||||||
|
environment,
|
||||||
|
kuery,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[indexLifecyclePhase, environment, kuery, start, end]
|
||||||
|
);
|
||||||
|
|
||||||
|
const loadingSummaryStats = isPending(summaryStatsStatus);
|
||||||
|
|
||||||
|
const hasSummaryStatsData = !isEmpty(summaryStatsData);
|
||||||
|
|
||||||
const loading = hasPrivilegesStatus === FETCH_STATUS.LOADING;
|
const loading = hasPrivilegesStatus === FETCH_STATUS.LOADING;
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
@ -190,12 +225,19 @@ export function StorageExplorer() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
<SummaryStats />
|
<SummaryStats
|
||||||
|
data={summaryStatsData}
|
||||||
|
loading={loadingSummaryStats}
|
||||||
|
hasData={hasSummaryStatsData}
|
||||||
|
/>
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
<EuiPanel hasShadow={false} hasBorder={true}>
|
<EuiPanel hasShadow={false} hasBorder={true}>
|
||||||
<StorageChart />
|
<StorageChart />
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
<ServicesTable />
|
<ServicesTable
|
||||||
|
summaryStatsData={summaryStatsData}
|
||||||
|
loadingSummaryStats={loadingSummaryStats}
|
||||||
|
/>
|
||||||
</EuiPanel>
|
</EuiPanel>
|
||||||
<EuiSpacer />
|
<EuiSpacer />
|
||||||
<TipsAndResources />
|
<TipsAndResources />
|
||||||
|
|
|
@ -28,7 +28,10 @@ import { isEmpty } from 'lodash';
|
||||||
import { downloadJson } from '../../../../utils/download_json';
|
import { downloadJson } from '../../../../utils/download_json';
|
||||||
import { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent';
|
import { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent';
|
||||||
import { EnvironmentBadge } from '../../../shared/environment_badge';
|
import { EnvironmentBadge } from '../../../shared/environment_badge';
|
||||||
import { asPercent } from '../../../../../common/utils/formatters';
|
import {
|
||||||
|
asPercent,
|
||||||
|
asTransactionRate,
|
||||||
|
} from '../../../../../common/utils/formatters';
|
||||||
import { ServiceLink } from '../../../shared/links/apm/service_link';
|
import { ServiceLink } from '../../../shared/links/apm/service_link';
|
||||||
import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip';
|
import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip';
|
||||||
import { StorageDetailsPerService } from './storage_details_per_service';
|
import { StorageDetailsPerService } from './storage_details_per_service';
|
||||||
|
@ -42,6 +45,7 @@ import { useProgressiveFetcher } from '../../../../hooks/use_progressive_fetcher
|
||||||
import { useTimeRange } from '../../../../hooks/use_time_range';
|
import { useTimeRange } from '../../../../hooks/use_time_range';
|
||||||
import { SizeLabel } from './size_label';
|
import { SizeLabel } from './size_label';
|
||||||
import { joinByKey } from '../../../../../common/utils/join_by_key';
|
import { joinByKey } from '../../../../../common/utils/join_by_key';
|
||||||
|
import { APIReturnType } from '../../../../services/rest/create_call_apm_api';
|
||||||
|
|
||||||
interface StorageExplorerItem {
|
interface StorageExplorerItem {
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
|
@ -57,8 +61,15 @@ enum StorageExplorerFieldName {
|
||||||
Sampling = 'sampling',
|
Sampling = 'sampling',
|
||||||
Size = 'size',
|
Size = 'size',
|
||||||
}
|
}
|
||||||
|
interface Props {
|
||||||
|
summaryStatsData?: APIReturnType<'GET /internal/apm/storage_explorer_summary_stats'>;
|
||||||
|
loadingSummaryStats: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function ServicesTable() {
|
export function ServicesTable({
|
||||||
|
summaryStatsData,
|
||||||
|
loadingSummaryStats,
|
||||||
|
}: Props) {
|
||||||
const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<
|
const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<
|
||||||
Record<string, ReactNode>
|
Record<string, ReactNode>
|
||||||
>({});
|
>({});
|
||||||
|
@ -283,6 +294,9 @@ export function ServicesTable() {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const isDownloadButtonDisable =
|
||||||
|
isEmpty(serviceStatisticsItems) || loadingSummaryStats;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiPanel
|
<EuiPanel
|
||||||
hasShadow={false}
|
hasShadow={false}
|
||||||
|
@ -295,7 +309,7 @@ export function ServicesTable() {
|
||||||
<EuiButton
|
<EuiButton
|
||||||
data-test-subj="StorageExplorerDownloadReportButton"
|
data-test-subj="StorageExplorerDownloadReportButton"
|
||||||
iconType="download"
|
iconType="download"
|
||||||
isDisabled={isEmpty(serviceStatisticsItems)}
|
isDisabled={isDownloadButtonDisable}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
downloadJson({
|
downloadJson({
|
||||||
fileName: `storage-explorefpr-${moment(Date.now()).format(
|
fileName: `storage-explorefpr-${moment(Date.now()).format(
|
||||||
|
@ -309,6 +323,25 @@ export function ServicesTable() {
|
||||||
kuery,
|
kuery,
|
||||||
indexLifecyclePhase,
|
indexLifecyclePhase,
|
||||||
},
|
},
|
||||||
|
summary: {
|
||||||
|
totalSize: asDynamicBytes(summaryStatsData?.totalSize),
|
||||||
|
diskSpaceUsedPct: asPercent(
|
||||||
|
summaryStatsData?.diskSpaceUsedPct,
|
||||||
|
1
|
||||||
|
),
|
||||||
|
estimatedIncrementalSize: asDynamicBytes(
|
||||||
|
summaryStatsData?.estimatedIncrementalSize
|
||||||
|
),
|
||||||
|
dailyDataGeneration: asDynamicBytes(
|
||||||
|
summaryStatsData?.dailyDataGeneration
|
||||||
|
),
|
||||||
|
tracesPerMinute: asTransactionRate(
|
||||||
|
summaryStatsData?.tracesPerMinute
|
||||||
|
),
|
||||||
|
numberOfServices: (
|
||||||
|
summaryStatsData?.numberOfServices ?? 0
|
||||||
|
).toString(),
|
||||||
|
},
|
||||||
services: serviceStatisticsItems.map((item) => ({
|
services: serviceStatisticsItems.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
sampling: asPercent(item?.sampling, 1),
|
sampling: asPercent(item?.sampling, 1),
|
||||||
|
|
|
@ -22,34 +22,29 @@ import {
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { useEuiTheme } from '@elastic/eui';
|
import { useEuiTheme } from '@elastic/eui';
|
||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
import { isEmpty } from 'lodash';
|
|
||||||
import { useProgressiveFetcher } from '../../../hooks/use_progressive_fetcher';
|
|
||||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
|
||||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||||
import { asDynamicBytes, asPercent } from '../../../../common/utils/formatters';
|
import { asDynamicBytes, asPercent } from '../../../../common/utils/formatters';
|
||||||
import { useApmRouter } from '../../../hooks/use_apm_router';
|
import { useApmRouter } from '../../../hooks/use_apm_router';
|
||||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||||
import { isPending } from '../../../hooks/use_fetcher';
|
|
||||||
import { asTransactionRate } from '../../../../common/utils/formatters';
|
import { asTransactionRate } from '../../../../common/utils/formatters';
|
||||||
import { getIndexManagementHref } from './get_storage_explorer_links';
|
import { getIndexManagementHref } from './get_storage_explorer_links';
|
||||||
|
import { APIReturnType } from '../../../services/rest/create_call_apm_api';
|
||||||
|
|
||||||
export function SummaryStats() {
|
interface Props {
|
||||||
|
data?: APIReturnType<'GET /internal/apm/storage_explorer_summary_stats'>;
|
||||||
|
loading: boolean;
|
||||||
|
hasData: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SummaryStats({ data, loading, hasData }: Props) {
|
||||||
const router = useApmRouter();
|
const router = useApmRouter();
|
||||||
const { core } = useApmPluginContext();
|
const { core } = useApmPluginContext();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
query: {
|
query: { rangeFrom, rangeTo, environment, kuery, comparisonEnabled },
|
||||||
rangeFrom,
|
|
||||||
rangeTo,
|
|
||||||
environment,
|
|
||||||
kuery,
|
|
||||||
indexLifecyclePhase,
|
|
||||||
comparisonEnabled,
|
|
||||||
},
|
|
||||||
} = useApmParams('/storage-explorer');
|
} = useApmParams('/storage-explorer');
|
||||||
|
|
||||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
|
||||||
|
|
||||||
const serviceInventoryLink = router.link('/services', {
|
const serviceInventoryLink = router.link('/services', {
|
||||||
query: {
|
query: {
|
||||||
rangeFrom,
|
rangeFrom,
|
||||||
|
@ -61,27 +56,6 @@ export function SummaryStats() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data, status } = useProgressiveFetcher(
|
|
||||||
(callApmApi) => {
|
|
||||||
return callApmApi('GET /internal/apm/storage_explorer_summary_stats', {
|
|
||||||
params: {
|
|
||||||
query: {
|
|
||||||
indexLifecyclePhase,
|
|
||||||
environment,
|
|
||||||
kuery,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[indexLifecyclePhase, environment, kuery, start, end]
|
|
||||||
);
|
|
||||||
|
|
||||||
const loading = isPending(status);
|
|
||||||
|
|
||||||
const hasData = !isEmpty(data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiPanel
|
<EuiPanel
|
||||||
hasBorder={true}
|
hasBorder={true}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue