From e70d1b3aa9aaf2fd2a6b25de9bb584c35f494107 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 17 Sep 2024 21:16:04 -0400 Subject: [PATCH 1/9] fix(core): Set log level for Fetch/XHR breadcrumbs based on status code Signed-off-by: Kaung Zin Hein --- packages/core/src/breadcrumbs.ts | 3 ++- packages/core/src/scope.ts | 3 ++- packages/core/src/utils/breadcrumbsUtils.ts | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 packages/core/src/utils/breadcrumbsUtils.ts diff --git a/packages/core/src/breadcrumbs.ts b/packages/core/src/breadcrumbs.ts index 1cfad5d08fea..f452fa8cfcbc 100644 --- a/packages/core/src/breadcrumbs.ts +++ b/packages/core/src/breadcrumbs.ts @@ -1,6 +1,7 @@ import type { Breadcrumb, BreadcrumbHint } from '@sentry/types'; import { consoleSandbox, dateTimestampInSeconds } from '@sentry/utils'; import { getClient, getIsolationScope } from './currentScopes'; +import { assignBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; /** * Default maximum number of breadcrumbs added to an event. Can be overwritten @@ -25,7 +26,7 @@ export function addBreadcrumb(breadcrumb: Breadcrumb, hint?: BreadcrumbHint): vo if (maxBreadcrumbs <= 0) return; const timestamp = dateTimestampInSeconds(); - const mergedBreadcrumb = { timestamp, ...breadcrumb }; + const mergedBreadcrumb = { timestamp, ...assignBreadcrumbLogLevel(breadcrumb) }; const finalBreadcrumb = beforeBreadcrumb ? (consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint)) as Breadcrumb | null) : mergedBreadcrumb; diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index ff89c0d593a9..60a055eca943 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -24,6 +24,7 @@ import type { import { dateTimestampInSeconds, generatePropagationContext, isPlainObject, logger, uuid4 } from '@sentry/utils'; import { updateSession } from './session'; +import { assignBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; import { _getSpanForScope, _setSpanForScope } from './utils/spanOnScope'; /** @@ -412,7 +413,7 @@ class ScopeClass implements ScopeInterface { const mergedBreadcrumb = { timestamp: dateTimestampInSeconds(), - ...breadcrumb, + ...assignBreadcrumbLogLevel(breadcrumb), }; const breadcrumbs = this._breadcrumbs; diff --git a/packages/core/src/utils/breadcrumbsUtils.ts b/packages/core/src/utils/breadcrumbsUtils.ts new file mode 100644 index 000000000000..e09a3beaedb1 --- /dev/null +++ b/packages/core/src/utils/breadcrumbsUtils.ts @@ -0,0 +1,20 @@ +import type { Breadcrumb } from '@sentry/types'; + +/** + * Set a Fetch/XHR breadcrumb's log level based on the returned status code + * @param breadcrumb + */ +export function assignBreadcrumbLogLevel(breadcrumb: Breadcrumb): Breadcrumb { + const statusCode = breadcrumb?.data?.status_code; + if (typeof statusCode !== 'number') { + return breadcrumb; + } + + if (statusCode >= 400 && statusCode < 500) { + breadcrumb.level = 'warning'; + } else if (statusCode >= 500) { + breadcrumb.level = 'error'; + } + + return breadcrumb; +} From c141bd818bea56eb4527fb4a1cc19524e2a8af66 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 17 Sep 2024 21:19:48 -0400 Subject: [PATCH 2/9] chore(typo): Fix typo in `Scope.addBreadcrumb` Signed-off-by: Kaung Zin Hein --- packages/types/src/scope.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/types/src/scope.ts b/packages/types/src/scope.ts index aa51c69035f1..799f1717e106 100644 --- a/packages/types/src/scope.ts +++ b/packages/types/src/scope.ts @@ -189,8 +189,8 @@ export interface Scope { clear(): this; /** - * Sets the breadcrumbs in the scope - * @param breadcrumbs Breadcrumb + * Sets the breadcrumb in the scope + * @param breadcrumb Breadcrumb * @param maxBreadcrumbs number of max breadcrumbs to merged into event. */ addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this; From fbcc14093c05d30e73bd180178a5b77807c04970 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Tue, 17 Sep 2024 21:25:00 -0400 Subject: [PATCH 3/9] Remove extra optional chain Signed-off-by: Kaung Zin Hein --- packages/core/src/utils/breadcrumbsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/utils/breadcrumbsUtils.ts b/packages/core/src/utils/breadcrumbsUtils.ts index e09a3beaedb1..45802a1903af 100644 --- a/packages/core/src/utils/breadcrumbsUtils.ts +++ b/packages/core/src/utils/breadcrumbsUtils.ts @@ -5,7 +5,7 @@ import type { Breadcrumb } from '@sentry/types'; * @param breadcrumb */ export function assignBreadcrumbLogLevel(breadcrumb: Breadcrumb): Breadcrumb { - const statusCode = breadcrumb?.data?.status_code; + const statusCode = breadcrumb.data?.status_code; if (typeof statusCode !== 'number') { return breadcrumb; } From 80efec1cc10de9fb5c58ebfc20e62e52fbb57645 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Wed, 18 Sep 2024 10:17:20 -0400 Subject: [PATCH 4/9] test(core): Add unit test for the updated log level function Signed-off-by: Kaung Zin Hein --- packages/core/src/breadcrumbs.ts | 3 +-- packages/core/src/scope.ts | 3 +-- packages/core/src/utils/breadcrumbsUtils.ts | 25 ++++++++----------- .../test/lib/utils/breadcrumbsUtils.test.ts | 15 +++++++++++ 4 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 packages/core/test/lib/utils/breadcrumbsUtils.test.ts diff --git a/packages/core/src/breadcrumbs.ts b/packages/core/src/breadcrumbs.ts index f452fa8cfcbc..dd2d38110910 100644 --- a/packages/core/src/breadcrumbs.ts +++ b/packages/core/src/breadcrumbs.ts @@ -1,7 +1,6 @@ import type { Breadcrumb, BreadcrumbHint } from '@sentry/types'; import { consoleSandbox, dateTimestampInSeconds } from '@sentry/utils'; import { getClient, getIsolationScope } from './currentScopes'; -import { assignBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; /** * Default maximum number of breadcrumbs added to an event. Can be overwritten @@ -26,7 +25,7 @@ export function addBreadcrumb(breadcrumb: Breadcrumb, hint?: BreadcrumbHint): vo if (maxBreadcrumbs <= 0) return; const timestamp = dateTimestampInSeconds(); - const mergedBreadcrumb = { timestamp, ...assignBreadcrumbLogLevel(breadcrumb) }; + const mergedBreadcrumb = { timestamp, breadcrumb }; const finalBreadcrumb = beforeBreadcrumb ? (consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint)) as Breadcrumb | null) : mergedBreadcrumb; diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index 60a055eca943..c3b52c221fe3 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -24,7 +24,6 @@ import type { import { dateTimestampInSeconds, generatePropagationContext, isPlainObject, logger, uuid4 } from '@sentry/utils'; import { updateSession } from './session'; -import { assignBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; import { _getSpanForScope, _setSpanForScope } from './utils/spanOnScope'; /** @@ -413,7 +412,7 @@ class ScopeClass implements ScopeInterface { const mergedBreadcrumb = { timestamp: dateTimestampInSeconds(), - ...assignBreadcrumbLogLevel(breadcrumb), + breadcrumb, }; const breadcrumbs = this._breadcrumbs; diff --git a/packages/core/src/utils/breadcrumbsUtils.ts b/packages/core/src/utils/breadcrumbsUtils.ts index 45802a1903af..10df9558fe66 100644 --- a/packages/core/src/utils/breadcrumbsUtils.ts +++ b/packages/core/src/utils/breadcrumbsUtils.ts @@ -1,20 +1,17 @@ -import type { Breadcrumb } from '@sentry/types'; +import type { SeverityLevel } from '@sentry/types'; /** - * Set a Fetch/XHR breadcrumb's log level based on the returned status code - * @param breadcrumb + * Determine a breadcrumb's log level based on the response status code + * @param statusCode */ -export function assignBreadcrumbLogLevel(breadcrumb: Breadcrumb): Breadcrumb { - const statusCode = breadcrumb.data?.status_code; - if (typeof statusCode !== 'number') { - return breadcrumb; - } - - if (statusCode >= 400 && statusCode < 500) { - breadcrumb.level = 'warning'; +export function getBreadcrumbLogLevel(statusCode: number | undefined): SeverityLevel { + if (statusCode === undefined) { + return 'info'; + } else if (statusCode >= 400 && statusCode < 500) { + return 'warning'; } else if (statusCode >= 500) { - breadcrumb.level = 'error'; + return 'error'; + } else { + return 'info'; } - - return breadcrumb; } diff --git a/packages/core/test/lib/utils/breadcrumbsUtils.test.ts b/packages/core/test/lib/utils/breadcrumbsUtils.test.ts new file mode 100644 index 000000000000..172016d64f15 --- /dev/null +++ b/packages/core/test/lib/utils/breadcrumbsUtils.test.ts @@ -0,0 +1,15 @@ +import type { SeverityLevel } from '@sentry/types'; +import { getBreadcrumbLogLevel } from '../../../src/utils/breadcrumbsUtils'; + +describe('getBreadcrumbLogLevel()', () => { + it.each([ + ['warning', '4xx', 403], + ['error', '5xx', 500], + ['info', '3xx', 307], + ['info', '2xx', 200], + ['info', '1xx', 103], + ['info', 'undefined', undefined], + ] as [SeverityLevel, string, number | undefined][])('should return `%s` for %s', (output, _codeRange, input) => { + expect(getBreadcrumbLogLevel(input)).toBe(output); + }); +}); From 3100ead02ebfd0175bef99db2524363e485eb5a3 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Wed, 18 Sep 2024 10:36:50 -0400 Subject: [PATCH 5/9] fix(core): Apply breadcrumb log level function in packages where `addBreadcrumb` is called Signed-off-by: Kaung Zin Hein --- packages/browser/src/integrations/breadcrumbs.ts | 8 +++++++- packages/cloudflare/src/integrations/fetch.ts | 12 +++++++++++- packages/core/src/index.ts | 1 + packages/deno/src/integrations/breadcrumbs.ts | 5 ++++- packages/node/src/integrations/http.ts | 7 ++++++- packages/node/src/integrations/node-fetch.ts | 12 ++++++++++-- .../vercel-edge/src/integrations/wintercg-fetch.ts | 12 +++++++++++- 7 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index e3c1120fca57..43fa4e21da79 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -4,7 +4,7 @@ import { addHistoryInstrumentationHandler, addXhrInstrumentationHandler, } from '@sentry-internal/browser-utils'; -import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getBreadcrumbLogLevel, getClient } from '@sentry/core'; import type { Breadcrumb, Client, @@ -247,11 +247,14 @@ function _getXhrBreadcrumbHandler(client: Client): (handlerData: HandlerDataXhr) endTimestamp, }; + const level = getBreadcrumbLogLevel(status_code); + addBreadcrumb( { category: 'xhr', data, type: 'http', + level, }, hint, ); @@ -309,11 +312,14 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe startTimestamp, endTimestamp, }; + const level = getBreadcrumbLogLevel(data.status_code); + addBreadcrumb( { category: 'fetch', data, type: 'http', + level, }, hint, ); diff --git a/packages/cloudflare/src/integrations/fetch.ts b/packages/cloudflare/src/integrations/fetch.ts index 4781a71a896d..877adedb0ede 100644 --- a/packages/cloudflare/src/integrations/fetch.ts +++ b/packages/cloudflare/src/integrations/fetch.ts @@ -1,4 +1,11 @@ -import { addBreadcrumb, defineIntegration, getClient, instrumentFetchRequest, isSentryRequestUrl } from '@sentry/core'; +import { + addBreadcrumb, + defineIntegration, + getBreadcrumbLogLevel, + getClient, + instrumentFetchRequest, + isSentryRequestUrl, +} from '@sentry/core'; import type { Client, FetchBreadcrumbData, @@ -144,11 +151,14 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { startTimestamp, endTimestamp, }; + const level = getBreadcrumbLogLevel(data.status_code); + addBreadcrumb( { category: 'fetch', data, type: 'http', + level, }, hint, ); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 24cea1bea7ca..2b8dddc13086 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -84,6 +84,7 @@ export { parseSampleRate } from './utils/parseSampleRate'; export { applySdkMetadata } from './utils/sdkMetadata'; export { getTraceData } from './utils/traceData'; export { getTraceMetaTags } from './utils/meta'; +export { getBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; export { DEFAULT_ENVIRONMENT } from './constants'; export { addBreadcrumb } from './breadcrumbs'; export { functionToStringIntegration } from './integrations/functiontostring'; diff --git a/packages/deno/src/integrations/breadcrumbs.ts b/packages/deno/src/integrations/breadcrumbs.ts index 47953d4d7ce8..64edad50234c 100644 --- a/packages/deno/src/integrations/breadcrumbs.ts +++ b/packages/deno/src/integrations/breadcrumbs.ts @@ -1,4 +1,4 @@ -import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getBreadcrumbLogLevel, getClient } from '@sentry/core'; import type { Client, Event as SentryEvent, @@ -178,11 +178,14 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe startTimestamp, endTimestamp, }; + const level = getBreadcrumbLogLevel(data.status_code); + addBreadcrumb( { category: 'fetch', data, type: 'http', + level, }, hint, ); diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index d9e5e671b702..c62fda280e0e 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -6,6 +6,7 @@ import { addOpenTelemetryInstrumentation } from '@sentry/opentelemetry'; import { addBreadcrumb, defineIntegration, + getBreadcrumbLogLevel, getCapturedScopesOnSpan, getCurrentScope, getIsolationScope, @@ -229,14 +230,18 @@ function _addRequestBreadcrumb( } const data = getBreadcrumbData(request); + const statusCode = response.statusCode; + const level = getBreadcrumbLogLevel(statusCode); + addBreadcrumb( { category: 'http', data: { - status_code: response.statusCode, + status_code: statusCode, ...data, }, type: 'http', + level, }, { event: 'response', diff --git a/packages/node/src/integrations/node-fetch.ts b/packages/node/src/integrations/node-fetch.ts index 0726c2c63f9b..839fb6a5b356 100644 --- a/packages/node/src/integrations/node-fetch.ts +++ b/packages/node/src/integrations/node-fetch.ts @@ -1,6 +1,11 @@ import type { UndiciRequest, UndiciResponse } from '@opentelemetry/instrumentation-undici'; import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, addBreadcrumb, defineIntegration } from '@sentry/core'; +import { + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + addBreadcrumb, + defineIntegration, + getBreadcrumbLogLevel, +} from '@sentry/core'; import { addOpenTelemetryInstrumentation } from '@sentry/opentelemetry'; import type { IntegrationFn, SanitizedRequestData } from '@sentry/types'; import { getSanitizedUrlString, parseUrl } from '@sentry/utils'; @@ -56,15 +61,18 @@ export const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchInte /** Add a breadcrumb for outgoing requests. */ function addRequestBreadcrumb(request: UndiciRequest, response: UndiciResponse): void { const data = getBreadcrumbData(request); + const statusCode = response.statusCode; + const level = getBreadcrumbLogLevel(statusCode); addBreadcrumb( { category: 'http', data: { - status_code: response.statusCode, + status_code: statusCode, ...data, }, type: 'http', + level, }, { event: 'response', diff --git a/packages/vercel-edge/src/integrations/wintercg-fetch.ts b/packages/vercel-edge/src/integrations/wintercg-fetch.ts index 970e10958333..09e07282bc8e 100644 --- a/packages/vercel-edge/src/integrations/wintercg-fetch.ts +++ b/packages/vercel-edge/src/integrations/wintercg-fetch.ts @@ -1,4 +1,11 @@ -import { addBreadcrumb, defineIntegration, getClient, instrumentFetchRequest, isSentryRequestUrl } from '@sentry/core'; +import { + addBreadcrumb, + defineIntegration, + getBreadcrumbLogLevel, + getClient, + instrumentFetchRequest, + isSentryRequestUrl, +} from '@sentry/core'; import type { Client, FetchBreadcrumbData, @@ -150,11 +157,14 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { startTimestamp, endTimestamp, }; + const level = getBreadcrumbLogLevel(data.status_code); + addBreadcrumb( { category: 'fetch', data, type: 'http', + level, }, hint, ); From 7cea142d52967200f15666796432a772b970bab7 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Wed, 18 Sep 2024 11:39:12 -0400 Subject: [PATCH 6/9] fix(core): Revert to original `addBreadcrumb` code Signed-off-by: Kaung Zin Hein --- packages/core/src/breadcrumbs.ts | 2 +- packages/core/src/scope.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/breadcrumbs.ts b/packages/core/src/breadcrumbs.ts index dd2d38110910..1cfad5d08fea 100644 --- a/packages/core/src/breadcrumbs.ts +++ b/packages/core/src/breadcrumbs.ts @@ -25,7 +25,7 @@ export function addBreadcrumb(breadcrumb: Breadcrumb, hint?: BreadcrumbHint): vo if (maxBreadcrumbs <= 0) return; const timestamp = dateTimestampInSeconds(); - const mergedBreadcrumb = { timestamp, breadcrumb }; + const mergedBreadcrumb = { timestamp, ...breadcrumb }; const finalBreadcrumb = beforeBreadcrumb ? (consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint)) as Breadcrumb | null) : mergedBreadcrumb; diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index c3b52c221fe3..ff89c0d593a9 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -412,7 +412,7 @@ class ScopeClass implements ScopeInterface { const mergedBreadcrumb = { timestamp: dateTimestampInSeconds(), - breadcrumb, + ...breadcrumb, }; const breadcrumbs = this._breadcrumbs; From a71e07e98420de301dcb71a719a6419d56911af0 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Wed, 18 Sep 2024 12:37:29 -0400 Subject: [PATCH 7/9] test(browser): Add sample integration test for breadcrumb log level Signed-off-by: Kaung Zin Hein --- .../Breadcrumbs/fetch/get/test.ts | 1 + .../fetch/getWithRequestObj/test.ts | 1 + .../Breadcrumbs/fetch/post/test.ts | 1 + .../integrations/Breadcrumbs/xhr/get/test.ts | 59 +++++++++++++++++++ .../integrations/Breadcrumbs/xhr/post/test.ts | 1 + 5 files changed, 63 insertions(+) diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts index 9ecf29c31014..b3ae70f2c19c 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts @@ -33,5 +33,6 @@ sentryTest('captures Breadcrumb for basic GET request', async ({ getLocalTestUrl status_code: 200, url: 'http://sentry-test.io/foo', }, + level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts index 8d545ea6f566..2fdf54667e5d 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts @@ -33,5 +33,6 @@ sentryTest('captures Breadcrumb for basic GET request that uses request object', status_code: 200, url: 'http://sentry-test.io/foo', }, + level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts index fd27c71e6ad7..4e638265ea8d 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts @@ -33,5 +33,6 @@ sentryTest('captures Breadcrumb for POST request', async ({ getLocalTestUrl, pag status_code: 200, url: 'http://sentry-test.io/foo', }, + level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts index 9c4b14e89033..6f7686893e82 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts @@ -34,5 +34,64 @@ sentryTest('captures Breadcrumb for basic GET request', async ({ getLocalTestUrl status_code: 200, url: 'http://sentry-test.io/foo', }, + level: 'info', + }); +}); + +sentryTest('captures Breadcrumb for GET request with 4xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 404, + contentType: 'text/plain', + body: 'Not Found!', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'xhr', + type: 'http', + data: { + method: 'GET', + status_code: 404, + url: 'http://sentry-test.io/foo', + }, + level: 'warning', + }); +}); + +sentryTest('captures Breadcrumb for GET request with 5xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 500, + contentType: 'text/plain', + body: 'Internal Server Error', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'xhr', + type: 'http', + data: { + method: 'GET', + status_code: 500, + url: 'http://sentry-test.io/foo', + }, + level: 'error', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts index 985e7e316244..5fcb3140d3f0 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts @@ -33,5 +33,6 @@ sentryTest('captures Breadcrumb for POST request', async ({ getLocalTestUrl, pag status_code: 200, url: 'http://sentry-test.io/foo', }, + level: 'info', }); }); From bfa9cafdf1540cd37aff8e97ebc36c64cb76f483 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Sun, 22 Sep 2024 13:34:35 -0400 Subject: [PATCH 8/9] fix(core): Add log level only to 4xx/5xx codes Modify `getBreadcrumbLogLevel` to account only for 4xx or 5xx status. Tests updated to reflect the changes to `getBreadcrumbLogLevel` function. Signed-off-by: Kaung Zin Hein --- .../Breadcrumbs/fetch/get/test.ts | 1 - .../fetch/getWithRequestObj/test.ts | 1 - .../Breadcrumbs/fetch/post/test.ts | 1 - .../Breadcrumbs/fetch/statusCode/subject.js | 3 + .../Breadcrumbs/fetch/statusCode/test.ts | 71 +++++++++++++++++++ .../integrations/Breadcrumbs/xhr/get/test.ts | 59 --------------- .../integrations/Breadcrumbs/xhr/post/test.ts | 1 - .../Breadcrumbs/xhr/statusCode/subject.js | 10 +++ .../Breadcrumbs/xhr/statusCode/test.ts | 71 +++++++++++++++++++ .../browser/src/integrations/breadcrumbs.ts | 4 +- packages/cloudflare/src/integrations/fetch.ts | 2 +- packages/core/src/utils/breadcrumbsUtils.ts | 12 ++-- .../test/lib/utils/breadcrumbsUtils.test.ts | 17 +++-- packages/deno/src/integrations/breadcrumbs.ts | 2 +- packages/node/src/integrations/http.ts | 2 +- packages/node/src/integrations/node-fetch.ts | 2 +- .../src/integrations/wintercg-fetch.ts | 2 +- 17 files changed, 176 insertions(+), 85 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/test.ts diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts index b3ae70f2c19c..9ecf29c31014 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/test.ts @@ -33,6 +33,5 @@ sentryTest('captures Breadcrumb for basic GET request', async ({ getLocalTestUrl status_code: 200, url: 'http://sentry-test.io/foo', }, - level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts index 2fdf54667e5d..8d545ea6f566 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts @@ -33,6 +33,5 @@ sentryTest('captures Breadcrumb for basic GET request that uses request object', status_code: 200, url: 'http://sentry-test.io/foo', }, - level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts index 4e638265ea8d..fd27c71e6ad7 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/test.ts @@ -33,6 +33,5 @@ sentryTest('captures Breadcrumb for POST request', async ({ getLocalTestUrl, pag status_code: 200, url: 'http://sentry-test.io/foo', }, - level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/subject.js new file mode 100644 index 000000000000..1cbadc6e36e6 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/subject.js @@ -0,0 +1,3 @@ +fetch('http://sentry-test.io/foo').then(() => { + Sentry.captureException('test error'); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/test.ts new file mode 100644 index 000000000000..70cd868ccfe1 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/statusCode/test.ts @@ -0,0 +1,71 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('captures Breadcrumb with log level for 4xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 404, + contentType: 'text/plain', + body: 'Not Found!', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'fetch', + type: 'http', + data: { + method: 'GET', + status_code: 404, + url: 'http://sentry-test.io/foo', + }, + level: 'warning', + }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 500, + contentType: 'text/plain', + body: 'Internal Server Error', + }); + }); +}); + +sentryTest('captures Breadcrumb with log level for 5xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 500, + contentType: 'text/plain', + body: 'Internal Server Error', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'fetch', + type: 'http', + data: { + method: 'GET', + status_code: 500, + url: 'http://sentry-test.io/foo', + }, + level: 'error', + }); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts index 6f7686893e82..9c4b14e89033 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/get/test.ts @@ -34,64 +34,5 @@ sentryTest('captures Breadcrumb for basic GET request', async ({ getLocalTestUrl status_code: 200, url: 'http://sentry-test.io/foo', }, - level: 'info', - }); -}); - -sentryTest('captures Breadcrumb for GET request with 4xx response code', async ({ getLocalTestUrl, page }) => { - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.route('**/foo', async route => { - await route.fulfill({ - status: 404, - contentType: 'text/plain', - body: 'Not Found!', - }); - }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - - expect(eventData.exception?.values).toHaveLength(1); - - expect(eventData?.breadcrumbs?.length).toBe(1); - expect(eventData!.breadcrumbs![0]).toEqual({ - timestamp: expect.any(Number), - category: 'xhr', - type: 'http', - data: { - method: 'GET', - status_code: 404, - url: 'http://sentry-test.io/foo', - }, - level: 'warning', - }); -}); - -sentryTest('captures Breadcrumb for GET request with 5xx response code', async ({ getLocalTestUrl, page }) => { - const url = await getLocalTestUrl({ testDir: __dirname }); - - await page.route('**/foo', async route => { - await route.fulfill({ - status: 500, - contentType: 'text/plain', - body: 'Internal Server Error', - }); - }); - - const eventData = await getFirstSentryEnvelopeRequest(page, url); - - expect(eventData.exception?.values).toHaveLength(1); - - expect(eventData?.breadcrumbs?.length).toBe(1); - expect(eventData!.breadcrumbs![0]).toEqual({ - timestamp: expect.any(Number), - category: 'xhr', - type: 'http', - data: { - method: 'GET', - status_code: 500, - url: 'http://sentry-test.io/foo', - }, - level: 'error', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts index 5fcb3140d3f0..985e7e316244 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/post/test.ts @@ -33,6 +33,5 @@ sentryTest('captures Breadcrumb for POST request', async ({ getLocalTestUrl, pag status_code: 200, url: 'http://sentry-test.io/foo', }, - level: 'info', }); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/subject.js new file mode 100644 index 000000000000..8202bb03803b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/subject.js @@ -0,0 +1,10 @@ +const xhr = new XMLHttpRequest(); + +xhr.open('GET', 'http://sentry-test.io/foo'); +xhr.send(); + +xhr.addEventListener('readystatechange', function () { + if (xhr.readyState === 4) { + Sentry.captureException('test error'); + } +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/test.ts new file mode 100644 index 000000000000..eb7014df5890 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/xhr/statusCode/test.ts @@ -0,0 +1,71 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('captures Breadcrumb with log level for 4xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 404, + contentType: 'text/plain', + body: 'Not Found!', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'xhr', + type: 'http', + data: { + method: 'GET', + status_code: 404, + url: 'http://sentry-test.io/foo', + }, + level: 'warning', + }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 500, + contentType: 'text/plain', + body: 'Internal Server Error', + }); + }); +}); + +sentryTest('captures Breadcrumb with log level for 5xx response code', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', async route => { + await route.fulfill({ + status: 500, + contentType: 'text/plain', + body: 'Internal Server Error', + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'xhr', + type: 'http', + data: { + method: 'GET', + status_code: 500, + url: 'http://sentry-test.io/foo', + }, + level: 'error', + }); +}); diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 43fa4e21da79..14a49e8b3433 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -254,7 +254,7 @@ function _getXhrBreadcrumbHandler(client: Client): (handlerData: HandlerDataXhr) category: 'xhr', data, type: 'http', - level, + ...level, }, hint, ); @@ -319,7 +319,7 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe category: 'fetch', data, type: 'http', - level, + ...level, }, hint, ); diff --git a/packages/cloudflare/src/integrations/fetch.ts b/packages/cloudflare/src/integrations/fetch.ts index 877adedb0ede..3aa2d84d0556 100644 --- a/packages/cloudflare/src/integrations/fetch.ts +++ b/packages/cloudflare/src/integrations/fetch.ts @@ -158,7 +158,7 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { category: 'fetch', data, type: 'http', - level, + ...level, }, hint, ); diff --git a/packages/core/src/utils/breadcrumbsUtils.ts b/packages/core/src/utils/breadcrumbsUtils.ts index 10df9558fe66..a73f4dc23504 100644 --- a/packages/core/src/utils/breadcrumbsUtils.ts +++ b/packages/core/src/utils/breadcrumbsUtils.ts @@ -1,17 +1,17 @@ import type { SeverityLevel } from '@sentry/types'; /** - * Determine a breadcrumb's log level based on the response status code + * Determine a breadcrumb's log level (only `warning` or `error`) based on the response status code * @param statusCode */ -export function getBreadcrumbLogLevel(statusCode: number | undefined): SeverityLevel { +export function getBreadcrumbLogLevel(statusCode: number | undefined): { level?: SeverityLevel } { if (statusCode === undefined) { - return 'info'; + return {}; } else if (statusCode >= 400 && statusCode < 500) { - return 'warning'; + return { level: 'warning' }; } else if (statusCode >= 500) { - return 'error'; + return { level: 'error' }; } else { - return 'info'; + return {}; } } diff --git a/packages/core/test/lib/utils/breadcrumbsUtils.test.ts b/packages/core/test/lib/utils/breadcrumbsUtils.test.ts index 172016d64f15..c54e22e8ab98 100644 --- a/packages/core/test/lib/utils/breadcrumbsUtils.test.ts +++ b/packages/core/test/lib/utils/breadcrumbsUtils.test.ts @@ -1,15 +1,14 @@ -import type { SeverityLevel } from '@sentry/types'; import { getBreadcrumbLogLevel } from '../../../src/utils/breadcrumbsUtils'; describe('getBreadcrumbLogLevel()', () => { it.each([ - ['warning', '4xx', 403], - ['error', '5xx', 500], - ['info', '3xx', 307], - ['info', '2xx', 200], - ['info', '1xx', 103], - ['info', 'undefined', undefined], - ] as [SeverityLevel, string, number | undefined][])('should return `%s` for %s', (output, _codeRange, input) => { - expect(getBreadcrumbLogLevel(input)).toBe(output); + [{ level: 'warning' }, '4xx', 403], + [{ level: 'error' }, '5xx', 500], + [{}, '3xx', 307], + [{}, '2xx', 200], + [{}, '1xx', 103], + [{}, 'undefined', undefined], + ])('should return `%s` for %s', (output, _codeRange, input) => { + expect(getBreadcrumbLogLevel(input)).toEqual(output); }); }); diff --git a/packages/deno/src/integrations/breadcrumbs.ts b/packages/deno/src/integrations/breadcrumbs.ts index 64edad50234c..f6c599eb4b15 100644 --- a/packages/deno/src/integrations/breadcrumbs.ts +++ b/packages/deno/src/integrations/breadcrumbs.ts @@ -185,7 +185,7 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe category: 'fetch', data, type: 'http', - level, + ...level, }, hint, ); diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index c62fda280e0e..46b3a578da4f 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -241,7 +241,7 @@ function _addRequestBreadcrumb( ...data, }, type: 'http', - level, + ...level, }, { event: 'response', diff --git a/packages/node/src/integrations/node-fetch.ts b/packages/node/src/integrations/node-fetch.ts index 839fb6a5b356..517e99ed52af 100644 --- a/packages/node/src/integrations/node-fetch.ts +++ b/packages/node/src/integrations/node-fetch.ts @@ -72,7 +72,7 @@ function addRequestBreadcrumb(request: UndiciRequest, response: UndiciResponse): ...data, }, type: 'http', - level, + ...level, }, { event: 'response', diff --git a/packages/vercel-edge/src/integrations/wintercg-fetch.ts b/packages/vercel-edge/src/integrations/wintercg-fetch.ts index 09e07282bc8e..4ffa40bdf844 100644 --- a/packages/vercel-edge/src/integrations/wintercg-fetch.ts +++ b/packages/vercel-edge/src/integrations/wintercg-fetch.ts @@ -164,7 +164,7 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { category: 'fetch', data, type: 'http', - level, + ...level, }, hint, ); From e5e33ee428f429cae2436a46de488f7f68ee9a74 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 23 Sep 2024 11:05:10 +0000 Subject: [PATCH 9/9] Clean up --- .../browser/src/integrations/breadcrumbs.ts | 11 +++++----- packages/cloudflare/src/integrations/fetch.ts | 20 +++++++++---------- packages/core/src/index.ts | 1 - packages/core/src/utils/breadcrumbsUtils.ts | 17 ---------------- .../test/lib/utils/breadcrumbsUtils.test.ts | 14 ------------- packages/deno/src/integrations/breadcrumbs.ts | 7 ++++--- packages/node/src/integrations/http.ts | 12 +++++++---- packages/node/src/integrations/node-fetch.ts | 13 ++++-------- packages/types/src/scope.ts | 4 ++-- packages/utils/src/breadcrumb-log-level.ts | 17 ++++++++++++++++ packages/utils/src/index.ts | 1 + .../utils/test/breadcrumb-log-level.test.ts | 15 ++++++++++++++ .../src/integrations/wintercg-fetch.ts | 20 +++++++++---------- 13 files changed, 75 insertions(+), 77 deletions(-) delete mode 100644 packages/core/src/utils/breadcrumbsUtils.ts delete mode 100644 packages/core/test/lib/utils/breadcrumbsUtils.test.ts create mode 100644 packages/utils/src/breadcrumb-log-level.ts create mode 100644 packages/utils/test/breadcrumb-log-level.test.ts diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 14a49e8b3433..db30a48dda67 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -4,7 +4,7 @@ import { addHistoryInstrumentationHandler, addXhrInstrumentationHandler, } from '@sentry-internal/browser-utils'; -import { addBreadcrumb, defineIntegration, getBreadcrumbLogLevel, getClient } from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core'; import type { Breadcrumb, Client, @@ -23,6 +23,7 @@ import type { import { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, + getBreadcrumbLogLevelFromHttpStatusCode, getComponentName, getEventDescription, htmlTreeAsString, @@ -247,14 +248,14 @@ function _getXhrBreadcrumbHandler(client: Client): (handlerData: HandlerDataXhr) endTimestamp, }; - const level = getBreadcrumbLogLevel(status_code); + const level = getBreadcrumbLogLevelFromHttpStatusCode(status_code); addBreadcrumb( { category: 'xhr', data, type: 'http', - ...level, + level, }, hint, ); @@ -312,14 +313,14 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe startTimestamp, endTimestamp, }; - const level = getBreadcrumbLogLevel(data.status_code); + const level = getBreadcrumbLogLevelFromHttpStatusCode(data.status_code); addBreadcrumb( { category: 'fetch', data, type: 'http', - ...level, + level, }, hint, ); diff --git a/packages/cloudflare/src/integrations/fetch.ts b/packages/cloudflare/src/integrations/fetch.ts index 3aa2d84d0556..4bada212e7d5 100644 --- a/packages/cloudflare/src/integrations/fetch.ts +++ b/packages/cloudflare/src/integrations/fetch.ts @@ -1,11 +1,4 @@ -import { - addBreadcrumb, - defineIntegration, - getBreadcrumbLogLevel, - getClient, - instrumentFetchRequest, - isSentryRequestUrl, -} from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getClient, instrumentFetchRequest, isSentryRequestUrl } from '@sentry/core'; import type { Client, FetchBreadcrumbData, @@ -14,7 +7,12 @@ import type { IntegrationFn, Span, } from '@sentry/types'; -import { LRUMap, addFetchInstrumentationHandler, stringMatchesSomePattern } from '@sentry/utils'; +import { + LRUMap, + addFetchInstrumentationHandler, + getBreadcrumbLogLevelFromHttpStatusCode, + stringMatchesSomePattern, +} from '@sentry/utils'; const INTEGRATION_NAME = 'Fetch'; @@ -151,14 +149,14 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { startTimestamp, endTimestamp, }; - const level = getBreadcrumbLogLevel(data.status_code); + const level = getBreadcrumbLogLevelFromHttpStatusCode(data.status_code); addBreadcrumb( { category: 'fetch', data, type: 'http', - ...level, + level, }, hint, ); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2b8dddc13086..24cea1bea7ca 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -84,7 +84,6 @@ export { parseSampleRate } from './utils/parseSampleRate'; export { applySdkMetadata } from './utils/sdkMetadata'; export { getTraceData } from './utils/traceData'; export { getTraceMetaTags } from './utils/meta'; -export { getBreadcrumbLogLevel } from './utils/breadcrumbsUtils'; export { DEFAULT_ENVIRONMENT } from './constants'; export { addBreadcrumb } from './breadcrumbs'; export { functionToStringIntegration } from './integrations/functiontostring'; diff --git a/packages/core/src/utils/breadcrumbsUtils.ts b/packages/core/src/utils/breadcrumbsUtils.ts deleted file mode 100644 index a73f4dc23504..000000000000 --- a/packages/core/src/utils/breadcrumbsUtils.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { SeverityLevel } from '@sentry/types'; - -/** - * Determine a breadcrumb's log level (only `warning` or `error`) based on the response status code - * @param statusCode - */ -export function getBreadcrumbLogLevel(statusCode: number | undefined): { level?: SeverityLevel } { - if (statusCode === undefined) { - return {}; - } else if (statusCode >= 400 && statusCode < 500) { - return { level: 'warning' }; - } else if (statusCode >= 500) { - return { level: 'error' }; - } else { - return {}; - } -} diff --git a/packages/core/test/lib/utils/breadcrumbsUtils.test.ts b/packages/core/test/lib/utils/breadcrumbsUtils.test.ts deleted file mode 100644 index c54e22e8ab98..000000000000 --- a/packages/core/test/lib/utils/breadcrumbsUtils.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { getBreadcrumbLogLevel } from '../../../src/utils/breadcrumbsUtils'; - -describe('getBreadcrumbLogLevel()', () => { - it.each([ - [{ level: 'warning' }, '4xx', 403], - [{ level: 'error' }, '5xx', 500], - [{}, '3xx', 307], - [{}, '2xx', 200], - [{}, '1xx', 103], - [{}, 'undefined', undefined], - ])('should return `%s` for %s', (output, _codeRange, input) => { - expect(getBreadcrumbLogLevel(input)).toEqual(output); - }); -}); diff --git a/packages/deno/src/integrations/breadcrumbs.ts b/packages/deno/src/integrations/breadcrumbs.ts index f6c599eb4b15..6b945ebc37f5 100644 --- a/packages/deno/src/integrations/breadcrumbs.ts +++ b/packages/deno/src/integrations/breadcrumbs.ts @@ -1,4 +1,4 @@ -import { addBreadcrumb, defineIntegration, getBreadcrumbLogLevel, getClient } from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core'; import type { Client, Event as SentryEvent, @@ -11,6 +11,7 @@ import type { import { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, + getBreadcrumbLogLevelFromHttpStatusCode, getEventDescription, safeJoin, severityLevelFromString, @@ -178,14 +179,14 @@ function _getFetchBreadcrumbHandler(client: Client): (handlerData: HandlerDataFe startTimestamp, endTimestamp, }; - const level = getBreadcrumbLogLevel(data.status_code); + const level = getBreadcrumbLogLevelFromHttpStatusCode(data.status_code); addBreadcrumb( { category: 'fetch', data, type: 'http', - ...level, + level, }, hint, ); diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 46b3a578da4f..50904051bf78 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -6,7 +6,6 @@ import { addOpenTelemetryInstrumentation } from '@sentry/opentelemetry'; import { addBreadcrumb, defineIntegration, - getBreadcrumbLogLevel, getCapturedScopesOnSpan, getCurrentScope, getIsolationScope, @@ -15,7 +14,12 @@ import { import { getClient } from '@sentry/opentelemetry'; import type { IntegrationFn, SanitizedRequestData } from '@sentry/types'; -import { getSanitizedUrlString, parseUrl, stripUrlQueryAndFragment } from '@sentry/utils'; +import { + getBreadcrumbLogLevelFromHttpStatusCode, + getSanitizedUrlString, + parseUrl, + stripUrlQueryAndFragment, +} from '@sentry/utils'; import type { NodeClient } from '../sdk/client'; import { setIsolationScope } from '../sdk/scope'; import type { HTTPModuleRequestIncomingMessage } from '../transports/http-module'; @@ -231,7 +235,7 @@ function _addRequestBreadcrumb( const data = getBreadcrumbData(request); const statusCode = response.statusCode; - const level = getBreadcrumbLogLevel(statusCode); + const level = getBreadcrumbLogLevelFromHttpStatusCode(statusCode); addBreadcrumb( { @@ -241,7 +245,7 @@ function _addRequestBreadcrumb( ...data, }, type: 'http', - ...level, + level, }, { event: 'response', diff --git a/packages/node/src/integrations/node-fetch.ts b/packages/node/src/integrations/node-fetch.ts index 517e99ed52af..ee797b0587d7 100644 --- a/packages/node/src/integrations/node-fetch.ts +++ b/packages/node/src/integrations/node-fetch.ts @@ -1,14 +1,9 @@ import type { UndiciRequest, UndiciResponse } from '@opentelemetry/instrumentation-undici'; import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici'; -import { - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - addBreadcrumb, - defineIntegration, - getBreadcrumbLogLevel, -} from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, addBreadcrumb, defineIntegration } from '@sentry/core'; import { addOpenTelemetryInstrumentation } from '@sentry/opentelemetry'; import type { IntegrationFn, SanitizedRequestData } from '@sentry/types'; -import { getSanitizedUrlString, parseUrl } from '@sentry/utils'; +import { getBreadcrumbLogLevelFromHttpStatusCode, getSanitizedUrlString, parseUrl } from '@sentry/utils'; interface NodeFetchOptions { /** @@ -62,7 +57,7 @@ export const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchInte function addRequestBreadcrumb(request: UndiciRequest, response: UndiciResponse): void { const data = getBreadcrumbData(request); const statusCode = response.statusCode; - const level = getBreadcrumbLogLevel(statusCode); + const level = getBreadcrumbLogLevelFromHttpStatusCode(statusCode); addBreadcrumb( { @@ -72,7 +67,7 @@ function addRequestBreadcrumb(request: UndiciRequest, response: UndiciResponse): ...data, }, type: 'http', - ...level, + level, }, { event: 'response', diff --git a/packages/types/src/scope.ts b/packages/types/src/scope.ts index 799f1717e106..a4b91f4b5d96 100644 --- a/packages/types/src/scope.ts +++ b/packages/types/src/scope.ts @@ -189,7 +189,7 @@ export interface Scope { clear(): this; /** - * Sets the breadcrumb in the scope + * Adds a breadcrumb to the scope * @param breadcrumb Breadcrumb * @param maxBreadcrumbs number of max breadcrumbs to merged into event. */ @@ -201,7 +201,7 @@ export interface Scope { getLastBreadcrumb(): Breadcrumb | undefined; /** - * Clears all currently set Breadcrumbs. + * Clears all breadcrumbs from the scope. */ clearBreadcrumbs(): this; diff --git a/packages/utils/src/breadcrumb-log-level.ts b/packages/utils/src/breadcrumb-log-level.ts new file mode 100644 index 000000000000..a19d70e00412 --- /dev/null +++ b/packages/utils/src/breadcrumb-log-level.ts @@ -0,0 +1,17 @@ +import type { SeverityLevel } from '@sentry/types'; + +/** + * Determine a breadcrumb's log level (only `warning` or `error`) based on an HTTP status code. + */ +export function getBreadcrumbLogLevelFromHttpStatusCode(statusCode: number | undefined): SeverityLevel | undefined { + // NOTE: undefined defaults to 'info' in Sentry + if (statusCode === undefined) { + return undefined; + } else if (statusCode >= 400 && statusCode < 500) { + return 'warning'; + } else if (statusCode >= 500) { + return 'error'; + } else { + return undefined; + } +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 822d150dfde1..245751b3e72c 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,5 +1,6 @@ export * from './aggregate-errors'; export * from './array'; +export * from './breadcrumb-log-level'; export * from './browser'; export * from './dsn'; export * from './error'; diff --git a/packages/utils/test/breadcrumb-log-level.test.ts b/packages/utils/test/breadcrumb-log-level.test.ts new file mode 100644 index 000000000000..49792d2726bb --- /dev/null +++ b/packages/utils/test/breadcrumb-log-level.test.ts @@ -0,0 +1,15 @@ +import { getBreadcrumbLogLevelFromHttpStatusCode } from '../src/breadcrumb-log-level'; + +describe('getBreadcrumbLogLevelFromHttpStatusCode()', () => { + it.each([ + ['warning', '4xx', 403], + ['error', '5xx', 500], + [undefined, '3xx', 307], + [undefined, '2xx', 200], + [undefined, '1xx', 103], + [undefined, '0', 0], + [undefined, 'undefined', undefined], + ])('should return `%s` for %s', (output, _codeRange, input) => { + expect(getBreadcrumbLogLevelFromHttpStatusCode(input)).toEqual(output); + }); +}); diff --git a/packages/vercel-edge/src/integrations/wintercg-fetch.ts b/packages/vercel-edge/src/integrations/wintercg-fetch.ts index 4ffa40bdf844..4dd4bf399e4c 100644 --- a/packages/vercel-edge/src/integrations/wintercg-fetch.ts +++ b/packages/vercel-edge/src/integrations/wintercg-fetch.ts @@ -1,11 +1,4 @@ -import { - addBreadcrumb, - defineIntegration, - getBreadcrumbLogLevel, - getClient, - instrumentFetchRequest, - isSentryRequestUrl, -} from '@sentry/core'; +import { addBreadcrumb, defineIntegration, getClient, instrumentFetchRequest, isSentryRequestUrl } from '@sentry/core'; import type { Client, FetchBreadcrumbData, @@ -14,7 +7,12 @@ import type { IntegrationFn, Span, } from '@sentry/types'; -import { LRUMap, addFetchInstrumentationHandler, stringMatchesSomePattern } from '@sentry/utils'; +import { + LRUMap, + addFetchInstrumentationHandler, + getBreadcrumbLogLevelFromHttpStatusCode, + stringMatchesSomePattern, +} from '@sentry/utils'; const INTEGRATION_NAME = 'WinterCGFetch'; @@ -157,14 +155,14 @@ function createBreadcrumb(handlerData: HandlerDataFetch): void { startTimestamp, endTimestamp, }; - const level = getBreadcrumbLogLevel(data.status_code); + const level = getBreadcrumbLogLevelFromHttpStatusCode(data.status_code); addBreadcrumb( { category: 'fetch', data, type: 'http', - ...level, + level, }, hint, );