Skip to content

Commit

Permalink
[APM] Error stack trace improvements (elastic#49254) (elastic#51072)
Browse files Browse the repository at this point in the history
  • Loading branch information
smith authored and sorenlouv committed Nov 20, 2019
1 parent e488f5d commit f385912
Show file tree
Hide file tree
Showing 20 changed files with 1,463 additions and 1,157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface ErrorTab {
export const logStacktraceTab: ErrorTab = {
key: 'log_stacktrace',
label: i18n.translate('xpack.apm.propertiesTable.tabs.logStacktraceLabel', {
defaultMessage: 'Log stacktrace'
defaultMessage: 'Log stack trace'
})
};

Expand All @@ -26,7 +26,7 @@ export const exceptionStacktraceTab: ErrorTab = {
label: i18n.translate(
'xpack.apm.propertiesTable.tabs.exceptionStacktraceLabel',
{
defaultMessage: 'Exception stacktrace'
defaultMessage: 'Exception stack trace'
}
)
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { shallow } from 'enzyme';
import { ExceptionStacktrace } from './ExceptionStacktrace';

describe('ExceptionStacktrace', () => {
describe('render', () => {
it('renders', () => {
const props = { exceptions: [] };

expect(() =>
shallow(<ExceptionStacktrace {...props} />)
).not.toThrowError();
});

describe('with a stack trace', () => {
it('renders the stack trace', () => {
const props = { exceptions: [{}] };

expect(
shallow(<ExceptionStacktrace {...props} />).find('Stacktrace')
).toHaveLength(1);
});
});

describe('with more than one stack trace', () => {
it('renders a cause stack trace', () => {
const props = { exceptions: [{}, {}] };

expect(
shallow(<ExceptionStacktrace {...props} />).find('CauseStacktrace')
).toHaveLength(1);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { EuiTitle } from '@elastic/eui';
import { idx } from '@kbn/elastic-idx/target';
import { Exception } from '../../../../../typings/es_schemas/raw/ErrorRaw';
import { Stacktrace } from '../../../shared/Stacktrace';
import { CauseStacktrace } from '../../../shared/Stacktrace/CauseStacktrace';

interface ExceptionStacktraceProps {
codeLanguage?: string;
exceptions: Exception[];
}

export function ExceptionStacktrace({
codeLanguage,
exceptions
}: ExceptionStacktraceProps) {
const title = idx(exceptions, _ => _[0].message);

return (
<>
<EuiTitle size="xs">
<h4>{title}</h4>
</EuiTitle>
{exceptions.map((ex, index) => {
return index === 0 ? (
<Stacktrace
key={index}
stackframes={ex.stacktrace}
codeLanguage={codeLanguage}
/>
) : (
<CauseStacktrace
codeLanguage={codeLanguage}
key={index}
id={index.toString()}
message={ex.message}
stackframes={ex.stacktrace}
/>
);
})}
</>
);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { TimestampTooltip } from '../../../shared/TimestampTooltip';
import { HttpInfoSummaryItem } from '../../../shared/Summary/HttpInfoSummaryItem';
import { TransactionDetailLink } from '../../../shared/Links/apm/TransactionDetailLink';
import { UserAgentSummaryItem } from '../../../shared/Summary/UserAgentSummaryItem';
import { ExceptionStacktrace } from './ExceptionStacktrace';

const HeaderContainer = styled.div`
display: flex;
Expand Down Expand Up @@ -180,15 +181,15 @@ export function DetailView({ errorGroup, urlParams, location }: Props) {
);
}

export function TabContent({
function TabContent({
error,
currentTab
}: {
error: APMError;
currentTab: ErrorTab;
}) {
const codeLanguage = idx(error, _ => _.service.language.name);
const excStackframes = idx(error, _ => _.error.exception[0].stacktrace);
const exceptions = idx(error, _ => _.error.exception) || [];
const logStackframes = idx(error, _ => _.error.log.stacktrace);

switch (currentTab.key) {
Expand All @@ -198,7 +199,10 @@ export function TabContent({
);
case exceptionStacktraceTab.key:
return (
<Stacktrace stackframes={excStackframes} codeLanguage={codeLanguage} />
<ExceptionStacktrace
codeLanguage={codeLanguage}
exceptions={exceptions}
/>
);
default:
return <ErrorMetadata error={error} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiLink } from '@elastic/eui';
import { EuiIcon, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Fragment, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { px, units } from '../../../../../../../style/variables';
import { Ellipsis } from '../../../../../../shared/Icons';

const ToggleButtonContainer = styled.div`
margin-top: ${px(units.half)};
Expand Down Expand Up @@ -55,7 +54,13 @@ export const TruncateHeightSection: React.SFC<Props> = ({
setIsOpen(!isOpen);
}}
>
<Ellipsis horizontal={!isOpen} />{' '}
<EuiIcon
style={{
transition: 'transform 0.1s',
transform: `rotate(${isOpen ? 90 : 0}deg)`
}}
type="arrowRight"
/>{' '}
{isOpen
? i18n.translate('xpack.apm.toggleHeight.showLessButtonLabel', {
defaultMessage: 'Show fewer lines'
Expand Down
20 changes: 0 additions & 20 deletions x-pack/legacy/plugins/apm/public/components/shared/Icons.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { mount, shallow } from 'enzyme';
import { CauseStacktrace } from './CauseStacktrace';

describe('CauseStacktrace', () => {
describe('render', () => {
describe('with no stack trace', () => {
it('renders without the accordion', () => {
const props = { id: 'testId', message: 'testMessage' };

expect(
mount(<CauseStacktrace {...props} />).find('CausedBy')
).toHaveLength(1);
});
});

describe('with no message and a stack trace', () => {
it('says "Caused by …', () => {
const props = {
id: 'testId',
stackframes: [{ filename: 'testFilename', line: { number: 1 } }]
};

expect(
mount(<CauseStacktrace {...props} />)
.find('EuiTitle span')
.text()
).toEqual('…');
});
});

describe('with a message and a stack trace', () => {
it('renders with the accordion', () => {
const props = {
id: 'testId',
message: 'testMessage',
stackframes: [{ filename: 'testFilename', line: { number: 1 } }]
};

expect(
shallow(<CauseStacktrace {...props} />).find('Styled(EuiAccordion)')
).toHaveLength(1);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import styled from 'styled-components';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiTitle } from '@elastic/eui';
import { px, unit } from '../../../style/variables';
import { Stacktrace } from '.';
import { IStackframe } from '../../../../typings/es_schemas/raw/fields/Stackframe';

// @ts-ignore Styled Components has trouble inferring the types of the default props here.
const Accordion = styled(EuiAccordion)`
border-top: ${theme.euiBorderThin};
`;

const CausedByContainer = styled('h5')`
padding: ${theme.spacerSizes.s} 0;
`;

const CausedByHeading = styled('span')`
color: ${theme.textColors.subdued};
display: block;
font-size: ${theme.euiFontSizeXS};
font-weight: ${theme.euiFontWeightBold};
text-transform: uppercase;
`;

const FramesContainer = styled('div')`
padding-left: ${px(unit)};
`;

function CausedBy({ message }: { message: string }) {
return (
<CausedByContainer>
<CausedByHeading>
{i18n.translate(
'xpack.apm.stacktraceTab.causedByFramesToogleButtonLabel',
{
defaultMessage: 'Caused By'
}
)}
</CausedByHeading>
<EuiTitle size="xxs">
<span>{message}</span>
</EuiTitle>
</CausedByContainer>
);
}

interface CauseStacktraceProps {
codeLanguage?: string;
id: string;
message?: string;
stackframes?: IStackframe[];
}

export function CauseStacktrace({
codeLanguage,
id,
message = '…',
stackframes = []
}: CauseStacktraceProps) {
if (stackframes.length === 0) {
return <CausedBy message={message} />;
}

return (
<Accordion buttonContent={<CausedBy message={message} />} id={id}>
<FramesContainer>
<Stacktrace stackframes={stackframes} codeLanguage={codeLanguage} />
</FramesContainer>
</Accordion>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ registerLanguage('ruby', ruby);

const ContextContainer = styled.div`
position: relative;
border-radius: 0 0 ${borderRadius} ${borderRadius};
border-radius: ${borderRadius};
`;

const LINE_HEIGHT = units.eighth * 9;
Expand All @@ -49,7 +49,7 @@ const LineNumberContainer = styled.div<{ isLibraryFrame: boolean }>`
position: absolute;
top: 0;
left: 0;
border-radius: 0 0 0 ${borderRadius};
border-radius: ${borderRadius};
background: ${props =>
props.isLibraryFrame
? theme.euiColorEmptyShade
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { IStackframe } from '../../../../typings/es_schemas/raw/fields/Stackfram
import { fontFamilyCode, fontSize, px, units } from '../../../style/variables';

const FileDetails = styled.div`
color: ${theme.euiColorMediumShade};
padding: ${px(units.half)};
color: ${theme.euiColorDarkShade};
padding: ${px(units.half)} 0;
font-family: ${fontFamilyCode};
font-size: ${fontSize};
`;

const LibraryFrameFileDetail = styled.span`
color: ${theme.euiColorDarkShade};
`;

const AppFrameFileDetail = styled.span`
font-weight: bold;
color: ${theme.euiColorFullShade};
`;

Expand Down
Loading

0 comments on commit f385912

Please sign in to comment.