Skip to content

Commit

Permalink
Support diffing of traces (jaegertracing#228)
Browse files Browse the repository at this point in the history
* Use Lerna (jaegertracing#209)

* Prep the repo for separately developed components
* Fix uberinternal yarn.lock issues
* Upgrade react to 16.3.2
* Update readme to account for on Lerna changes

Signed-off-by: Joe Farro <joef@uber.com>

Directed graph layout and presentation (jaegertracing#212)

* Prep the repo for separately developed components

Signed-off-by: Joe Farro <joef@uber.com>

* WIP - Very rough graph layout functionality

Signed-off-by: Joe Farro <joef@uber.com>

* Graph layout functionality is in solid shape

Outstanding:
* tests
* calculate edges via several workers when there are many edges

Signed-off-by: Joe Farro <joef@uber.com>

* Fix minor misc issues with plexus layout

Signed-off-by: Joe Farro <joef@uber.com>

* Fix uberinternal yarn.lock issues

Signed-off-by: Joe Farro <joef@uber.com>

* Fix uberinternal yarn.lock issues

Signed-off-by: Joe Farro <joef@uber.com>

* Upgrade react to 16.3.2

Signed-off-by: Joe Farro <joef@uber.com>

* Upgrade flow to 0.71.0

Signed-off-by: Joe Farro <joef@uber.com>

* Very rough React graph component

Signed-off-by: Joe Farro <joef@uber.com>

* Enable custom props for graph elements

Signed-off-by: Joe Farro <joef@uber.com>

* The graph refreshes when it gets new data

Signed-off-by: Joe Farro <joef@uber.com>

* Make the jaeger-ui package private

Signed-off-by: Joe Farro <joef@uber.com>

* Misc cleanup for plexus package.json

Signed-off-by: Joe Farro <joef@uber.com>

* Fix issues with plexus package.json

Signed-off-by: Joe Farro <joef@uber.com>

* Don't output a CSS file for plexus

Signed-off-by: Joe Farro <joef@uber.com>

* Increase plexus node spacing for neato layouts

Signed-off-by: Joe Farro <joef@uber.com>

* Update plexus to 0.0.1-dev.2

Signed-off-by: Joe Farro <joef@uber.com>

* Adding new issue and pull request template (jaegertracing#219)

Signed-off-by: Prakriti <prakritibansal98@gmail.com>

* plexus readme, remove `LayoutManager.dispose()`

Signed-off-by: Joe Farro <joef@uber.com>

* remove unecessary package

Signed-off-by: Joe Farro <joef@uber.com>

* Add more complex graphs to plexus demo

Signed-off-by: Joe Farro <joef@uber.com>

* Start the worker ID at 0

Signed-off-by: Joe Farro <joef@uber.com>

Search page functionality for trace diffs

Signed-off-by: Joe Farro <joef@uber.com>

Stub for trace diff page, update redux state shape

- Better redux state shape for trace diff
  - Refer to traces selected for comparison as trace diff cohort
- Better redux state shape for fetched trace data
  - Before: One loading prop to keep track of all search and individual
    trace fetching
  - After: Loading is tracked separately for serach and for each
    individual trace being fetched
  - This is better all around and lays the ground-work for fetching
    multiple individual traces which will be necessary for trace diff
    page when hit directly via URL (will need to fetch two or more
    traces)

Signed-off-by: Joe Farro <joef@uber.com>

Optimization for trace mini-map rendering

On a trace with ~16k spans reduced minimap rendering from ~250ms to
~20ms. For context, the initial render of the trace was around 1.22s.

Signed-off-by: Joe Farro <joef@uber.com>

Redux cleanup, hydrate diff cohort on search page

- Merge TraceSummary into Trace
- Redux action to fetch multiple traces by ID
- Create a small-sized variation of the loading indicator
- SearchTracePage loads trace data for traces in the diff cohort
  - Show loading indicator when trace data is being loaded
  - Show inline error when trace loading fails
  - Strip failed traces from diff cohort when linking to diff page
- Diff page forces redux state based on URL params

Signed-off-by: Joe Farro <joef@uber.com>

Trace diff page header functionality

- Fetch traces that need to be loaded
- Keep the URL and redux state in sync after changes to A or B
- Allow entering traces by ID
- Allow selecting other traces in the cohort
- Indicate when loading a trace failed

Signed-off-by: Joe Farro <joef@uber.com>

Convert trace to a DAG

Apply three transforms to spans when converting to DAG:

- Adopt peer.service for service name when a client span is missing
  the corresponding server span
- Ignore client spans when the only child is a reasonable server span
- Try to figure out a better operation name when operation === the
  http.method tag

The conversion can be optimized; it takes about 230ms on a trace with
~35k spans. A trace with ~9k spans takes about 50ms.

Signed-off-by: Joe Farro <joef@uber.com>

Add useDotEdges and totalMemory options to plexus

- Option in plexus to set the totalMemory viz.js uses
  - Sometimes viz.js runs out of memory on large graphs, especially
    when using the neato engine, increasing the total memeory can help
- Option in plexus to use dot edges in plexus graphs
  - Useful for trees (neato and plexus are very similar) or large
    graphs (neato is too slow)

Signed-off-by: Joe Farro <joef@uber.com>

Initial trace diff graph

- Ability to create diff of two TraceDag instances
- Additional transforms to trim superfluous nodes
  - skipAnnotationSpans
  - skipClientSpans

Signed-off-by: Joe Farro <joef@uber.com>

Add zoom and pan to plexus

- Zoom and pan
- Add graph state as param to setOn* props
- Enable scaling edge stroke based on zoom level

Signed-off-by: Joe Farro <joef@uber.com>

Add zoom to trace diff and increase color contrast

- Add zoom pan to trace diff
- On node hover show node @ 1x zoom (useful when zoomed out)
- Higher contrast colors for trace diff DAG
- Allowing scrolling for errors
- Fix issue with node sizing during measurement phase

Signed-off-by: Joe Farro <joef@uber.com>

Add a minimap to plexus to help zoom and pan

Also added to trace-diffs

Signed-off-by: Joe Farro <joef@uber.com>

Guard plexus zoom functionality with a flag

Signed-off-by: Joe Farro <joef@uber.com>

Fixes and optimizations to plexus and trace diffs

- Bug fix: Each graph should have a unique edge arrow def IRI

- Keep strokes from scaling into invisibility when zooming

  - Remove redundant root node

  - Apply zoom transforms to the node and edge containers

  - Scale the arrow def based on the current zoom (when zoom is
    enabled) by scaling the coords in the marker and path definitions

- Add a convenience prop-factory that toggles a class, "is-small",
  based on the current zoom level

  - Use "is-small" to toggle the visibility of node text and edge
    stroke width based on the current zoom level

- Change prop factories to be grouped by feature instead of context

  - In many cases the prop factory can be applied to multiple contexts,
    e.g. to both the edges container and an edge path

- Make Node and EdgePath components PureComponents

- Wrap rendering the nodes and edges in a PureComponent to prevent
  unnecessary renders

- Remove DirectedGraphState from the edge and node factory prop
  functions to prevent rendering with every transform change

Signed-off-by: Joe Farro <joef@uber.com>

Add additional layout options to plexus

Signed-off-by: Joe Farro <joef@uber.com>

Lighten trace diff color scheme

Signed-off-by: Joe Farro <joef@uber.com>

Use green instead of blue in trace diff coloring

Green is more commonly used to show additions

Signed-off-by: Joe Farro <joef@uber.com>

Add "Compare" to the top nav and other small fixes

Signed-off-by: Joe Farro <joef@uber.com>

Adding new issue and pull request template (jaegertracing#219)

Signed-off-by: Prakriti <prakritibansal98@gmail.com>

Integrate Google Analytics into Search Page (jaegertracing#220)

* Integrate GA into search page

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Review changes

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Remove tracking of actual values

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

Timeline Expand and Collapse Features (jaegertracing#221)

* Add expansion and collapsing features

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Use Icon component

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Use spans upstream

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Improve css

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Rotate collapse buttons

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Remove debug logging

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Remove spans from TimelineHeaderRow

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add unit test for TimelineCollapser

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Use popover

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add TimelineCollapser test

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Revert "Use popover"

This reverts commit 6152402

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add tests for duck.js

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add more tests for duck.js

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add more tests for index.js

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Add keyboard shortcuts

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Update changelog

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

* Make review changes

Signed-off-by: Davit Yeghshatyan <davo@uber.com>

Squashed commits from develop-directed-graph (jaegertracing#224)

Signed-off-by: Joe Farro <joef@uber.com>

Lazily initialize the first worker in plexus

Signed-off-by: Joe Farro <joef@uber.com>

Fix issue with trace diff URL from auth redirects

The trace diff url was of the form:

    /trace/<trace-a-id>:diff?b=<trace-b-id>

But, during OneLogin / SAML auth redirects it would get URL encoded
and then not URL decoded resulting in it being interpreted as a trace
ID.

Move to the following form with three literal periods between the IDs:

    /trace/<trace-a-id>...<trace-b-id>

Other misc fixes and tweaks:

- Fix an issue where selecting a cohort of traces and then clicking the
  "Compare" button in the top nav cleared the cohort

- Fix an issue where removing a trace from the cohort on the search
  page would not clear the trace from A or B, effectively preventing
  traces set as A or B from ever being removed

- Clean up route definitions

Signed-off-by: Joe Farro <joef@uber.com>

Fix trace detail tracking for revised redux shape

Signed-off-by: Joe Farro <joef@uber.com>

* Typo

Signed-off-by: Joe Farro <joef@uber.com>

* Fix jaegertracing#232 Split leaf from parent nodes in the tree

Signed-off-by: Joe Farro <joef@uber.com>

* plexus - Fix chart style issues and bump version

Also tweak the demo a bit.

Signed-off-by: Joe Farro <joef@uber.com>

* Fix yarn workspace based install

Signed-off-by: Joe Farro <joef@uber.com>

* In CI, fail if an update to yarn.lock is needed

Signed-off-by: Joe Farro <joef@uber.com>

* Misc cleanup

Signed-off-by: Joe Farro <joef@uber.com>

* Use stable yarn in CI

Signed-off-by: Joe Farro <joef@uber.com>

* Use yarn in package.json scripts

Signed-off-by: Joe Farro <joef@uber.com>

* Use newly downloaded yarn in CI

Signed-off-by: Joe Farro <joef@uber.com>

Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
  • Loading branch information
tiffon authored and yurishkuro committed Aug 14, 2018
1 parent 7182d59 commit eff9c27
Show file tree
Hide file tree
Showing 119 changed files with 4,555 additions and 1,154 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ npm-debug.log
.vscode
.idea
yarn-error.log

lerna-debug\.log
lerna-debug.log
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ language: node_js
node_js:
- '6'
cache: yarn
env:
global:
# so the yarn installed in before_install will be used
- PATH=$HOME/.yarn/bin:$PATH
before_install:
# update yarn - travis is using an old version
# https://yarnpkg.com/en/docs/install#alternatives-stable
- curl -o- -L https://yarnpkg.com/install.sh | bash
install:
- yarn install --frozen-lockfile
script:
- yarn lint
- yarn coverage
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"lerna": "2.10.2",
"packages": ["packages/*"],
"version": "independent",
"npmClient": "yarn",
"npmClientArgs": ["--pure-lockfile"],
"useWorkspaces": true
}
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
"coverage": "lerna run coverage",
"eslint": "eslint 'scripts/*.js' 'packages/*/src/**/*.js' 'packages/*/*.js'",
"flow": "glow",
"lint": "npm run eslint && npm run prettier && npm run flow && npm run check-license",
"lint": "yarn run eslint && yarn run prettier && yarn run flow && yarn run check-license",
"precommit": "lint-staged",
"prepare": "lerna run --stream --sort prepublishOnly",
"prettier":
"prettier --write '{.,scripts}/*.{js,json,md}' 'packages/*/{src,demo/src}/**/*.{css,js,json,md}' 'packages/*/*.{css,js,json,md}'",
"test": "lerna run test",
Expand All @@ -39,7 +40,7 @@
"trailingComma": "es5"
},
"lint-staged": {
"*.{css,js,json}": ["npm run lint", "npm run test", "git add"],
"*.md": ["npm run prettier", "git add"]
"*.{css,js,json}": ["yarn run lint", "yarn run test", "git add"],
"*.md": ["yarn run prettier", "git add"]
}
}
3 changes: 3 additions & 0 deletions packages/jaeger-ui/config-overrides-antd-vars.less
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@
@layout-zero-trigger-height : 42px;

@menu-dark-bg: #151515;

// Table
@table-row-hover-bg:#e5f2f2;
3 changes: 2 additions & 1 deletion packages/jaeger-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"sinon": "^3.2.1"
},
"dependencies": {
"@jaegertracing/plexus": "0.0.1-dev.3",
"antd": "^3.0.3",
"chance": "^1.0.10",
"classnames": "^2.2.5",
Expand Down Expand Up @@ -77,7 +78,7 @@
},
"scripts": {
"build": "REACT_APP_VSN_STATE=$(../../scripts/get-tracking-version.js) react-app-rewired build",
"coverage": "npm run test -- --coverage",
"coverage": "yarn run test -- --coverage",
"start:ga-debug":
"REACT_APP_GA_DEBUG=1 REACT_APP_VSN_STATE=$(../../scripts/get-tracking-version.js) react-app-rewired start",
"start": "react-app-rewired start",
Expand Down
6 changes: 6 additions & 0 deletions packages/jaeger-ui/src/actions/jaeger-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export const fetchTrace = createAction(
id => ({ id })
);

export const fetchMultipleTraces = createAction(
'@JAEGER_API/FETCH_MULTIPLE_TRACES',
ids => JaegerAPI.searchTraces({ traceID: ids }),
ids => ({ ids })
);

export const archiveTrace = createAction(
'@JAEGER_API/ARCHIVE_TRACE',
id => JaegerAPI.archiveTrace(id),
Expand Down
32 changes: 14 additions & 18 deletions packages/jaeger-ui/src/components/App/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,58 +22,54 @@ import type { Location } from 'react-router-dom';
import { withRouter } from 'react-router-dom';

import TopNav from './TopNav';
import type { Config } from '../../types/config';
import { trackPageView } from '../../utils/tracking';

import './Page.css';

type PageProps = {
location: Location,
type Props = {
pathname: string,
search: string,
children: React.Node,
config: Config,
};

const { Header, Content } = Layout;

// export for tests
export class PageImpl extends React.Component<PageProps> {
props: PageProps;
export class PageImpl extends React.Component<Props> {
props: Props;

componentDidMount() {
const { pathname, search } = this.props.location;
const { pathname, search } = this.props;
trackPageView(pathname, search);
}

componentWillReceiveProps(nextProps: PageProps) {
const { pathname, search } = this.props.location;
const { pathname: nextPathname, search: nextSearch } = nextProps.location;
componentWillReceiveProps(nextProps: Props) {
const { pathname, search } = this.props;
const { pathname: nextPathname, search: nextSearch } = nextProps;
if (pathname !== nextPathname || search !== nextSearch) {
trackPageView(nextPathname, nextSearch);
}
}

render() {
const { children, config, location } = this.props;
const menu = config && config.menu;
return (
<div>
<Helmet title="Jaeger UI" />
<Layout>
<Header className="Page--topNav">
<TopNav activeKey={location.pathname} menuConfig={menu} />
<TopNav />
</Header>
<Content className="Page--content">{children}</Content>
<Content className="Page--content">{this.props.children}</Content>
</Layout>
</div>
);
}
}

// export for tests
export function mapStateToProps(state: { config: Config, router: { location: Location } }, ownProps: any) {
const { config } = state;
const { location } = state.router;
return { ...ownProps, config, location };
export function mapStateToProps(state: { router: { location: Location } }) {
const { pathname, search } = state.router.location;
return { pathname, search };
}

export default withRouter(connect(mapStateToProps)(PageImpl));
27 changes: 10 additions & 17 deletions packages/jaeger-ui/src/components/App/Page.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@ import { trackPageView } from '../../utils/tracking';

describe('mapStateToProps()', () => {
it('maps state to props', () => {
const pathname = 'a-pathname';
const search = 'a-search';
const state = {
config: {},
router: { location: {} },
router: { location: { pathname, search } },
};
const ownProps = { a: {} };
expect(mapStateToProps(state, ownProps)).toEqual({
config: state.config,
location: state.router.location,
a: ownProps.a,
});
expect(mapStateToProps(state)).toEqual({ pathname, search });
});
});

Expand All @@ -44,11 +40,8 @@ describe('<Page>', () => {
beforeEach(() => {
trackPageView.mockReset();
props = {
location: {
pathname: String(Math.random()),
search: String(Math.random()),
},
config: { menu: [] },
pathname: String(Math.random()),
search: String(Math.random()),
};
wrapper = mount(<Page {...props} />);
});
Expand All @@ -58,14 +51,14 @@ describe('<Page>', () => {
});

it('tracks an initial page-view', () => {
const { pathname, search } = props.location;
const { pathname, search } = props;
expect(trackPageView.mock.calls).toEqual([[pathname, search]]);
});

it('tracks a pageView when the location changes', () => {
trackPageView.mockReset();
const location = { pathname: 'le-path', search: 'searching' };
wrapper.setProps({ location });
expect(trackPageView.mock.calls).toEqual([[location.pathname, location.search]]);
props = { pathname: 'le-path', search: 'searching' };
wrapper.setProps(props);
expect(trackPageView.mock.calls).toEqual([[props.pathname, props.search]]);
});
});
61 changes: 41 additions & 20 deletions packages/jaeger-ui/src/components/App/TopNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,38 @@

import React from 'react';
import { Dropdown, Icon, Menu } from 'antd';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';

import TraceIDSearchInput from './TraceIDSearchInput';
import type { ConfigMenuItem, ConfigMenuGroup } from '../../types/config';
import * as dependencies from '../DependencyGraph/url';
import * as searchUrl from '../SearchTracePage/url';
import * as diffUrl from '../TraceDiff/url';
import { getConfigValue } from '../../utils/config/get-config';
import prefixUrl from '../../utils/prefix-url';

type TopNavProps = {
activeKey: string,
menuConfig: (ConfigMenuItem | ConfigMenuGroup)[],
};
import type { ReduxState } from '../../types';
import type { ConfigMenuItem, ConfigMenuGroup } from '../../types/config';

type Props = ReduxState;

const NAV_LINKS = [
{
to: prefixUrl('/search'),
to: searchUrl.getUrl(),
matches: searchUrl.matches,
text: 'Search',
},
{
to: (props: Props) => diffUrl.getUrl(props.traceDiff),
matches: diffUrl.matches,
text: 'Compare',
},
];

if (getConfigValue('dependencies.menuEnabled')) {
NAV_LINKS.push({
to: prefixUrl('/dependencies'),
to: dependencies.getUrl(),
matches: dependencies.matches,
text: 'Dependencies',
});
}
Expand Down Expand Up @@ -66,12 +76,13 @@ function CustomNavDropdown({ label, items }: ConfigMenuGroup) {
);
}

export default function TopNav(props: TopNavProps) {
const { activeKey, menuConfig } = props;
const menuItems = Array.isArray(menuConfig) ? menuConfig : [];
export function TopNavImpl(props: Props) {
const { config, router } = props;
const { pathname } = router.location;
const menuItems = Array.isArray(config.menu) ? config.menu : [];
return (
<div>
<Menu theme="dark" mode="horizontal" selectable={false} className="ub-right" selectedKeys={[activeKey]}>
<Menu theme="dark" mode="horizontal" selectable={false} className="ub-right" selectedKeys={[pathname]}>
{menuItems.map(m => {
if (m.items != null) {
const group = ((m: any): ConfigMenuGroup);
Expand All @@ -91,25 +102,35 @@ export default function TopNav(props: TopNavProps) {
);
})}
</Menu>
<Menu theme="dark" mode="horizontal" selectable={false} selectedKeys={[activeKey]}>
<Menu theme="dark" mode="horizontal" selectable={false} selectedKeys={[pathname]}>
<Menu.Item>
<Link to={prefixUrl('/')}>Jaeger UI</Link>
</Menu.Item>
<Menu.Item>
<TraceIDSearchInput />
</Menu.Item>
{NAV_LINKS.map(({ to, text }) => (
<Menu.Item key={to}>
<Link to={to}>{text}</Link>
</Menu.Item>
))}
{NAV_LINKS.map(({ matches, to, text }) => {
const url = typeof to === 'string' ? to : to(props);
const key = matches(pathname) ? pathname : url;
return (
<Menu.Item key={key}>
<Link to={url}>{text}</Link>
</Menu.Item>
);
})}
</Menu>
</div>
);
}

TopNav.defaultProps = {
TopNavImpl.defaultProps = {
menuConfig: [],
};

TopNav.CustomNavDropdown = CustomNavDropdown;
TopNavImpl.CustomNavDropdown = CustomNavDropdown;

function mapStateToProps(state: Props) {
return state;
}

export default withRouter(connect(mapStateToProps)(TopNavImpl));
27 changes: 16 additions & 11 deletions packages/jaeger-ui/src/components/App/TopNav.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { Link } from 'react-router-dom';

import TopNav from './TopNav';
import { TopNavImpl as TopNav } from './TopNav';

describe('<TopNav>', () => {
const labelGitHub = 'GitHub';
Expand All @@ -34,16 +34,21 @@ describe('<TopNav>', () => {
];

const defaultProps = {
menuConfig: [
{
label: labelGitHub,
url: githubUrl,
},
{
label: labelAbout,
items: dropdownItems,
},
],
config: {
menu: [
{
label: labelGitHub,
url: githubUrl,
},
{
label: labelAbout,
items: dropdownItems,
},
],
},
router: {
location: { location: { pathname: 'some-path ' } },
},
};

let wrapper;
Expand Down
Loading

0 comments on commit eff9c27

Please sign in to comment.