[APM] Only add decimals for numbers below 10 (#69334)
This commit is contained in:
parent
3ee0bf2132
commit
8a6aab33bd
|
@ -1,9 +1,9 @@
|
|||
module.exports = {
|
||||
APM: {
|
||||
'Transaction duration charts': {
|
||||
'1': '350.0 ms',
|
||||
'2': '175.0 ms',
|
||||
'3': '0.0 ms',
|
||||
'1': '350 ms',
|
||||
'2': '175 ms',
|
||||
'3': '0 ms',
|
||||
},
|
||||
},
|
||||
__version: '4.5.0',
|
||||
|
|
|
@ -40,7 +40,7 @@ describe('ServiceOverview -> List', () => {
|
|||
expect(renderedColumns[0]).toMatchSnapshot();
|
||||
expect(renderedColumns.slice(2)).toEqual([
|
||||
'python',
|
||||
'91.5 ms',
|
||||
'92 ms',
|
||||
'86.9 tpm',
|
||||
'12.6 err.',
|
||||
]);
|
||||
|
|
|
@ -9,7 +9,7 @@ Array [
|
|||
"text": <ForwardRef(styled.span)>
|
||||
Avg.
|
||||
<ForwardRef(styled.span)>
|
||||
467.6 ms
|
||||
468 ms
|
||||
</ForwardRef(styled.span)>
|
||||
</ForwardRef(styled.span)>,
|
||||
},
|
||||
|
@ -2744,7 +2744,7 @@ Array [
|
|||
<span
|
||||
className="c4"
|
||||
>
|
||||
467.6 ms
|
||||
468 ms
|
||||
</span>
|
||||
</styled.span>
|
||||
</span>
|
||||
|
@ -5923,7 +5923,7 @@ Array [
|
|||
<span
|
||||
className="c4"
|
||||
>
|
||||
467.6 ms
|
||||
468 ms
|
||||
</span>
|
||||
</styled.span>
|
||||
</span>
|
||||
|
|
|
@ -11,8 +11,8 @@ import d3 from 'd3';
|
|||
import { HistogramInner } from '../index';
|
||||
import response from './response.json';
|
||||
import {
|
||||
asDecimal,
|
||||
getDurationFormatter,
|
||||
asInteger,
|
||||
} from '../../../../../utils/formatters';
|
||||
import { toJson } from '../../../../../utils/testHelpers';
|
||||
import { getFormattedBuckets } from '../../../../app/TransactionDetails/Distribution/index';
|
||||
|
@ -33,8 +33,8 @@ describe('Histogram', () => {
|
|||
transactionId="myTransactionId"
|
||||
onClick={onClick}
|
||||
formatX={(time) => timeFormatter(time).formatted}
|
||||
formatYShort={(t) => `${asDecimal(t)} occ.`}
|
||||
formatYLong={(t) => `${asDecimal(t)} occurrences`}
|
||||
formatYShort={(t) => `${asInteger(t)} occ.`}
|
||||
formatYLong={(t) => `${asInteger(t)} occurrences`}
|
||||
tooltipHeader={(bucket) => {
|
||||
const xFormatted = timeFormatter(bucket.x);
|
||||
const x0Formatted = timeFormatter(bucket.x0);
|
||||
|
@ -78,9 +78,9 @@ describe('Histogram', () => {
|
|||
const tooltips = wrapper.find('Tooltip');
|
||||
|
||||
expect(tooltips.length).toBe(1);
|
||||
expect(tooltips.prop('header')).toBe('811.1 - 926.9 ms');
|
||||
expect(tooltips.prop('header')).toBe('811 - 927 ms');
|
||||
expect(tooltips.prop('tooltipPoints')).toEqual([
|
||||
{ value: '49.0 occurrences' },
|
||||
{ value: '49 occurrences' },
|
||||
]);
|
||||
expect(tooltips.prop('x')).toEqual(869010);
|
||||
expect(tooltips.prop('y')).toEqual(27.5);
|
||||
|
|
|
@ -127,7 +127,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
0.0 ms
|
||||
0 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -162,7 +162,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
500.0 ms
|
||||
500 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -197,7 +197,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
1,000.0 ms
|
||||
1,000 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -232,7 +232,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
1,500.0 ms
|
||||
1,500 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -267,7 +267,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
2,000.0 ms
|
||||
2,000 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -302,7 +302,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
2,500.0 ms
|
||||
2,500 ms
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -337,7 +337,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, 18)"
|
||||
>
|
||||
3,000.0 ms
|
||||
3,000 ms
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
|
@ -371,7 +371,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="end"
|
||||
transform="translate(-8, 0)"
|
||||
>
|
||||
0.0 occ.
|
||||
0 occ.
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -394,7 +394,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="end"
|
||||
transform="translate(-8, 0)"
|
||||
>
|
||||
27.5 occ.
|
||||
28 occ.
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
|
@ -417,7 +417,7 @@ exports[`Histogram Initially should have default markup 1`] = `
|
|||
textAnchor="end"
|
||||
transform="translate(-8, 0)"
|
||||
>
|
||||
55.0 occ.
|
||||
55 occ.
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
|
@ -1477,7 +1477,7 @@ exports[`Histogram when hovering over a non-empty bucket should have correct mar
|
|||
<div
|
||||
className="c1"
|
||||
>
|
||||
811.1 - 926.9 ms
|
||||
811 - 927 ms
|
||||
</div>
|
||||
</styled.div>
|
||||
<styled.div>
|
||||
|
@ -1488,7 +1488,7 @@ exports[`Histogram when hovering over a non-empty bucket should have correct mar
|
|||
<div
|
||||
className="c3"
|
||||
>
|
||||
49.0 occurrences
|
||||
49 occurrences
|
||||
</div>
|
||||
</styled.div>
|
||||
</div>
|
||||
|
|
|
@ -37,7 +37,7 @@ describe('ErrorMarker', () => {
|
|||
act(() => {
|
||||
fireEvent.click(component.getByTestId('popover'));
|
||||
});
|
||||
expectTextsInDocument(component, ['10.0 ms']);
|
||||
expectTextsInDocument(component, ['10 ms']);
|
||||
return component;
|
||||
}
|
||||
function getKueryDecoded(url: string) {
|
||||
|
|
|
@ -14,14 +14,14 @@ describe('duration formatters', () => {
|
|||
expect(asDuration(1)).toEqual('1 μs');
|
||||
expect(asDuration(toMicroseconds(1, 'milliseconds'))).toEqual('1,000 μs');
|
||||
expect(asDuration(toMicroseconds(1000, 'milliseconds'))).toEqual(
|
||||
'1,000.0 ms'
|
||||
'1,000 ms'
|
||||
);
|
||||
expect(asDuration(toMicroseconds(10000, 'milliseconds'))).toEqual(
|
||||
'10,000.0 ms'
|
||||
'10,000 ms'
|
||||
);
|
||||
expect(asDuration(toMicroseconds(20, 'seconds'))).toEqual('20.0 s');
|
||||
expect(asDuration(toMicroseconds(10, 'minutes'))).toEqual('10.0 min');
|
||||
expect(asDuration(toMicroseconds(1, 'hours'))).toEqual('60.0 min');
|
||||
expect(asDuration(toMicroseconds(20, 'seconds'))).toEqual('20 s');
|
||||
expect(asDuration(toMicroseconds(10, 'minutes'))).toEqual('10 min');
|
||||
expect(asDuration(toMicroseconds(1, 'hours'))).toEqual('60 min');
|
||||
expect(asDuration(toMicroseconds(1.5, 'hours'))).toEqual('1.5 h');
|
||||
});
|
||||
|
||||
|
@ -41,7 +41,7 @@ describe('duration formatters', () => {
|
|||
|
||||
describe('asMilliseconds', () => {
|
||||
it('converts to formatted decimal milliseconds', () => {
|
||||
expect(asMillisecondDuration(0)).toEqual('0.0 ms');
|
||||
expect(asMillisecondDuration(0)).toEqual('0 ms');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,13 +18,6 @@ interface FormatterOptions {
|
|||
|
||||
type DurationTimeUnit = TimeUnit | 'microseconds';
|
||||
|
||||
interface DurationUnit {
|
||||
[unit: string]: {
|
||||
label: string;
|
||||
convert: (value: number) => string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ConvertedDuration {
|
||||
value: string;
|
||||
unit?: string;
|
||||
|
@ -38,42 +31,69 @@ export type TimeFormatter = (
|
|||
|
||||
type TimeFormatterBuilder = (max: number) => TimeFormatter;
|
||||
|
||||
const durationUnit: DurationUnit = {
|
||||
hours: {
|
||||
label: i18n.translate('xpack.apm.formatters.hoursTimeUnitLabel', {
|
||||
defaultMessage: 'h',
|
||||
}),
|
||||
convert: (value: number) =>
|
||||
asDecimal(moment.duration(value / 1000).asHours()),
|
||||
},
|
||||
minutes: {
|
||||
label: i18n.translate('xpack.apm.formatters.minutesTimeUnitLabel', {
|
||||
defaultMessage: 'min',
|
||||
}),
|
||||
convert: (value: number) =>
|
||||
asDecimal(moment.duration(value / 1000).asMinutes()),
|
||||
},
|
||||
seconds: {
|
||||
label: i18n.translate('xpack.apm.formatters.secondsTimeUnitLabel', {
|
||||
defaultMessage: 's',
|
||||
}),
|
||||
convert: (value: number) =>
|
||||
asDecimal(moment.duration(value / 1000).asSeconds()),
|
||||
},
|
||||
milliseconds: {
|
||||
label: i18n.translate('xpack.apm.formatters.millisTimeUnitLabel', {
|
||||
defaultMessage: 'ms',
|
||||
}),
|
||||
convert: (value: number) =>
|
||||
asDecimal(moment.duration(value / 1000).asMilliseconds()),
|
||||
},
|
||||
microseconds: {
|
||||
label: i18n.translate('xpack.apm.formatters.microsTimeUnitLabel', {
|
||||
defaultMessage: 'μs',
|
||||
}),
|
||||
convert: (value: number) => asInteger(value),
|
||||
},
|
||||
};
|
||||
function asDecimalOrInteger(value: number) {
|
||||
// exact 0 or above 10 should not have decimal
|
||||
if (value === 0 || value >= 10) {
|
||||
return asInteger(value);
|
||||
}
|
||||
return asDecimal(value);
|
||||
}
|
||||
|
||||
function getUnitLabelAndConvertedValue(
|
||||
unitKey: DurationTimeUnit,
|
||||
value: number
|
||||
) {
|
||||
switch (unitKey) {
|
||||
case 'hours': {
|
||||
return {
|
||||
unitLabel: i18n.translate('xpack.apm.formatters.hoursTimeUnitLabel', {
|
||||
defaultMessage: 'h',
|
||||
}),
|
||||
convertedValue: asDecimalOrInteger(
|
||||
moment.duration(value / 1000).asHours()
|
||||
),
|
||||
};
|
||||
}
|
||||
case 'minutes': {
|
||||
return {
|
||||
unitLabel: i18n.translate('xpack.apm.formatters.minutesTimeUnitLabel', {
|
||||
defaultMessage: 'min',
|
||||
}),
|
||||
convertedValue: asDecimalOrInteger(
|
||||
moment.duration(value / 1000).asMinutes()
|
||||
),
|
||||
};
|
||||
}
|
||||
case 'seconds': {
|
||||
return {
|
||||
unitLabel: i18n.translate('xpack.apm.formatters.secondsTimeUnitLabel', {
|
||||
defaultMessage: 's',
|
||||
}),
|
||||
convertedValue: asDecimalOrInteger(
|
||||
moment.duration(value / 1000).asSeconds()
|
||||
),
|
||||
};
|
||||
}
|
||||
case 'milliseconds': {
|
||||
return {
|
||||
unitLabel: i18n.translate('xpack.apm.formatters.millisTimeUnitLabel', {
|
||||
defaultMessage: 'ms',
|
||||
}),
|
||||
convertedValue: asDecimalOrInteger(
|
||||
moment.duration(value / 1000).asMilliseconds()
|
||||
),
|
||||
};
|
||||
}
|
||||
case 'microseconds': {
|
||||
return {
|
||||
unitLabel: i18n.translate('xpack.apm.formatters.microsTimeUnitLabel', {
|
||||
defaultMessage: 'μs',
|
||||
}),
|
||||
convertedValue: asInteger(value),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a microseconds value into the unit defined.
|
||||
|
@ -87,16 +107,19 @@ function convertTo({
|
|||
microseconds: Maybe<number>;
|
||||
defaultValue?: string;
|
||||
}): ConvertedDuration {
|
||||
const duration = durationUnit[unit];
|
||||
if (!duration || microseconds == null) {
|
||||
if (microseconds == null) {
|
||||
return { value: defaultValue, formatted: defaultValue };
|
||||
}
|
||||
|
||||
const convertedValue = duration.convert(microseconds);
|
||||
const { convertedValue, unitLabel } = getUnitLabelAndConvertedValue(
|
||||
unit,
|
||||
microseconds
|
||||
);
|
||||
|
||||
return {
|
||||
value: convertedValue,
|
||||
unit: duration.label,
|
||||
formatted: `${convertedValue} ${duration.label}`,
|
||||
unit: unitLabel,
|
||||
formatted: `${convertedValue} ${unitLabel}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue