Skip to content

Commit

Permalink
[APM] Hoist loading of waterfall and flatten it (#24651) (#24893)
Browse files Browse the repository at this point in the history
* [APM] Hoist loading of waterfall and flatten it

Remove unused test

Convert to typescript

* Address feedback

* Make `totalDuration` optional

* Renamed rootTransaction to traceRoot

* [APM] Only show relevant service legends

* Adds services label to the service legend

* [APM] Clock skew fix

Only skew child spans from the same service

Take parent skew into account when finding diff

# Conflicts:
#	x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap
#	x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts
#	x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts

* Use switch statement
  • Loading branch information
sorenlouv authored Oct 31, 2018
1 parent b63b53d commit cd13ccb
Show file tree
Hide file tree
Showing 31 changed files with 522 additions and 676 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
} from '../../../../style/variables';
import { get, capitalize, isEmpty } from 'lodash';
import { STATUS } from '../../../../constants';

import { StickyProperties } from '../../../shared/StickyProperties';
import { Tab, HeaderMedium } from '../../../shared/UIComponents';
import DiscoverButton from '../../../shared/DiscoverButton';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import { connect } from 'react-redux';
import { IReduxState } from '../../../store/rootReducer';
// @ts-ignore
import { getUrlParams } from '../../../store/urlParams';
import { TraceOverview as View } from './view';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { EuiCallOut, EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import React from 'react';
import { RRRRenderArgs } from 'react-redux-request';
import { RRRRenderResponse } from 'react-redux-request';
import { ITransactionGroup } from '../../../../typings/TransactionGroup';
// @ts-ignore
import { TraceListRequest } from '../../../store/reactReduxRequest/traceList';
Expand Down Expand Up @@ -37,7 +37,7 @@ export function TraceOverview(props: Props) {
<EuiSpacer />
<TraceListRequest
urlParams={urlParams}
render={({ data, status }: RRRRenderArgs<ITransactionGroup[]>) => (
render={({ data, status }: RRRRenderResponse<ITransactionGroup[]>) => (
<TraceList
items={data}
isLoading={status === 'LOADING'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

import { get } from 'lodash';
import React from 'react';
import { connect } from 'react-redux';
import { selectWaterfallRoot } from 'x-pack/plugins/apm/public/store/selectors/waterfall';
import {
REQUEST_URL_FULL,
TRANSACTION_DURATION,
Expand All @@ -17,35 +15,33 @@ import {
import { Transaction } from '../../../../../typings/Transaction';
// @ts-ignore
import { asTime } from '../../../../utils/formatters';
// @ts-ignore
import {
IStickyProperty,
StickyProperties
} from '../../../shared/StickyProperties';

function getDurationPercent(
transactionDuration: number,
rootDuration?: number
totalDuration?: number
) {
if (rootDuration === undefined || rootDuration === 0) {
if (!totalDuration) {
return '';
}
return ((transactionDuration / rootDuration) * 100).toFixed(2) + '%';
return ((transactionDuration / totalDuration) * 100).toFixed(2) + '%';
}

interface Props {
transaction: Transaction;
root?: Transaction;
totalDuration?: number;
}

export function StickyTransactionPropertiesComponent({
export function StickyTransactionProperties({
transaction,
root
totalDuration
}: Props) {
const timestamp = get(transaction, '@timestamp');
const timestamp = transaction['@timestamp'];
const url = get(transaction, REQUEST_URL_FULL, 'N/A');
const duration = transaction.transaction.duration.us;
const rootDuration = root && root.transaction.duration.us;
const stickyProperties: IStickyProperty[] = [
{
label: 'Timestamp',
Expand All @@ -69,7 +65,7 @@ export function StickyTransactionPropertiesComponent({
},
{
label: '% of trace',
val: getDurationPercent(duration, rootDuration),
val: getDurationPercent(duration, totalDuration),
width: '25%'
},
{
Expand All @@ -89,11 +85,3 @@ export function StickyTransactionPropertiesComponent({

return <StickyProperties stickyProperties={stickyProperties} />;
}

const mapStateToProps = (state: any, props: Partial<Props>) => ({
root: selectWaterfallRoot(state, props)
});

export const StickyTransactionProperties = connect<{}, {}, Props>(
mapStateToProps
)(StickyTransactionPropertiesComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
PropertiesTable
} from '../../../shared/PropertiesTable';
import { WaterfallContainer } from './WaterfallContainer';
import { IWaterfall } from './WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers';

const TableContainer = styled.div`
padding: ${px(units.plus)} ${px(units.plus)} 0;
Expand All @@ -44,11 +45,15 @@ interface TransactionPropertiesTableProps {
location: any;
transaction: Transaction;
urlParams: IUrlParams;
waterfall: IWaterfall;
}

export const TransactionPropertiesTable: React.SFC<
TransactionPropertiesTableProps
> = ({ location, transaction, urlParams }) => {
export function TransactionPropertiesTable({
location,
transaction,
urlParams,
waterfall
}: TransactionPropertiesTableProps) {
const tabs = getTabs(transaction);
const currentTab = getCurrentTab(tabs, urlParams.detailTab);
const agentName = transaction.context.service.agent.name;
Expand Down Expand Up @@ -84,6 +89,7 @@ export const TransactionPropertiesTable: React.SFC<
transaction={transaction}
location={location}
urlParams={urlParams}
waterfall={waterfall}
/>
)}

Expand All @@ -98,4 +104,4 @@ export const TransactionPropertiesTable: React.SFC<
)}
</div>
);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiTitle } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { px, unit } from '../../../../../style/variables';
Expand All @@ -13,7 +14,7 @@ import Legend from '../../../../shared/charts/Legend';
const Legends = styled.div`
display: flex;
div {
> * {
margin-right: ${px(unit)};
&:last-child {
margin-right: 0;
Expand All @@ -30,6 +31,9 @@ interface Props {
export function ServiceLegends({ serviceColors }: Props) {
return (
<Legends>
<EuiTitle size="xxxs">
<span>Services</span>
</EuiTitle>
{Object.entries(serviceColors).map(([label, color]) => (
<Legend key={color} color={color} text={label} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ import {
SERVICE_NAME,
TRANSACTION_NAME
} from 'x-pack/plugins/apm/common/constants';
// @ts-ignore
import { StickyProperties } from 'x-pack/plugins/apm/public/components/shared/StickyProperties';
import { TransactionLink } from 'x-pack/plugins/apm/public/components/shared/TransactionLink';
import { KibanaLink } from 'x-pack/plugins/apm/public/utils/url';
import { Transaction } from 'x-pack/plugins/apm/typings/Transaction';

interface Props {
transaction: Transaction;
transaction?: Transaction;
}

export function FlyoutTopLevelProperties({ transaction }: Props) {
if (!transaction) {
return null;
}

const stickyProperties = [
{
label: 'Service',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { first } from 'lodash';
import { Span } from '../../../../../../../../typings/Span';
// @ts-ignore
import { asMillis } from '../../../../../../../utils/formatters';
// @ts-ignore
import { StickyProperties } from '../../../../../../shared/StickyProperties';

function getSpanLabel(type: string) {
Expand All @@ -32,10 +31,14 @@ function getPrimaryType(type: string) {

interface Props {
span: Span;
totalDuration: number;
totalDuration?: number;
}

export function StickySpanProperties({ span, totalDuration }: Props) {
if (!totalDuration) {
return null;
}

const spanName = span.span.name;
const spanDuration = span.span.duration.us;
const relativeDuration = spanDuration / totalDuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ function getDiscoverQuery(span: Span) {

interface Props {
span?: Span;
parentTransaction: Transaction;
totalDuration: number;
parentTransaction?: Transaction;
totalDuration?: number;
onClose: () => void;
}

Expand All @@ -70,7 +70,7 @@ export function SpanFlyout({
return null;
}
const stackframes = span.span.stacktrace;
const codeLanguage = get(span, SERVICE_LANGUAGE_NAME);
const codeLanguage: string = get(span, SERVICE_LANGUAGE_NAME);
const dbContext = span.context.db;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ export function TransactionFlyout({
<EuiFlyoutBody>
<FlyoutTopLevelProperties transaction={transactionDoc} />
<EuiHorizontalRule />
<StickyTransactionProperties transaction={transactionDoc} />
<StickyTransactionProperties
transaction={transactionDoc}
totalDuration={waterfall.traceRootDuration}
/>
<EuiHorizontalRule />
<TransactionPropertiesTableForFlyout
transaction={transactionDoc}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ interface ITimelineMargins {

interface IWaterfallItemProps {
timelineMargins: ITimelineMargins;
totalDuration: number;
totalDuration?: number;
item: IWaterfallItem;
color: string;
isSelected: boolean;
Expand All @@ -111,8 +111,12 @@ export function WaterfallItem({
isSelected,
onClick
}: IWaterfallItemProps) {
if (!totalDuration) {
return null;
}

const width = (item.duration / totalDuration) * 100;
const left = (item.offset / totalDuration) * 100;
const left = ((item.offset + item.skew) / totalDuration) * 100;
const Label = item.docType === 'transaction' ? TransactionLabel : SpanLabel;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Component, Fragment } from 'react';
import React, { Component } from 'react';
// @ts-ignore
import { StickyContainer } from 'react-sticky';
import styled from 'styled-components';
Expand Down Expand Up @@ -62,26 +62,19 @@ export class Waterfall extends Component<Props> {
});
};

public renderWaterfall = (item?: IWaterfallItem) => {
if (!item) {
return null;
}

public getWaterfallItem = (item: IWaterfallItem) => {
const { serviceColors, waterfall, urlParams }: Props = this.props;

return (
<Fragment key={item.id}>
<WaterfallItem
timelineMargins={TIMELINE_MARGINS}
color={serviceColors[item.serviceName]}
item={item}
totalDuration={waterfall.duration}
isSelected={item.id === urlParams.waterfallItemId}
onClick={() => this.onOpenFlyout(item)}
/>

{item.children && item.children.map(this.renderWaterfall)}
</Fragment>
<WaterfallItem
key={item.id}
timelineMargins={TIMELINE_MARGINS}
color={serviceColors[item.serviceName]}
item={item}
totalDuration={waterfall.duration}
isSelected={item.id === urlParams.waterfallItemId}
onClick={() => this.onOpenFlyout(item)}
/>
);
};

Expand All @@ -98,11 +91,15 @@ export class Waterfall extends Component<Props> {

switch (currentItem.docType) {
case 'span':
const parentTransaction = waterfall.getTransactionById(
currentItem.parentId
);

return (
<SpanFlyout
totalDuration={waterfall.duration}
span={currentItem.span}
parentTransaction={currentItem.parentTransaction}
parentTransaction={parentTransaction}
onClose={this.onCloseFlyout}
/>
);
Expand All @@ -124,7 +121,7 @@ export class Waterfall extends Component<Props> {
public render() {
const { waterfall } = this.props;
const itemContainerHeight = 58; // TODO: This is a nasty way to calculate the height of the svg element. A better approach should be found
const waterfallHeight = itemContainerHeight * waterfall.childrenCount;
const waterfallHeight = itemContainerHeight * waterfall.items.length;

return (
<Container>
Expand All @@ -140,7 +137,7 @@ export class Waterfall extends Component<Props> {
paddingTop: TIMELINE_MARGINS.top
}}
>
{this.renderWaterfall(waterfall.root)}
{waterfall.items.map(this.getWaterfallItem)}
</div>
</StickyContainer>

Expand Down
Loading

0 comments on commit cd13ccb

Please sign in to comment.