[APM] Sanitize duration display issues w/ hidden root traces (#39207)
* [APM] Sanitize duration display issues w/ hidden root traces Closes #35152. This change make sure that if the parent transaction is not visible, and the top most visible transaction is async and longer than its parent: - duration of trace is displayed as > 100% with a tooltip explaining _why_ this happens - the x-axis highlight will use the duration of the topmost visible transaction rather than the parent * Give trace label explanation a unique id * Update tooltip label according to feedback * Update x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/StickyTransactionProperties.tsx Co-Authored-By: Casper Hübertz <casper@formgeist.com>
This commit is contained in:
parent
8c8ef33d36
commit
1483a6eeef
|
@ -7,6 +7,7 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { idx } from '@kbn/elastic-idx';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import {
|
||||
TRANSACTION_DURATION,
|
||||
TRANSACTION_RESULT,
|
||||
|
@ -79,7 +80,22 @@ export function StickyTransactionProperties({
|
|||
defaultMessage: '% of trace'
|
||||
}
|
||||
),
|
||||
val: asPercent(duration, totalDuration, NOT_AVAILABLE_LABEL),
|
||||
val:
|
||||
totalDuration !== undefined && duration > totalDuration ? (
|
||||
<EuiToolTip
|
||||
content={i18n.translate(
|
||||
'xpack.apm.transactionDetails.percentOfTraceLabelExplanation',
|
||||
{
|
||||
defaultMessage:
|
||||
'The % of trace exceeds 100% because this transaction takes longer than the root transaction.'
|
||||
}
|
||||
)}
|
||||
>
|
||||
<span>>100%</span>
|
||||
</EuiToolTip>
|
||||
) : (
|
||||
asPercent(duration, totalDuration, NOT_AVAILABLE_LABEL)
|
||||
),
|
||||
width: '25%'
|
||||
},
|
||||
{
|
||||
|
|
|
@ -136,7 +136,6 @@ export class Waterfall extends Component<Props> {
|
|||
<Timeline
|
||||
agentMarks={this.props.agentMarks}
|
||||
duration={waterfall.duration}
|
||||
traceRootDuration={waterfall.traceRootDuration}
|
||||
height={waterfallHeight}
|
||||
margins={TIMELINE_MARGINS}
|
||||
/>
|
||||
|
|
|
@ -15,26 +15,26 @@ import { px } from '../../../../style/variables';
|
|||
import { getTimeFormatter } from '../../../../utils/formatters';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
|
||||
// Remove any tick that is too close to traceRootDuration
|
||||
const getXAxisTickValues = (tickValues, traceRootDuration) => {
|
||||
if (traceRootDuration == null) {
|
||||
// Remove any tick that is too close to topTraceDuration
|
||||
const getXAxisTickValues = (tickValues, topTraceDuration) => {
|
||||
if (topTraceDuration == null) {
|
||||
return tickValues;
|
||||
}
|
||||
|
||||
const padding = (tickValues[1] - tickValues[0]) / 2;
|
||||
const lowerBound = traceRootDuration - padding;
|
||||
const upperBound = traceRootDuration + padding;
|
||||
const lowerBound = topTraceDuration - padding;
|
||||
const upperBound = topTraceDuration + padding;
|
||||
|
||||
return tickValues.filter(value => {
|
||||
const isInRange = inRange(value, lowerBound, upperBound);
|
||||
return !isInRange && value !== traceRootDuration;
|
||||
return !isInRange && value !== topTraceDuration;
|
||||
});
|
||||
};
|
||||
|
||||
function TimelineAxis({ plotValues, agentMarks, traceRootDuration }) {
|
||||
function TimelineAxis({ plotValues, agentMarks, topTraceDuration }) {
|
||||
const { margins, tickValues, width, xDomain, xMax, xScale } = plotValues;
|
||||
const tickFormat = getTimeFormatter(xMax);
|
||||
const xAxisTickValues = getXAxisTickValues(tickValues, traceRootDuration);
|
||||
const xAxisTickValues = getXAxisTickValues(tickValues, topTraceDuration);
|
||||
|
||||
return (
|
||||
<Sticky disableCompensation>
|
||||
|
@ -73,10 +73,10 @@ function TimelineAxis({ plotValues, agentMarks, traceRootDuration }) {
|
|||
}}
|
||||
/>
|
||||
|
||||
{traceRootDuration > 0 && (
|
||||
{topTraceDuration > 0 && (
|
||||
<LastTickValue
|
||||
x={xScale(traceRootDuration)}
|
||||
value={tickFormat(traceRootDuration)}
|
||||
x={xScale(topTraceDuration)}
|
||||
value={tickFormat(topTraceDuration)}
|
||||
marginTop={28}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -11,7 +11,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json';
|
|||
|
||||
class VerticalLines extends PureComponent {
|
||||
render() {
|
||||
const { traceRootDuration } = this.props;
|
||||
const { topTraceDuration } = this.props;
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
|
@ -47,9 +47,9 @@ class VerticalLines extends PureComponent {
|
|||
style={{ stroke: theme.euiColorMediumShade }}
|
||||
/>
|
||||
|
||||
{traceRootDuration > 0 && (
|
||||
{topTraceDuration > 0 && (
|
||||
<VerticalGridLines
|
||||
tickValues={[traceRootDuration]}
|
||||
tickValues={[topTraceDuration]}
|
||||
style={{ stroke: theme.gray3euiColorMediumShade }}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -14,14 +14,7 @@ import VerticalLines from './VerticalLines';
|
|||
|
||||
class Timeline extends PureComponent {
|
||||
render() {
|
||||
const {
|
||||
width,
|
||||
duration,
|
||||
agentMarks,
|
||||
traceRootDuration,
|
||||
height,
|
||||
margins
|
||||
} = this.props;
|
||||
const { width, duration, agentMarks, height, margins } = this.props;
|
||||
if (duration == null || !width) {
|
||||
return null;
|
||||
}
|
||||
|
@ -32,12 +25,12 @@ class Timeline extends PureComponent {
|
|||
<TimelineAxis
|
||||
plotValues={plotValues}
|
||||
agentMarks={agentMarks}
|
||||
traceRootDuration={traceRootDuration}
|
||||
topTraceDuration={duration}
|
||||
/>
|
||||
<VerticalLines
|
||||
plotValues={plotValues}
|
||||
agentMarks={agentMarks}
|
||||
traceRootDuration={traceRootDuration}
|
||||
topTraceDuration={duration}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue