Skip to content

Commit

Permalink
Resolve perf issues on the search page (jaegertracing#179)
Browse files Browse the repository at this point in the history
Signed-off-by: Joe Farro <joef@uber.com>
Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
  • Loading branch information
tiffon authored Feb 6, 2018
1 parent 4e38633 commit e25a7d4
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 107 deletions.
112 changes: 58 additions & 54 deletions src/components/SearchTracePage/SearchResults/ResultItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React from 'react';
import * as React from 'react';
import { Col, Divider, Row, Tag } from 'antd';
import { sortBy } from 'lodash';
import moment from 'moment';
Expand All @@ -28,60 +28,64 @@ import type { TraceSummary } from '../../../types/search';

import './ResultItem.css';

export default function ResultItem({
trace,
durationPercent = 100,
}: {
type Props = {
trace: TraceSummary,
durationPercent: number,
}) {
const { duration, services, timestamp, numberOfErredSpans, numberOfSpans, traceName } = trace;
const mDate = moment(timestamp);
const timeStr = mDate.format('h:mm:ss a');
const fromNow = mDate.fromNow();
return (
<div className="ResultItem">
<div className="ResultItem--title clearfix">
<span className="ResultItem--durationBar" style={{ width: `${durationPercent}%` }} />
<span className="ub-right ub-relative">{formatDuration(duration * 1000)}</span>
<h3 className="ub-m0 ub-relative">{traceName || FALLBACK_TRACE_NAME}</h3>
</div>
<Row>
<Col span={4} className="ub-p2">
<Tag className="ub-m1" data-test={markers.NUM_SPANS}>
{numberOfSpans} Span{numberOfSpans > 1 && 's'}
</Tag>
{Boolean(numberOfErredSpans) && (
<Tag className="ub-m1" color="red">
{numberOfErredSpans} Error{numberOfErredSpans > 1 && 's'}
};

export default class ResultItem extends React.PureComponent<Props> {
props: Props;

render() {
const { durationPercent, trace } = this.props;
const { duration, services, timestamp, numberOfErredSpans, numberOfSpans, traceName } = trace;
const mDate = moment(timestamp);
const timeStr = mDate.format('h:mm:ss a');
const fromNow = mDate.fromNow();
return (
<div className="ResultItem">
<div className="ResultItem--title clearfix">
<span className="ResultItem--durationBar" style={{ width: `${durationPercent}%` }} />
<span className="ub-right ub-relative">{formatDuration(duration * 1000)}</span>
<h3 className="ub-m0 ub-relative">{traceName || FALLBACK_TRACE_NAME}</h3>
</div>
<Row>
<Col span={4} className="ub-p2">
<Tag className="ub-m1" data-test={markers.NUM_SPANS}>
{numberOfSpans} Span{numberOfSpans > 1 && 's'}
</Tag>
)}
</Col>
<Col span={16} className="ub-p2">
<ul className="ub-list-reset" data-test={markers.SERVICE_TAGS}>
{sortBy(services, s => s.name).map(service => {
const { name, numberOfSpans: count } = service;
return (
<li key={name} className="ub-inline-block ub-m1">
<Tag
className="ResultItem--serviceTag"
style={{ borderLeftColor: colorGenerator.getColorByKey(name) }}
>
{name} ({count})
</Tag>
</li>
);
})}
</ul>
</Col>
<Col span={4} className="ub-p3 ub-tx-right">
{formatRelativeDate(timestamp)}
<Divider type="vertical" />
{timeStr.slice(0, -3)}&nbsp;{timeStr.slice(-2)}
<br />
<small>{fromNow}</small>
</Col>
</Row>
</div>
);
{Boolean(numberOfErredSpans) && (
<Tag className="ub-m1" color="red">
{numberOfErredSpans} Error{numberOfErredSpans > 1 && 's'}
</Tag>
)}
</Col>
<Col span={16} className="ub-p2">
<ul className="ub-list-reset" data-test={markers.SERVICE_TAGS}>
{sortBy(services, s => s.name).map(service => {
const { name, numberOfSpans: count } = service;
return (
<li key={name} className="ub-inline-block ub-m1">
<Tag
className="ResultItem--serviceTag"
style={{ borderLeftColor: colorGenerator.getColorByKey(name) }}
>
{name} ({count})
</Tag>
</li>
);
})}
</ul>
</Col>
<Col span={4} className="ub-p3 ub-tx-right-align">
{formatRelativeDate(timestamp)}
<Divider type="vertical" />
{timeStr.slice(0, -3)}&nbsp;{timeStr.slice(-2)}
<br />
<small>{fromNow}</small>
</Col>
</Row>
</div>
);
}
}
104 changes: 54 additions & 50 deletions src/components/SearchTracePage/SearchResults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React from 'react';
import * as React from 'react';
import { Select } from 'antd';
import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Link } from 'react-router-dom';
Expand Down Expand Up @@ -66,58 +66,62 @@ const SelectSort = reduxForm({

export const sortFormSelector = formValueSelector('traceResultsSort');

export default function SearchResults(props: SearchResultsProps) {
const { goToTrace, loading, maxTraceDuration, traces } = props;
if (loading) {
return <LoadingIndicator className="u-mt-vast" centered />;
}
if (!Array.isArray(traces) || !traces.length) {
export default class SearchResults extends React.PureComponent<SearchResultsProps> {
props: SearchResultsProps;

render() {
const { goToTrace, loading, maxTraceDuration, traces } = this.props;
if (loading) {
return <LoadingIndicator className="u-mt-vast" centered />;
}
if (!Array.isArray(traces) || !traces.length) {
return (
<div className="u-simple-card" data-test={markers.NO_RESULTS}>
No trace results. Try another query.
</div>
);
}
return (
<div className="u-simple-card" data-test={markers.NO_RESULTS}>
No trace results. Try another query.
</div>
);
}
return (
<div>
<div>
<div className="SearchResults--header">
<div className="ub-p3">
<ScatterPlot
data={traces.map(t => ({
x: t.timestamp,
y: t.duration,
traceID: t.traceID,
size: t.numberOfSpans,
name: t.traceName,
}))}
onValueClick={t => {
goToTrace(t.traceID);
}}
/>
</div>
<div className="SearchResults--headerOverview">
<SelectSort />
<h2 className="ub-m0">
{traces.length} Trace{traces.length > 1 && 's'}
</h2>
<div>
<div className="SearchResults--header">
<div className="ub-p3">
<ScatterPlot
data={traces.map(t => ({
x: t.timestamp,
y: t.duration,
traceID: t.traceID,
size: t.numberOfSpans,
name: t.traceName,
}))}
onValueClick={t => {
goToTrace(t.traceID);
}}
/>
</div>
<div className="SearchResults--headerOverview">
<SelectSort />
<h2 className="ub-m0">
{traces.length} Trace{traces.length > 1 && 's'}
</h2>
</div>
</div>
</div>
<div>
<ul className="ub-list-reset">
{traces.map(trace => (
<li className="ub-my3" key={trace.traceID}>
<Link to={prefixUrl(`/trace/${trace.traceID}`)} className="SearchResults--resultLink">
<ResultItem
trace={trace}
durationPercent={getPercentageOfDuration(trace.duration, maxTraceDuration)}
/>
</Link>
</li>
))}
</ul>
</div>
</div>
<div>
<ul className="ub-list-reset">
{traces.map(trace => (
<li className="ub-my3" key={trace.traceID}>
<Link to={prefixUrl(`/trace/${trace.traceID}`)} className="SearchResults--resultLink">
<ResultItem
trace={trace}
durationPercent={getPercentageOfDuration(trace.duration, maxTraceDuration)}
/>
</Link>
</li>
))}
</ul>
</div>
</div>
);
);
}
}
11 changes: 8 additions & 3 deletions src/components/SearchTracePage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ const stateTraceXformer = getLastXformCacher(stateTrace => {
return { traces, maxDuration, traceError, loadingTraces };
});

const sortedTracesXformer = getLastXformCacher((traces, sortBy) => {
const traceResults = traces.slice();
sortTraces(traceResults, sortBy);
return traceResults;
});

const stateServicesXformer = getLastXformCacher(stateServices => {
const {
loading: loadingServices,
Expand Down Expand Up @@ -169,17 +175,16 @@ export function mapStateToProps(state) {
errors.push(serviceError);
}
const sortBy = sortFormSelector(state, 'sortBy');
sortTraces(traces, sortBy);

const traceResults = sortedTracesXformer(traces, sortBy);
return {
isHomepage,
services,
traceResults,
loadingTraces,
loadingServices,
errors: errors.length ? errors : null,
maxTraceDuration: maxDuration,
sortTracesBy: sortBy,
traceResults: traces,
urlQueryParams: query,
};
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import { document } from 'global';
import JaegerUIApp from './components/App';
import { init as initTracking } from './utils/metrics';

import 'u-basscss/css/flexbox.css';
import 'u-basscss/css/layout.css';
import 'u-basscss/css/margin.css';
import 'u-basscss/css/padding.css';
import 'u-basscss/css/position.css';
import 'u-basscss/css/typography.css';

Expand Down

0 comments on commit e25a7d4

Please sign in to comment.