diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index a302e5a14c34..d10b9dea08d6 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -24,6 +24,7 @@ import { isPlainObject } from './utils-hoist/is'; import { logger } from './utils-hoist/logger'; import { uuid4 } from './utils-hoist/misc'; import { generateTraceId } from './utils-hoist/propagationContext'; +import { truncate } from './utils-hoist/string'; import { dateTimestampInSeconds } from './utils-hoist/time'; import { merge } from './utils/merge'; import { _getSpanForScope, _setSpanForScope } from './utils/spanOnScope'; @@ -474,9 +475,11 @@ export class Scope { return this; } - const mergedBreadcrumb = { + const mergedBreadcrumb: Breadcrumb = { timestamp: dateTimestampInSeconds(), ...breadcrumb, + // Breadcrumb messages can theoretically be infinitely large and they're held in memory so we truncate them not to leak (too much) memory + message: breadcrumb.message ? truncate(breadcrumb.message, 2048) : breadcrumb.message, }; this._breadcrumbs.push(mergedBreadcrumb); diff --git a/packages/core/test/lib/scope.test.ts b/packages/core/test/lib/scope.test.ts index 4b27eff42824..87dcf9315ba9 100644 --- a/packages/core/test/lib/scope.test.ts +++ b/packages/core/test/lib/scope.test.ts @@ -186,6 +186,12 @@ describe('Scope', () => { expect(scope['_breadcrumbs']).toHaveLength(111); }); + test('addBreadcrumb will truncate the stored messages', () => { + const scope = new Scope(); + scope.addBreadcrumb({ message: 'A'.repeat(10_000) }); + expect(scope['_breadcrumbs'][0]?.message).toBe(`${'A'.repeat(2048)}...`); + }); + test('setLevel', () => { const scope = new Scope(); scope.setLevel('fatal'); diff --git a/packages/node/src/integrations/console.ts b/packages/node/src/integrations/console.ts index 5e5e6ac414d9..d1bb0463551e 100644 --- a/packages/node/src/integrations/console.ts +++ b/packages/node/src/integrations/console.ts @@ -5,7 +5,6 @@ import { defineIntegration, getClient, severityLevelFromString, - truncate, } from '@sentry/core'; const INTEGRATION_NAME = 'Console'; @@ -26,7 +25,7 @@ export const consoleIntegration = defineIntegration(() => { { category: 'console', level: severityLevelFromString(level), - message: truncate(util.format.apply(undefined, args), 2048), // 2KB + message: util.format.apply(undefined, args), }, { input: [...args], diff --git a/packages/node/test/integration/console.test.ts b/packages/node/test/integration/console.test.ts index 401dffd34819..691ccd4397ee 100644 --- a/packages/node/test/integration/console.test.ts +++ b/packages/node/test/integration/console.test.ts @@ -36,26 +36,4 @@ describe('Console integration', () => { }, ); }); - - it('should truncate breadcrumbs with more than 2 KB message size', () => { - consoleIntegration().setup?.(getClient() as NodeClient); - - const longMsg = 'A'.repeat(10_000); - - // eslint-disable-next-line no-console - console.log(longMsg); - - expect(addBreadcrumbSpy).toHaveBeenCalledTimes(1); - expect(addBreadcrumbSpy).toHaveBeenCalledWith( - { - category: 'console', - level: 'log', - message: `${'A'.repeat(2048)}...`, - }, - { - input: [longMsg], - level: 'log', - }, - ); - }); });