From 60f1bc8fb571d7ce4de53c2e2de58f5ca95059c5 Mon Sep 17 00:00:00 2001 From: Jono Yan Date: Wed, 13 Apr 2022 22:30:54 +1000 Subject: [PATCH] Add error icon to errored services in trace list view (#927) --- .../SearchResults/ResultItem.css | 11 ++++ .../SearchResults/ResultItem.test.js | 7 +++ .../SearchResults/ResultItem.tsx | 57 +++++++++++++++---- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.css b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.css index f53f6b91ec..fa0d1ece08 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.css +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.css @@ -27,4 +27,15 @@ limitations under the License. .ResultItem--serviceTag { border-left-width: 15px; margin: 0; + display: flex; + align-items: center; +} + +.ResultItem--errorIcon { + background: #db2828; + border-radius: 6.5px; + color: #fff; + font-size: 0.85em; + margin-right: 0.25rem; + padding: 1px; } diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.test.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.test.js index 2d03716c98..9ad0828aef 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.test.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.test.js @@ -40,3 +40,10 @@ it(' should not render any ServiceTags when there are no services' const serviceTags = wrapper.find(`[data-test="${markers.SERVICE_TAGS}"]`).find(Tag); expect(serviceTags).toHaveLength(0); }); + +it(' should render error icon on ServiceTags that have an error tag', () => { + trace.spans[0].tags.push({ key: 'error', value: true }); + const wrapper = shallow(); + const errorServiceTags = wrapper.find('.ResultItem--errorIcon').getElements(); + expect(errorServiceTags).toHaveLength(1); +}); diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.tsx b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.tsx index 3f8f300a9e..93d6077903 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.tsx +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.tsx @@ -19,6 +19,8 @@ import { Link } from 'react-router-dom'; import { sortBy } from 'lodash'; import moment from 'moment'; +import IoAlert from 'react-icons/lib/io/alert'; + import { trackConversions, EAltViewActions } from './index.track'; import * as markers from './ResultItem.markers'; import ResultItemTitle from './ResultItemTitle'; @@ -38,10 +40,43 @@ type Props = { disableComparision: boolean; }; +type State = { + erroredServices: Set; + numSpans: number; + numErredSpans: number; + timeStr: string; + fromNow: string | boolean; +}; + const isErrorTag = ({ key, value }: KeyValuePair) => key === 'error' && (value === true || value === 'true'); const trackTraceConversions = () => trackConversions(EAltViewActions.Traces); -export default class ResultItem extends React.PureComponent { +export default class ResultItem extends React.PureComponent { + constructor(props: Props, state: State) { + super(props, state); + const { startTime, spans } = props.trace; + + const mDate = moment(startTime / 1000); + + const erroredServices: Set = new Set(); + + const numErredSpans = spans.filter(sp => { + const hasError = sp.tags.some(isErrorTag); + if (hasError) { + erroredServices.add(sp.process.serviceName); + } + return hasError; + }).length; + + this.state = { + numSpans: spans.length, + timeStr: mDate.format('h:mm:ss a'), + fromNow: mDate.fromNow(), + numErredSpans, + erroredServices, + }; + } + render() { const { disableComparision, @@ -51,12 +86,7 @@ export default class ResultItem extends React.PureComponent { toggleComparison, trace, } = this.props; - const { duration, services, startTime, spans, traceName, traceID } = trace; - const mDate = moment(startTime / 1000); - const timeStr = mDate.format('h:mm:ss a'); - const fromNow = mDate.fromNow(); - const numSpans = spans.length; - const numErredSpans = spans.filter(sp => sp.tags.some(isErrorTag)).length; + const { duration, services, startTime, traceName, traceID } = trace; return (
{ - {numSpans} Span{numSpans > 1 && 's'} + {this.state.numSpans} Span{this.state.numSpans > 1 && 's'} - {Boolean(numErredSpans) && ( + {Boolean(this.state.numErredSpans) && ( - {numErredSpans} Error{numErredSpans > 1 && 's'} + {this.state.numErredSpans} Error{this.state.numErredSpans > 1 && 's'} )} @@ -91,6 +121,9 @@ export default class ResultItem extends React.PureComponent { className="ResultItem--serviceTag" style={{ borderLeftColor: colorGenerator.getColorByKey(name) }} > + {this.state.erroredServices.has(name) && ( + + )} {name} ({count}) @@ -101,9 +134,9 @@ export default class ResultItem extends React.PureComponent { {formatRelativeDate(startTime / 1000)} - {timeStr.slice(0, -3)} {timeStr.slice(-2)} + {this.state.timeStr.slice(0, -3)} {this.state.timeStr.slice(-2)}
- {fromNow} + {this.state.fromNow}