mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Performance] Track performance telemetry in APM (#208561)
## Summary Closes https://github.com/elastic/kibana/issues/205396 This PR adds performance telemetry to the missing APM pages
This commit is contained in:
parent
df573d7596
commit
23d926f096
17 changed files with 287 additions and 28 deletions
|
@ -7,10 +7,11 @@
|
|||
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useUiTracker } from '@kbn/observability-shared-plugin/public';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../../common/connections';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
|
@ -24,7 +25,7 @@ export function DependenciesInventoryTable() {
|
|||
const {
|
||||
query: { rangeFrom, rangeTo, environment, kuery, comparisonEnabled, offset },
|
||||
} = useApmParams('/dependencies/inventory');
|
||||
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
@ -52,6 +53,17 @@ export function DependenciesInventoryTable() {
|
|||
[start, end, environment, offset, kuery, comparisonEnabled]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [status, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
const dependencies =
|
||||
data?.dependencies.map((dependency) => {
|
||||
const { location } = dependency;
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { keyBy } from 'lodash';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { useSearchServiceDestinationMetrics } from '../../../../context/time_range_metadata/use_search_service_destination_metrics';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
|
@ -59,7 +60,7 @@ export function DependencyDetailOperationsList() {
|
|||
offset,
|
||||
},
|
||||
} = useApmParams('/dependencies/operations');
|
||||
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const { core } = useApmPluginContext();
|
||||
|
||||
const { isLarge } = useBreakpoints();
|
||||
|
@ -132,6 +133,20 @@ export function DependencyDetailOperationsList() {
|
|||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
comparisonStatsFetch.status === FETCH_STATUS.SUCCESS &&
|
||||
primaryStatsFetch.status === FETCH_STATUS.SUCCESS
|
||||
) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [onPageReady, primaryStatsFetch, comparisonStatsFetch, rangeFrom, rangeTo]);
|
||||
|
||||
const columns: Array<ITableColumn<OperationStatisticsItem>> = [
|
||||
{
|
||||
name: i18n.translate('xpack.apm.dependencyDetailOperationsList.spanNameColumnLabel', {
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../common/connections';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { DependenciesTable } from '../../shared/dependencies_table';
|
||||
import { ServiceLink } from '../../shared/links/apm/service_link';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
|
@ -31,6 +32,7 @@ export function DependenciesDetailTable() {
|
|||
} = useApmParams('/dependencies/overview');
|
||||
|
||||
const { core } = useApmPluginContext();
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
const comparisonEnabled = getComparisonEnabled({
|
||||
core,
|
||||
|
@ -58,6 +60,17 @@ export function DependenciesDetailTable() {
|
|||
[start, end, environment, offset, dependencyName, kuery, comparisonEnabled]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [onPageReady, status, rangeFrom, rangeTo]);
|
||||
|
||||
const dependencies =
|
||||
data?.services.map((dependency) => {
|
||||
const { location } = dependency;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import React, { useEffect } from 'react';
|
||||
import { omit } from 'lodash';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { isOpenTelemetryAgentName, isRumAgentName } from '../../../../common/agent_name';
|
||||
import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
|
@ -82,7 +83,7 @@ export function ErrorGroupDetails() {
|
|||
|
||||
const apmRouter = useApmRouter();
|
||||
const history = useHistory();
|
||||
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const { observabilityAIAssistant } = useApmPluginContext();
|
||||
|
||||
const {
|
||||
|
@ -170,6 +171,20 @@ export function ErrorGroupDetails() {
|
|||
}
|
||||
}, [history, errorId, errorSamplesData, errorSamplesFetchStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
errorSamplesFetchStatus === FETCH_STATUS.SUCCESS &&
|
||||
errorDistributionStatus === FETCH_STATUS.SUCCESS
|
||||
) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [onPageReady, errorSamplesFetchStatus, errorDistributionStatus, rangeFrom, rangeTo]);
|
||||
|
||||
const { agentName } = useApmServiceContext();
|
||||
const isOpenTelemetryAgent = isOpenTelemetryAgentName(agentName as AgentName);
|
||||
const isRumAgent = isRumAgentName(agentName as AgentName);
|
||||
|
|
|
@ -10,6 +10,13 @@ import { render } from '@testing-library/react';
|
|||
import React from 'react';
|
||||
import * as stories from './error_group_list.stories';
|
||||
|
||||
// Mock the usePerformanceContext hook
|
||||
jest.mock('@kbn/ebt-tools', () => ({
|
||||
usePerformanceContext: () => ({
|
||||
onPageReady: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const { Example } = composeStories(stories);
|
||||
|
||||
describe('ErrorGroupList', () => {
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
import { EuiBadge, EuiIconTip, EuiToolTip, RIGHT_ALIGNMENT } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
||||
import { apmEnableTableSearchBar } from '@kbn/observability-plugin/common';
|
||||
import { isPending } from '../../../../hooks/use_fetcher';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { FETCH_STATUS, isPending } from '../../../../hooks/use_fetcher';
|
||||
import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n';
|
||||
import { asBigNumber } from '../../../../../common/utils/formatters';
|
||||
import { useAnyOfApmParams } from '../../../../hooks/use_apm_params';
|
||||
|
@ -55,6 +56,7 @@ interface Props {
|
|||
comparisonEnabled?: boolean;
|
||||
saveTableOptionsToUrl?: boolean;
|
||||
showPerPageOptions?: boolean;
|
||||
onLoadTable?: () => void;
|
||||
}
|
||||
|
||||
const defaultSorting = {
|
||||
|
@ -69,6 +71,7 @@ export function ErrorGroupList({
|
|||
comparisonEnabled,
|
||||
saveTableOptionsToUrl,
|
||||
showPerPageOptions = true,
|
||||
onLoadTable,
|
||||
}: Props) {
|
||||
const { query } = useAnyOfApmParams(
|
||||
'/services/{serviceName}/overview',
|
||||
|
@ -79,10 +82,10 @@ export function ErrorGroupList({
|
|||
|
||||
const isTableSearchBarEnabled = core.uiSettings.get<boolean>(apmEnableTableSearchBar, true);
|
||||
|
||||
const { offset } = query;
|
||||
const { offset, rangeFrom, rangeTo } = query;
|
||||
|
||||
const [renderedItems, setRenderedItems] = useState<ErrorGroupItem[]>([]);
|
||||
|
||||
const hasTableLoaded = useRef(false);
|
||||
const [sorting, setSorting] = useState<TableOptions<ErrorGroupItem>['sort']>(defaultSorting);
|
||||
|
||||
const {
|
||||
|
@ -95,6 +98,36 @@ export function ErrorGroupList({
|
|||
|
||||
const isMainStatsLoading = isPending(mainStatisticsStatus);
|
||||
const isDetailedStatsLoading = isPending(detailedStatisticsStatus);
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
useEffect(() => {
|
||||
// this component is used both for the service overview tab and the errors tab,
|
||||
// onLoadTable will be defined if it's the service overview tab
|
||||
if (
|
||||
mainStatisticsStatus === FETCH_STATUS.SUCCESS &&
|
||||
detailedStatisticsStatus === FETCH_STATUS.SUCCESS &&
|
||||
!hasTableLoaded.current
|
||||
) {
|
||||
if (onLoadTable) {
|
||||
onLoadTable();
|
||||
} else {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
hasTableLoaded.current = true;
|
||||
}
|
||||
}, [
|
||||
mainStatisticsStatus,
|
||||
detailedStatisticsStatus,
|
||||
onLoadTable,
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
onPageReady,
|
||||
]);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const groupIdColumn: ITableColumn<ErrorGroupItem> = {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
import type { EuiFlexGroupProps } from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { chartHeight } from '..';
|
||||
import type { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent';
|
||||
import {
|
||||
|
@ -44,6 +45,24 @@ export function ApmOverview() {
|
|||
} = useApmParams('/services/{serviceName}/overview');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
const [haveTablesLoaded, setHaveTablesLoaded] = useState({
|
||||
transactions: false,
|
||||
dependencies: false,
|
||||
errors: false,
|
||||
});
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
useEffect(() => {
|
||||
const { transactions, dependencies, errors } = haveTablesLoaded;
|
||||
if (transactions && dependencies && errors) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [haveTablesLoaded, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
const isRumAgent = isRumAgentName(agentName);
|
||||
const isOpenTelemetryAgent = isOpenTelemetryAgentName(agentName as AgentName);
|
||||
|
@ -62,6 +81,10 @@ export function ApmOverview() {
|
|||
false
|
||||
);
|
||||
|
||||
const onLoadTable = (key: string) => {
|
||||
setHaveTablesLoaded((currentValues) => ({ ...currentValues, [key]: true }));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{!sloCalloutDismissed && (
|
||||
|
@ -98,6 +121,7 @@ export function ApmOverview() {
|
|||
kuery={kuery}
|
||||
environment={environment}
|
||||
fixedHeight={true}
|
||||
onLoadTable={() => onLoadTable('transactions')}
|
||||
start={start}
|
||||
end={end}
|
||||
showPerPageOptions={false}
|
||||
|
@ -121,7 +145,10 @@ export function ApmOverview() {
|
|||
)}
|
||||
<EuiFlexItem grow={7}>
|
||||
<EuiPanel hasBorder={true}>
|
||||
<ServiceOverviewErrorsTable serviceName={serviceName} />
|
||||
<ServiceOverviewErrorsTable
|
||||
serviceName={serviceName}
|
||||
onLoadTable={() => onLoadTable('errors')}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -151,6 +178,7 @@ export function ApmOverview() {
|
|||
<EuiFlexItem grow={7}>
|
||||
<EuiPanel hasBorder={true}>
|
||||
<ServiceOverviewDependenciesTable
|
||||
onLoadTable={() => onLoadTable('dependencies')}
|
||||
fixedHeight={true}
|
||||
showPerPageOptions={false}
|
||||
link={
|
||||
|
|
|
@ -12,6 +12,13 @@ import * as stories from './service_overview.stories';
|
|||
import * as useAdHocApmDataView from '../../../hooks/use_adhoc_apm_data_view';
|
||||
import { renderWithTheme } from '../../../utils/test_helpers';
|
||||
|
||||
// Mock the usePerformanceContext hook
|
||||
jest.mock('@kbn/ebt-tools', () => ({
|
||||
usePerformanceContext: () => ({
|
||||
onPageReady: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const { Example } = composeStories(stories);
|
||||
|
||||
describe('ServiceOverview', () => {
|
||||
|
|
|
@ -9,8 +9,9 @@ import { EuiIconTip } from '@elastic/eui';
|
|||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { useUiTracker } from '@kbn/observability-shared-plugin/public';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { FETCH_STATUS, useUiTracker } from '@kbn/observability-shared-plugin/public';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options';
|
||||
import { getNodeName, NodeType } from '../../../../../common/connections';
|
||||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
|
@ -26,6 +27,7 @@ interface ServiceOverviewDependenciesTableProps {
|
|||
link?: ReactNode;
|
||||
showPerPageOptions?: boolean;
|
||||
showSparkPlots?: boolean;
|
||||
onLoadTable?: () => void;
|
||||
}
|
||||
|
||||
export function ServiceOverviewDependenciesTable({
|
||||
|
@ -33,6 +35,7 @@ export function ServiceOverviewDependenciesTable({
|
|||
link,
|
||||
showPerPageOptions = true,
|
||||
showSparkPlots,
|
||||
onLoadTable,
|
||||
}: ServiceOverviewDependenciesTableProps) {
|
||||
const {
|
||||
query: {
|
||||
|
@ -50,9 +53,9 @@ export function ServiceOverviewDependenciesTable({
|
|||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const { serviceName, transactionType } = useApmServiceContext();
|
||||
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const trackEvent = useUiTracker();
|
||||
|
||||
const hasTableLoaded = useRef(false);
|
||||
const { data, status } = useFetcher(
|
||||
(callApmApi) => {
|
||||
if (!start || !end) {
|
||||
|
@ -75,6 +78,24 @@ export function ServiceOverviewDependenciesTable({
|
|||
[start, end, serviceName, environment, offset, comparisonEnabled]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// this component is used both for the service overview tab and the transactions tab,
|
||||
// onLoadTable will be defined if it's the service overview tab
|
||||
if (status === FETCH_STATUS.SUCCESS && !hasTableLoaded.current) {
|
||||
if (onLoadTable) {
|
||||
onLoadTable();
|
||||
} else {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
hasTableLoaded.current = true;
|
||||
}
|
||||
}, [status, onLoadTable, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
const dependencies =
|
||||
data?.serviceDependencies.map((dependency) => {
|
||||
const { location } = dependency;
|
||||
|
|
|
@ -15,9 +15,10 @@ import { ErrorGroupList } from '../../error_group_overview/error_group_list';
|
|||
|
||||
interface Props {
|
||||
serviceName: string;
|
||||
onLoadTable?: () => void;
|
||||
}
|
||||
|
||||
export function ServiceOverviewErrorsTable({ serviceName }: Props) {
|
||||
export function ServiceOverviewErrorsTable({ serviceName, onLoadTable }: Props) {
|
||||
const { query } = useApmParams('/services/{serviceName}/overview');
|
||||
|
||||
return (
|
||||
|
@ -46,6 +47,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
|
|||
<OverviewTableContainer fixedHeight={true} isEmptyAndNotInitiated={false}>
|
||||
<ErrorGroupList
|
||||
serviceName={serviceName}
|
||||
onLoadTable={onLoadTable}
|
||||
initialPageSize={5}
|
||||
isCompactMode={true}
|
||||
saveTableOptionsToUrl={false}
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState, useEffect } from 'react';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
import { useTraceExplorerSamples } from '../../../hooks/use_trace_explorer_samples';
|
||||
|
@ -16,7 +17,8 @@ export function TraceExplorerAggregatedCriticalPath() {
|
|||
} = useApmParams('/traces/explorer/critical_path');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const [hasLoadedTable, setHasLoadedTable] = useState(false);
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const {
|
||||
data: { traceSamples },
|
||||
status: samplesFetchStatus,
|
||||
|
@ -26,8 +28,24 @@ export function TraceExplorerAggregatedCriticalPath() {
|
|||
return traceSamples.map((sample) => sample.traceId);
|
||||
}, [traceSamples]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLoadedTable) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
customMetrics: {
|
||||
key1: 'traceIds',
|
||||
value1: traceIds.length,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [hasLoadedTable, onPageReady, rangeFrom, rangeTo, traceIds]);
|
||||
|
||||
return (
|
||||
<CriticalPathFlamegraph
|
||||
onLoadTable={() => setHasLoadedTable(true)}
|
||||
start={start}
|
||||
end={end}
|
||||
traceIds={traceIds}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useTimeRange } from '../../../hooks/use_time_range';
|
||||
import { useTraceExplorerSamples } from '../../../hooks/use_trace_explorer_samples';
|
||||
|
@ -18,7 +19,7 @@ import type { TransactionTab } from '../transaction_details/waterfall_with_summa
|
|||
|
||||
export function TraceExplorerWaterfall() {
|
||||
const history = useHistory();
|
||||
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const traceSamplesFetchResult = useTraceExplorerSamples();
|
||||
|
||||
const {
|
||||
|
@ -55,6 +56,21 @@ export function TraceExplorerWaterfall() {
|
|||
end,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (waterfallFetchResult.status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
customMetrics: {
|
||||
key1: 'traceDocsTotal',
|
||||
value1: waterfallFetchResult.waterfall.traceDocsTotal,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [waterfallFetchResult, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
const onSampleClick = useCallback(
|
||||
(sample: any) => {
|
||||
push(history, {
|
||||
|
|
|
@ -11,6 +11,7 @@ import type { XYBrushEvent } from '@elastic/charts';
|
|||
import { EuiPanel, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui';
|
||||
import { omit } from 'lodash';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { maybe } from '../../../../common/utils/maybe';
|
||||
import { useLegacyUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
|
||||
|
@ -47,6 +48,7 @@ export function TransactionDetailsTabs() {
|
|||
|
||||
const isCriticalPathFeatureEnabled = useCriticalPathFeatureEnabledSetting();
|
||||
const isTransactionProfilingEnabled = useTransactionProfilingSetting();
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
const availableTabs = useMemo(() => {
|
||||
const tabs = [traceSamplesTab, latencyCorrelationsTab, failedTransactionsCorrelationsTab];
|
||||
|
@ -68,7 +70,7 @@ export function TransactionDetailsTabs() {
|
|||
const { component: TabContent } =
|
||||
availableTabs.find((tab) => tab.key === currentTab) ?? traceSamplesTab;
|
||||
|
||||
const { environment, kuery, transactionName } = query;
|
||||
const { environment, kuery, transactionName, rangeFrom, rangeTo } = query;
|
||||
|
||||
const traceSamplesFetchResult = useTransactionTraceSamplesFetcher({
|
||||
transactionName,
|
||||
|
@ -90,6 +92,21 @@ export function TransactionDetailsTabs() {
|
|||
setCurrentTab(traceSamplesTabKey);
|
||||
}, [traceSamplesTabKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (traceSamplesFetchResult.status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
customMetrics: {
|
||||
key1: 'traceDocsTotal',
|
||||
value1: traceSamplesFetchResult.data?.traceSamples?.length ?? 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [traceSamplesFetchResult, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectedSample = traceSamplesFetchResult.data?.traceSamples.find(
|
||||
(sample) => sample.transactionId === transactionId && sample.traceId === traceId
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import { isServerlessAgentName } from '../../../../common/agent_name';
|
||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
|
@ -36,10 +37,22 @@ export function TransactionOverview() {
|
|||
} = useApmParams('/services/{serviceName}/transactions');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
|
||||
|
||||
const [hasLoadedTable, setHasLoadedTable] = useState(false);
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const { transactionType, fallbackToTransactions, serverlessType, serviceName } =
|
||||
useApmServiceContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLoadedTable) {
|
||||
onPageReady({
|
||||
meta: {
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [hasLoadedTable, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
// redirect to first transaction type
|
||||
|
@ -109,6 +122,7 @@ export function TransactionOverview() {
|
|||
hideViewTransactionsLink
|
||||
numberOfTransactionsPerPage={10}
|
||||
showMaxTransactionGroupsExceededWarning
|
||||
onLoadTable={() => setHasLoadedTable(true)}
|
||||
environment={environment}
|
||||
kuery={kuery}
|
||||
start={start}
|
||||
|
|
|
@ -25,6 +25,13 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
|||
import { ApmTimeRangeMetadataContextProvider } from '../../../context/time_range_metadata/time_range_metadata_context';
|
||||
import { MockTimeRangeContextProvider } from '../../../context/time_range_metadata/mock_time_range_metadata_context_provider';
|
||||
|
||||
// Mock the usePerformanceContext hook
|
||||
jest.mock('@kbn/ebt-tools', () => ({
|
||||
usePerformanceContext: () => ({
|
||||
onPageReady: jest.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const KibanaReactContext = createKibanaReactContext({
|
||||
uiSettings: { get: () => true },
|
||||
usageCollection: { reportUiCounter: () => {} },
|
||||
|
|
|
@ -10,9 +10,9 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, euiPaletteColorBlind } fr
|
|||
import { css } from '@emotion/css';
|
||||
import { useChartThemes } from '@kbn/observability-shared-plugin/public';
|
||||
import { uniqueId } from 'lodash';
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { FETCH_STATUS } from '../../../hooks/use_fetcher';
|
||||
import { FETCH_STATUS } from '../../../hooks/use_fetcher';
|
||||
import { useFetcher, isPending } from '../../../hooks/use_fetcher';
|
||||
import { CriticalPathFlamegraphTooltip } from './critical_path_flamegraph_tooltip';
|
||||
import { criticalPathToFlamegraph } from './critical_path_to_flamegraph';
|
||||
|
@ -27,9 +27,10 @@ export function CriticalPathFlamegraph(
|
|||
end: string;
|
||||
traceIds: string[];
|
||||
traceIdsFetchStatus: FETCH_STATUS;
|
||||
onLoadTable?: () => void;
|
||||
} & ({ serviceName: string; transactionName: string } | {})
|
||||
) {
|
||||
const { start, end, traceIds, traceIdsFetchStatus } = props;
|
||||
const { start, end, traceIds, traceIdsFetchStatus, onLoadTable } = props;
|
||||
|
||||
const serviceName = 'serviceName' in props ? props.serviceName : null;
|
||||
const transactionName = 'transactionName' in props ? props.transactionName : null;
|
||||
|
@ -40,6 +41,7 @@ export function CriticalPathFlamegraph(
|
|||
// of the search.
|
||||
const timerange = useRef({ start, end });
|
||||
timerange.current = { start, end };
|
||||
const [hasTableLoaded, setHasTableLoaded] = useState(false);
|
||||
|
||||
const { data: { criticalPath } = { criticalPath: null }, status: criticalPathFetchStatus } =
|
||||
useFetcher(
|
||||
|
@ -63,6 +65,24 @@ export function CriticalPathFlamegraph(
|
|||
[timerange, traceIds, serviceName, transactionName]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
criticalPathFetchStatus === FETCH_STATUS.SUCCESS &&
|
||||
traceIdsFetchStatus === FETCH_STATUS.SUCCESS &&
|
||||
onLoadTable &&
|
||||
!hasTableLoaded
|
||||
) {
|
||||
onLoadTable();
|
||||
setHasTableLoaded(true);
|
||||
}
|
||||
}, [
|
||||
criticalPathFetchStatus,
|
||||
onLoadTable,
|
||||
hasTableLoaded,
|
||||
traceIdsFetchStatus,
|
||||
setHasTableLoaded,
|
||||
]);
|
||||
|
||||
const chartThemes = useChartThemes();
|
||||
|
||||
const isLoading = isPending(traceIdsFetchStatus) || isPending(criticalPathFetchStatus);
|
||||
|
|
|
@ -55,6 +55,7 @@ interface Props {
|
|||
end: string;
|
||||
saveTableOptionsToUrl?: boolean;
|
||||
showSparkPlots?: boolean;
|
||||
onLoadTable?: () => void;
|
||||
}
|
||||
|
||||
export function TransactionsTable({
|
||||
|
@ -69,6 +70,7 @@ export function TransactionsTable({
|
|||
start,
|
||||
end,
|
||||
saveTableOptionsToUrl = false,
|
||||
onLoadTable,
|
||||
showSparkPlots,
|
||||
}: Props) {
|
||||
const { link } = useApmRouter();
|
||||
|
@ -89,7 +91,7 @@ export function TransactionsTable({
|
|||
const shouldShowSparkPlots = showSparkPlots ?? !isLarge;
|
||||
const { transactionType, serviceName } = useApmServiceContext();
|
||||
const [searchQuery, setSearchQueryDebounced] = useStateDebounced('');
|
||||
|
||||
const [hasTableLoaded, setHasTableLoaded] = useState(false);
|
||||
const [renderedItems, setRenderedItems] = useState<ApiResponse['transactionGroups']>([]);
|
||||
|
||||
const { mainStatistics, mainStatisticsStatus, detailedStatistics, detailedStatisticsStatus } =
|
||||
|
@ -107,6 +109,18 @@ export function TransactionsTable({
|
|||
transactionType,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
mainStatisticsStatus === FETCH_STATUS.SUCCESS &&
|
||||
detailedStatisticsStatus === FETCH_STATUS.SUCCESS &&
|
||||
onLoadTable &&
|
||||
!hasTableLoaded
|
||||
) {
|
||||
onLoadTable();
|
||||
setHasTableLoaded(true);
|
||||
}
|
||||
}, [mainStatisticsStatus, detailedStatisticsStatus, onLoadTable, hasTableLoaded]);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return getColumns({
|
||||
serviceName,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue