diff --git a/.size-limit.js b/.size-limit.js index 6e73c9234c09..45324236f6ac 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -93,7 +93,7 @@ module.exports = [ path: 'packages/browser/build/npm/esm/index.js', import: createImport('init', 'feedbackIntegration'), gzip: true, - limit: '41 KB', + limit: '42 KB', }, { name: '@sentry/browser (incl. sendFeedback)', diff --git a/packages/core/src/baseclient.ts b/packages/core/src/baseclient.ts index c394a0d77a95..727fec079b55 100644 --- a/packages/core/src/baseclient.ts +++ b/packages/core/src/baseclient.ts @@ -49,6 +49,7 @@ import { isParameterizedString, isPlainObject, isPrimitive, isThenable } from '. import { consoleSandbox, logger } from './utils-hoist/logger'; import { checkOrSetAlreadyCaught, uuid4 } from './utils-hoist/misc'; import { SyncPromise, rejectedSyncPromise, resolvedSyncPromise } from './utils-hoist/syncpromise'; +import { getPossibleEventMessages } from './utils/eventUtils'; import { parseSampleRate } from './utils/parseSampleRate'; import { prepareEvent } from './utils/prepareEvent'; import { showSpanDropWarning } from './utils/spanUtils'; @@ -713,6 +714,10 @@ export abstract class BaseClient implements Client { * @param scope */ protected _captureEvent(event: Event, hint: EventHint = {}, scope?: Scope): PromiseLike { + if (DEBUG_BUILD && isErrorEvent(event)) { + logger.log(`Captured error event \`${getPossibleEventMessages(event)[0] || ''}\``); + } + return this._processEvent(event, hint, scope).then( finalEvent => { return finalEvent.event_id; diff --git a/packages/core/src/integrations/inboundfilters.ts b/packages/core/src/integrations/inboundfilters.ts index 9d9f803a69f5..223490bf9528 100644 --- a/packages/core/src/integrations/inboundfilters.ts +++ b/packages/core/src/integrations/inboundfilters.ts @@ -5,6 +5,7 @@ import { defineIntegration } from '../integration'; import { logger } from '../utils-hoist/logger'; import { getEventDescription } from '../utils-hoist/misc'; import { stringMatchesSomePattern } from '../utils-hoist/string'; +import { getPossibleEventMessages } from '../utils/eventUtils'; // "Script error." is hard coded into browsers for errors that it can't read. // this is the result of a script being pulled in from an external domain and CORS. @@ -117,7 +118,7 @@ function _isIgnoredError(event: Event, ignoreErrors?: Array): b return false; } - return _getPossibleEventMessages(event).some(message => stringMatchesSomePattern(message, ignoreErrors)); + return getPossibleEventMessages(event).some(message => stringMatchesSomePattern(message, ignoreErrors)); } function _isIgnoredTransaction(event: Event, ignoreTransactions?: Array): boolean { @@ -147,33 +148,6 @@ function _isAllowedUrl(event: Event, allowUrls?: Array): boolea return !url ? true : stringMatchesSomePattern(url, allowUrls); } -function _getPossibleEventMessages(event: Event): string[] { - const possibleMessages: string[] = []; - - if (event.message) { - possibleMessages.push(event.message); - } - - let lastException; - try { - // @ts-expect-error Try catching to save bundle size - lastException = event.exception.values[event.exception.values.length - 1]; - } catch (e) { - // try catching to save bundle size checking existence of variables - } - - if (lastException) { - if (lastException.value) { - possibleMessages.push(lastException.value); - if (lastException.type) { - possibleMessages.push(`${lastException.type}: ${lastException.value}`); - } - } - } - - return possibleMessages; -} - function _isSentryError(event: Event): boolean { try { // @ts-expect-error can't be a sentry error if undefined diff --git a/packages/core/src/utils/eventUtils.ts b/packages/core/src/utils/eventUtils.ts new file mode 100644 index 000000000000..3d1fa16eca58 --- /dev/null +++ b/packages/core/src/utils/eventUtils.ts @@ -0,0 +1,27 @@ +import type { Event } from '../types-hoist'; + +/** + * Get a list of possible event messages from a Sentry event. + */ +export function getPossibleEventMessages(event: Event): string[] { + const possibleMessages: string[] = []; + + if (event.message) { + possibleMessages.push(event.message); + } + + try { + // @ts-expect-error Try catching to save bundle size + const lastException = event.exception.values[event.exception.values.length - 1]; + if (lastException && lastException.value) { + possibleMessages.push(lastException.value); + if (lastException.type) { + possibleMessages.push(`${lastException.type}: ${lastException.value}`); + } + } + } catch (e) { + // ignore errors here + } + + return possibleMessages; +} diff --git a/packages/core/test/lib/baseclient.test.ts b/packages/core/test/lib/baseclient.test.ts index d66ef05881d0..0432235a17a5 100644 --- a/packages/core/test/lib/baseclient.test.ts +++ b/packages/core/test/lib/baseclient.test.ts @@ -366,6 +366,22 @@ describe('BaseClient', () => { // `captureException` should bail right away this second time around and not get as far as calling this again expect(clientEventFromException).toHaveBeenCalledTimes(1); }); + + test('captures logger message', () => { + const logSpy = jest.spyOn(loggerModule.logger, 'log').mockImplementation(() => undefined); + + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + + client.captureException(new Error('test error here')); + client.captureException({}); + + expect(logSpy).toHaveBeenCalledTimes(2); + expect(logSpy).toBeCalledWith('Captured error event `test error here`'); + expect(logSpy).toBeCalledWith('Captured error event ``'); + + logSpy.mockRestore(); + }); }); describe('captureMessage', () => { @@ -442,6 +458,20 @@ describe('BaseClient', () => { }), ); }); + + test('captures logger message', () => { + const logSpy = jest.spyOn(loggerModule.logger, 'log').mockImplementation(() => undefined); + + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + + client.captureMessage('test error here'); + + expect(logSpy).toHaveBeenCalledTimes(1); + expect(logSpy).toBeCalledWith('Captured error event `test error here`'); + + logSpy.mockRestore(); + }); }); describe('captureEvent() / prepareEvent()', () => { @@ -1658,6 +1688,22 @@ describe('BaseClient', () => { message: 'hello', }); }); + + test('captures logger message', () => { + const logSpy = jest.spyOn(loggerModule.logger, 'log').mockImplementation(() => undefined); + + const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); + const client = new TestClient(options); + + client.captureEvent({ message: 'hello' }); + // transactions are ignored and not logged + client.captureEvent({ type: 'transaction', message: 'hello 2' }); + + expect(logSpy).toHaveBeenCalledTimes(1); + expect(logSpy).toBeCalledWith('Captured error event `hello`'); + + logSpy.mockRestore(); + }); }); describe('integrations', () => {