diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap index 205a303bcf47b..afa0cb51cd108 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap +++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap @@ -11,6 +11,12 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = ` "sortable": false, "width": "96px", }, + Object { + "field": "type", + "name": "Type", + "render": [Function], + "sortable": false, + }, Object { "field": "message", "name": "Error message and culprit", @@ -142,7 +148,28 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = ` +
+ + Type + +
+ + List should render empty state 1`] = ` List should render empty state 1`] = ` aria-live="polite" aria-sort="descending" className="euiTableHeaderCell" - data-test-subj="tableHeaderCell_occurrenceCount_3" + data-test-subj="tableHeaderCell_occurrenceCount_4" role="columnheader" scope="col" style={ @@ -225,7 +252,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = ` aria-live="polite" aria-sort="none" className="euiTableHeaderCell" - data-test-subj="tableHeaderCell_latestOccurrenceAt_4" + data-test-subj="tableHeaderCell_latestOccurrenceAt_5" role="columnheader" scope="col" style={ @@ -264,7 +291,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = ` > List should render with data 1`] = ` font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace; } +.c2 { + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .c1 { max-width: 100%; white-space: nowrap; @@ -301,7 +335,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` text-overflow: ellipsis; } -.c2 { +.c3 { font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace; font-size: 16px; max-width: 100%; @@ -310,7 +344,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` text-overflow: ellipsis; } -.c3 { +.c4 { font-family: "Roboto Mono",Consolas,Menlo,Courier,monospace; } @@ -324,6 +358,12 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` "sortable": false, "width": "96px", }, + Object { + "field": "type", + "name": "Type", + "render": [Function], + "sortable": false, + }, Object { "field": "message", "name": "Error message and culprit", @@ -486,7 +526,28 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` +
+ + Type + +
+ + List should render with data 1`] = ` List should render with data 1`] = ` aria-live="polite" aria-sort="descending" className="euiTableHeaderCell" - data-test-subj="tableHeaderCell_occurrenceCount_3" + data-test-subj="tableHeaderCell_occurrenceCount_4" role="columnheader" scope="col" style={ @@ -569,7 +630,7 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` aria-live="polite" aria-sort="none" className="euiTableHeaderCell" - data-test-subj="tableHeaderCell_latestOccurrenceAt_4" + data-test-subj="tableHeaderCell_latestOccurrenceAt_5" role="columnheader" scope="col" style={ @@ -642,6 +703,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = ` + +
+ Type +
+
+ + + + + +
+ List should render with data 1`] = ` className="" >
List should render with data 1`] = ` serviceName="opbeans-python" > List should render with data 1`] = ` onFocus={[Function]} >
@@ -812,6 +916,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
+ +
+ Type +
+
+ + + + + +
+ List should render with data 1`] = ` className="" >
List should render with data 1`] = ` serviceName="opbeans-python" > List should render with data 1`] = ` onFocus={[Function]} >
@@ -982,6 +1129,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
+ +
+ Type +
+
+ + + + + +
+ List should render with data 1`] = ` className="" >
List should render with data 1`] = ` serviceName="opbeans-python" > List should render with data 1`] = ` onFocus={[Function]} >
@@ -1152,6 +1342,49 @@ exports[`ErrorGroupOverview -> List should render with data 1`] = `
+ +
+ Type +
+
+ + + + + +
+ List should render with data 1`] = ` className="" >
List should render with data 1`] = ` serviceName="opbeans-python" > List should render with data 1`] = ` onFocus={[Function]} >
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx index b26833c02fe22..250b9a5d188d0 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx @@ -23,6 +23,8 @@ import { useUrlParams } from '../../../../hooks/useUrlParams'; import { ManagedTable } from '../../../shared/ManagedTable'; import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink'; import { TimestampTooltip } from '../../../shared/TimestampTooltip'; +import { ErrorOverviewLink } from '../../../shared/Links/apm/ErrorOverviewLink'; +import { APMQueryParams } from '../../../shared/Links/url_helpers'; const GroupIdLink = styled(ErrorDetailLink)` font-family: ${fontFamilyCode}; @@ -32,6 +34,10 @@ const MessageAndCulpritCell = styled.div` ${truncate('100%')}; `; +const ErrorLink = styled(ErrorOverviewLink)` + ${truncate('100%')}; +`; + const MessageLink = styled(ErrorDetailLink)` font-family: ${fontFamilyCode}; font-size: ${fontSizes.large}; @@ -48,9 +54,8 @@ interface Props { const ErrorGroupList: React.FC = props => { const { items } = props; - const { - urlParams: { serviceName } - } = useUrlParams(); + const { urlParams } = useUrlParams(); + const { serviceName } = urlParams; if (!serviceName) { throw new Error('Service name is required'); @@ -73,6 +78,29 @@ const ErrorGroupList: React.FC = props => { ); } }, + { + name: i18n.translate('xpack.apm.errorsTable.typeColumnLabel', { + defaultMessage: 'Type' + }), + field: 'type', + sortable: false, + render: (type: string, item: ErrorGroupListAPIResponse[0]) => { + return ( + + {type} + + ); + } + }, { name: i18n.translate( 'xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel', @@ -150,7 +178,7 @@ const ErrorGroupList: React.FC = props => { ) } ], - [serviceName] + [serviceName, urlParams] ); return ( diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 5de82a9ee8788..54dd4704edfc0 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -16,6 +16,8 @@ exports[`Error ERROR_EXC_HANDLED 1`] = `undefined`; exports[`Error ERROR_EXC_MESSAGE 1`] = `undefined`; +exports[`Error ERROR_EXC_TYPE 1`] = `undefined`; + exports[`Error ERROR_GROUP_ID 1`] = `"grouping key"`; exports[`Error ERROR_LOG_LEVEL 1`] = `undefined`; @@ -144,6 +146,8 @@ exports[`Span ERROR_EXC_HANDLED 1`] = `undefined`; exports[`Span ERROR_EXC_MESSAGE 1`] = `undefined`; +exports[`Span ERROR_EXC_TYPE 1`] = `undefined`; + exports[`Span ERROR_GROUP_ID 1`] = `undefined`; exports[`Span ERROR_LOG_LEVEL 1`] = `undefined`; @@ -272,6 +276,8 @@ exports[`Transaction ERROR_EXC_HANDLED 1`] = `undefined`; exports[`Transaction ERROR_EXC_MESSAGE 1`] = `undefined`; +exports[`Transaction ERROR_EXC_TYPE 1`] = `undefined`; + exports[`Transaction ERROR_GROUP_ID 1`] = `undefined`; exports[`Transaction ERROR_LOG_LEVEL 1`] = `undefined`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index bc1b346f50da7..d5c3f91eb9247 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -60,6 +60,7 @@ export const ERROR_LOG_LEVEL = 'error.log.level'; export const ERROR_LOG_MESSAGE = 'error.log.message'; export const ERROR_EXC_MESSAGE = 'error.exception.message'; // only to be used in es queries, since error.exception is now an array export const ERROR_EXC_HANDLED = 'error.exception.handled'; // only to be used in es queries, since error.exception is now an array +export const ERROR_EXC_TYPE = 'error.exception.type'; export const ERROR_PAGE_URL = 'error.page.url'; // METRICS diff --git a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap index b9ac9d5431700..982ad558dc91d 100644 --- a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap @@ -73,6 +73,7 @@ Object { "error.log.message", "error.exception.message", "error.exception.handled", + "error.exception.type", "error.culprit", "error.grouping_key", "@timestamp", @@ -148,6 +149,7 @@ Object { "error.log.message", "error.exception.message", "error.exception.handled", + "error.exception.type", "error.culprit", "error.grouping_key", "@timestamp", diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts index 8ea6df5a9898a..5221d737866f4 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts @@ -8,6 +8,7 @@ import { ERROR_CULPRIT, ERROR_EXC_HANDLED, ERROR_EXC_MESSAGE, + ERROR_EXC_TYPE, ERROR_GROUP_ID, ERROR_LOG_MESSAGE } from '../../../common/elasticsearch_fieldnames'; @@ -67,6 +68,7 @@ export async function getErrorGroups({ ERROR_LOG_MESSAGE, ERROR_EXC_MESSAGE, ERROR_EXC_HANDLED, + ERROR_EXC_TYPE, ERROR_CULPRIT, ERROR_GROUP_ID, '@timestamp' @@ -99,6 +101,7 @@ export async function getErrorGroups({ exception?: Array<{ handled?: boolean; message?: string; + type?: string; }>; culprit: APMError['error']['culprit']; grouping_key: APMError['error']['grouping_key']; @@ -120,7 +123,8 @@ export async function getErrorGroups({ culprit: source.error.culprit, groupId: source.error.grouping_key, latestOccurrenceAt: source['@timestamp'], - handled: source.error.exception?.[0].handled + handled: source.error.exception?.[0].handled, + type: source.error.exception?.[0].type }; });