From 8988e7d33add58bb17f0a3174d61e33eabbed62b Mon Sep 17 00:00:00 2001 From: Ash Anand Date: Wed, 20 Dec 2023 16:12:41 -0500 Subject: [PATCH 1/4] feat(breadcrumbs): Send component names on UI breadcrumbs --- .../Breadcrumbs/dom/click/template.html | 1 + .../Breadcrumbs/dom/click/test.ts | 36 +++++++++++++++ .../Breadcrumbs/dom/textInput/template.html | 1 + .../Breadcrumbs/dom/textInput/test.ts | 45 +++++++++++++++++++ .../browser/src/integrations/breadcrumbs.ts | 29 +++++++----- 5 files changed, 101 insertions(+), 11 deletions(-) diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/template.html b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/template.html index 5048dfd754f2..e54da47ff09d 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/template.html +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/template.html @@ -7,5 +7,6 @@ + diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts index 88a1c89fba0d..f965b8c93a83 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts @@ -55,3 +55,39 @@ sentryTest('captures Breadcrumb for clicks & debounces them for a second', async }, ]); }); + +sentryTest( + 'uses the annotated component name in the breadcrumb messages and adds it to the data object', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', route => { + return route.fulfill({ + status: 200, + body: JSON.stringify({ + userNames: ['John', 'Jane'], + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + }); + + const promise = getFirstSentryEnvelopeRequest(page); + + await page.goto(url); + await page.click('#annotated-button'); + await page.evaluate('Sentry.captureException("test exception")'); + + const eventData = await promise; + + expect(eventData.breadcrumbs).toEqual([ + { + timestamp: expect.any(Number), + category: 'ui.click', + message: 'body > AnnotatedButton', + data: { componentName: 'AnnotatedButton' }, + }, + ]); + }, +); diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/template.html b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/template.html index b3d53fbf9a3e..a16ca41e45da 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/template.html +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/template.html @@ -7,5 +7,6 @@ + diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts index b3393561f331..e36e8c17ed2e 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts @@ -64,3 +64,48 @@ sentryTest('captures Breadcrumb for events on inputs & debounced them', async ({ }, ]); }); + +sentryTest( + 'includes the annotated component name within the breadcrumb message and data', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', route => { + return route.fulfill({ + status: 200, + body: JSON.stringify({ + userNames: ['John', 'Jane'], + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + }); + + const promise = getFirstSentryEnvelopeRequest(page); + + await page.goto(url); + + await page.click('#annotated-input'); + await page.type('#annotated-input', 'John', { delay: 1 }); + + await page.evaluate('Sentry.captureException("test exception")'); + const eventData = await promise; + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData.breadcrumbs).toEqual([ + { + timestamp: expect.any(Number), + category: 'ui.click', + message: 'body > AnnotatedInput', + data: { componentName: 'AnnotatedInput' }, + }, + { + timestamp: expect.any(Number), + category: 'ui.input', + message: 'body > AnnotatedInput', + data: { componentName: 'AnnotatedInput' }, + }, + ]); + }, +); diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 102d1d7e500d..cd3ca3595e54 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -12,6 +12,7 @@ import type { IntegrationFn, } from '@sentry/types'; import type { + Breadcrumb, FetchBreadcrumbData, FetchBreadcrumbHint, XhrBreadcrumbData, @@ -24,6 +25,7 @@ import { addFetchInstrumentationHandler, addHistoryInstrumentationHandler, addXhrInstrumentationHandler, + getComponentName, getEventDescription, htmlTreeAsString, logger, @@ -133,6 +135,7 @@ function _getDomBreadcrumbHandler( } let target; + let componentName; let keyAttrs = typeof dom === 'object' ? dom.serializeAttribute : undefined; let maxStringLength = @@ -155,6 +158,7 @@ function _getDomBreadcrumbHandler( target = _isEvent(event) ? htmlTreeAsString(event.target, { keyAttrs, maxStringLength }) : htmlTreeAsString(event, { keyAttrs, maxStringLength }); + componentName = _isEvent(event) ? getComponentName(event.target) : getComponentName(event); } catch (e) { target = ''; } @@ -163,17 +167,20 @@ function _getDomBreadcrumbHandler( return; } - addBreadcrumb( - { - category: `ui.${handlerData.name}`, - message: target, - }, - { - event: handlerData.event, - name: handlerData.name, - global: handlerData.global, - }, - ); + const breadcrumb: Breadcrumb = { + category: `ui.${handlerData.name}`, + message: target, + }; + + if (componentName) { + breadcrumb.data = { componentName }; + } + + addBreadcrumb(breadcrumb, { + event: handlerData.event, + name: handlerData.name, + global: handlerData.global, + }); }; } From 10c5870da3187c0e3608a6daba61cdd3d4fad962 Mon Sep 17 00:00:00 2001 From: Ash Anand Date: Thu, 21 Dec 2023 12:18:26 -0500 Subject: [PATCH 2/4] Rename componentName property --- .../suites/integrations/Breadcrumbs/dom/click/test.ts | 2 +- .../suites/integrations/Breadcrumbs/dom/textInput/test.ts | 4 ++-- packages/browser/src/integrations/breadcrumbs.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts index f965b8c93a83..93ceb1e70001 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/click/test.ts @@ -86,7 +86,7 @@ sentryTest( timestamp: expect.any(Number), category: 'ui.click', message: 'body > AnnotatedButton', - data: { componentName: 'AnnotatedButton' }, + data: { 'ui.component_name': 'AnnotatedButton' }, }, ]); }, diff --git a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts index e36e8c17ed2e..3a25abb1f9fe 100644 --- a/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts +++ b/packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/textInput/test.ts @@ -98,13 +98,13 @@ sentryTest( timestamp: expect.any(Number), category: 'ui.click', message: 'body > AnnotatedInput', - data: { componentName: 'AnnotatedInput' }, + data: { 'ui.component_name': 'AnnotatedInput' }, }, { timestamp: expect.any(Number), category: 'ui.input', message: 'body > AnnotatedInput', - data: { componentName: 'AnnotatedInput' }, + data: { 'ui.component_name': 'AnnotatedInput' }, }, ]); }, diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index cd3ca3595e54..7c50630efa01 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -173,7 +173,7 @@ function _getDomBreadcrumbHandler( }; if (componentName) { - breadcrumb.data = { componentName }; + breadcrumb.data = { 'ui.component_name': componentName }; } addBreadcrumb(breadcrumb, { From f66dc8d718b2f33f016120f92ad8e035f4c6b576 Mon Sep 17 00:00:00 2001 From: Ash <0Calories@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:26:10 -0500 Subject: [PATCH 3/4] Update packages/browser/src/integrations/breadcrumbs.ts Co-authored-by: Abhijeet Prasad --- packages/browser/src/integrations/breadcrumbs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 7c50630efa01..f1511a7f4b68 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -155,10 +155,10 @@ function _getDomBreadcrumbHandler( // Accessing event.target can throw (see getsentry/raven-js#838, #768) try { const event = handlerData.event as Event | Node; - target = _isEvent(event) - ? htmlTreeAsString(event.target, { keyAttrs, maxStringLength }) - : htmlTreeAsString(event, { keyAttrs, maxStringLength }); - componentName = _isEvent(event) ? getComponentName(event.target) : getComponentName(event); + const element = _isEvent(event) ? event.target : event; + + target = htmlTreeAsString(element, { keyAttrs, maxStringLength }); + componentName = getComponentName(element); } catch (e) { target = ''; } From 44e49d171b45fd14a6840287ebbe9d172b32eb61 Mon Sep 17 00:00:00 2001 From: Ash Anand Date: Thu, 21 Dec 2023 12:56:38 -0500 Subject: [PATCH 4/4] run formatter --- packages/browser/src/integrations/breadcrumbs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index f1511a7f4b68..c14465b3448b 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -156,7 +156,7 @@ function _getDomBreadcrumbHandler( try { const event = handlerData.event as Event | Node; const element = _isEvent(event) ? event.target : event; - + target = htmlTreeAsString(element, { keyAttrs, maxStringLength }); componentName = getComponentName(element); } catch (e) {