mirror of https://github.com/linkerd/linkerd2.git
Tap web UI: Fix latency formatting (#1429)
* Nicely format tap latencies to be more readable * Various whitespace cleanups
This commit is contained in:
parent
f510d7ea08
commit
38c4b2937a
|
@ -50,7 +50,6 @@ class ErrorMessage extends React.Component {
|
||||||
<div><b>Error:</b> {status} {statusText}</div>
|
<div><b>Error:</b> {status} {statusText}</div>
|
||||||
{ !error ? null : <div><b>Message:</b> {error}</div> }
|
{ !error ? null : <div><b>Message:</b> {error}</div> }
|
||||||
<div><b>URL:</b> {url}</div>
|
<div><b>URL:</b> {url}</div>
|
||||||
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<div className="dismiss" onClick={this.hideMessage} role="presentation">Dismiss X</div>
|
<div className="dismiss" onClick={this.hideMessage} role="presentation">Dismiss X</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import BaseTable from './BaseTable.jsx';
|
import BaseTable from './BaseTable.jsx';
|
||||||
import { formatLatency } from './util/Utils.js';
|
import { formatLatencySec } from './util/Utils.js';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Col, Icon, Row } from 'antd';
|
import { Col, Icon, Row } from 'antd';
|
||||||
|
|
||||||
|
@ -157,9 +157,8 @@ let tapColumns = filterOptions => [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
let formatTapLatency = str => {
|
const formatTapLatency = str => {
|
||||||
let millis = parseFloat(str.replace("s", "")) * 1000;
|
return formatLatencySec(str.replace("s", ""));
|
||||||
return formatLatency(millis);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// hide verbose information
|
// hide verbose information
|
||||||
|
|
|
@ -5,7 +5,9 @@ import React from 'react';
|
||||||
import 'whatwg-fetch';
|
import 'whatwg-fetch';
|
||||||
|
|
||||||
const checkFetchOk = resp => {
|
const checkFetchOk = resp => {
|
||||||
if (resp.ok) { return resp; }
|
if (resp.ok) {
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
return resp.json().then(error => {
|
return resp.json().then(error => {
|
||||||
throw {
|
throw {
|
||||||
|
@ -15,7 +17,6 @@ const checkFetchOk = resp => {
|
||||||
error: error.error
|
error: error.error
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// makeCancelable from @istarkov
|
// makeCancelable from @istarkov
|
||||||
|
@ -115,7 +116,6 @@ const ApiHelpers = (pathPrefix, defaultMetricsWindow = '1m') => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// prefix all links in the app with `pathPrefix`
|
// prefix all links in the app with `pathPrefix`
|
||||||
class PrefixedLink extends React.Component {
|
class PrefixedLink extends React.Component {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
|
|
@ -11,23 +11,37 @@ export const rowGutter = 3 * baseWidth;
|
||||||
* Number formatters
|
* Number formatters
|
||||||
*/
|
*/
|
||||||
const successRateFormatter = d3.format(".2%");
|
const successRateFormatter = d3.format(".2%");
|
||||||
const latencySecFormatter = d3.format(".3f");
|
|
||||||
const latencyFormatter = d3.format(",");
|
const latencyFormatter = d3.format(",");
|
||||||
|
|
||||||
export const formatLatency = m => {
|
export const formatLatencyMs = m => {
|
||||||
if (_.isNil(m)) {
|
if (_.isNil(m)) {
|
||||||
return "---";
|
return "---";
|
||||||
} else if (m < 1000) {
|
|
||||||
return `${latencyFormatter(m)} ms`;
|
|
||||||
} else {
|
} else {
|
||||||
return `${latencySecFormatter(m / 1000)} s`;
|
return `${formatLatencySec(m / 1000)}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const niceLatency = l => latencyFormatter(Math.round(l));
|
||||||
|
|
||||||
|
export const formatLatencySec = latency => {
|
||||||
|
let s = parseFloat(latency);
|
||||||
|
if (_.isNil(s)) {
|
||||||
|
return "---";
|
||||||
|
} else if (s === parseFloat(0.0)) {
|
||||||
|
return "0 s";
|
||||||
|
} else if (s < 0.001) {
|
||||||
|
return `${niceLatency(s * 1000 * 1000)} µs`;
|
||||||
|
} else if (s < 1.0) {
|
||||||
|
return `${niceLatency(s * 1000)} ms`;
|
||||||
|
} else {
|
||||||
|
return `${niceLatency(s)} s`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const metricToFormatter = {
|
export const metricToFormatter = {
|
||||||
"REQUEST_RATE": m => _.isNil(m) ? "---" : styleNum(m, " RPS", true),
|
"REQUEST_RATE": m => _.isNil(m) ? "---" : styleNum(m, " RPS", true),
|
||||||
"SUCCESS_RATE": m => _.isNil(m) ? "---" : successRateFormatter(m),
|
"SUCCESS_RATE": m => _.isNil(m) ? "---" : successRateFormatter(m),
|
||||||
"LATENCY": formatLatency,
|
"LATENCY": formatLatencyMs,
|
||||||
"UNTRUNCATED": m => styleNum(m, "", false)
|
"UNTRUNCATED": m => styleNum(m, "", false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { metricToFormatter, styleNum, toClassName } from '../js/components/util/Utils.js';
|
import {
|
||||||
|
formatLatencySec,
|
||||||
|
metricToFormatter,
|
||||||
|
styleNum,
|
||||||
|
toClassName
|
||||||
|
} from '../js/components/util/Utils.js';
|
||||||
|
|
||||||
// introduce some binary floating point rounding errors, like ya do
|
// introduce some binary floating point rounding errors, like ya do
|
||||||
function float(num) {
|
function float(num) {
|
||||||
|
@ -74,9 +79,9 @@ describe('Utils', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats latency greater than 1s as s', () => {
|
it('formats latency greater than 1s as s', () => {
|
||||||
expect(metricToFormatter["LATENCY"](1000)).to.equal('1.000 s');
|
expect(metricToFormatter["LATENCY"](1000)).to.equal('1 s');
|
||||||
expect(metricToFormatter["LATENCY"](9999)).to.equal('9.999 s');
|
expect(metricToFormatter["LATENCY"](9999)).to.equal('10 s');
|
||||||
expect(metricToFormatter["LATENCY"](99999)).to.equal('99.999 s');
|
expect(metricToFormatter["LATENCY"](99999)).to.equal('100 s');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats success rate', () => {
|
it('formats success rate', () => {
|
||||||
|
@ -86,6 +91,16 @@ describe('Utils', () => {
|
||||||
expect(metricToFormatter["SUCCESS_RATE"](0.9999)).to.equal('99.99%');
|
expect(metricToFormatter["SUCCESS_RATE"](0.9999)).to.equal('99.99%');
|
||||||
expect(metricToFormatter["SUCCESS_RATE"](4)).to.equal('400.00%');
|
expect(metricToFormatter["SUCCESS_RATE"](4)).to.equal('400.00%');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('formats latencies expressed as seconds into a more appropriate display unit', () => {
|
||||||
|
expect(formatLatencySec("0.002837700")).to.equal("3 ms");
|
||||||
|
expect(formatLatencySec("0.000")).to.equal("0 s");
|
||||||
|
expect(formatLatencySec("0.000000797")).to.equal("1 µs");
|
||||||
|
expect(formatLatencySec("0.000231910")).to.equal("232 µs");
|
||||||
|
expect(formatLatencySec("0.000988600")).to.equal("989 µs");
|
||||||
|
expect(formatLatencySec("0.005598200")).to.equal("6 ms");
|
||||||
|
expect(formatLatencySec("3.029409200")).to.equal("3 s");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toClassName', () => {
|
describe('toClassName', () => {
|
||||||
|
|
Loading…
Reference in New Issue