Skip to content

Commit de9b23a

Browse files
authored
feat: Generate hint if not provided in the Hub calls (getsentry#2142)
1 parent ad219fd commit de9b23a

File tree

12 files changed

+78
-15
lines changed

12 files changed

+78
-15
lines changed

packages/browser/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ let windowIntegrations = {};
4949

5050
// This block is needed to add compatibility with the integrations packages when used with a CDN
5151
// tslint:disable: no-unsafe-any
52-
const _window = getGlobalObject<Window>() as any;
52+
const _window = getGlobalObject<Window>();
5353
if (_window.Sentry && _window.Sentry.Integrations) {
5454
windowIntegrations = _window.Sentry.Integrations;
5555
}

packages/browser/src/sdk.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export function init(options: BrowserOptions = {}): void {
7878
options.defaultIntegrations = defaultIntegrations;
7979
}
8080
if (options.release === undefined) {
81-
const window = getGlobalObject<Window>() as any;
81+
const window = getGlobalObject<Window>();
8282
// This supports the variable that sentry-webpack-plugin injects
8383
if (window.SENTRY_RELEASE && window.SENTRY_RELEASE.id) {
8484
options.release = window.SENTRY_RELEASE.id;

packages/browser/test/index.test.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,16 @@ describe('SentryBrowser', () => {
167167
});
168168
});
169169

170-
171170
describe('SentryBrowser initialization', () => {
172171
it('should use window.SENTRY_RELEASE to set release on initialization if available', () => {
173172
global.SENTRY_RELEASE = { id: 'foobar' };
174173
init({ dsn });
175174
expect(global.__SENTRY__.hub._stack[0].client.getOptions().release).to.equal('foobar');
176-
// Manually tear down global set. Is there a nicer way to do this?
177-
global.SENTRY_RELEASE = undefined;
175+
delete global.SENTRY_RELEASE;
178176
});
179177
it('should have initialization proceed as normal if window.SENTRY_RELEASE is not set', () => {
180178
// This is mostly a happy-path test to ensure that the initialization doesn't throw an error.
181179
init({ dsn });
182180
expect(global.__SENTRY__.hub._stack[0].client.getOptions().release).to.be.undefined;
183181
});
184-
})
182+
});

packages/hub/src/hub.ts

+40-2
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,27 @@ export class Hub implements HubInterface {
158158
*/
159159
public captureException(exception: any, hint?: EventHint): string {
160160
const eventId = (this._lastEventId = uuid4());
161+
let finalHint = hint;
162+
163+
// If there's no explicit hint provided, mimick the same thing that would happen
164+
// in the minimal itself to create a consistent behavior.
165+
// We don't do this in the client, as it's the lowest level API, and doing this,
166+
// would prevent user from having full control over direct calls.
167+
if (!hint) {
168+
let syntheticException: Error;
169+
try {
170+
throw new Error('Sentry syntheticException');
171+
} catch (exception) {
172+
syntheticException = exception as Error;
173+
}
174+
finalHint = {
175+
originalException: exception,
176+
syntheticException,
177+
};
178+
}
179+
161180
this._invokeClient('captureException', exception, {
162-
...hint,
181+
...finalHint,
163182
event_id: eventId,
164183
});
165184
return eventId;
@@ -170,8 +189,27 @@ export class Hub implements HubInterface {
170189
*/
171190
public captureMessage(message: string, level?: Severity, hint?: EventHint): string {
172191
const eventId = (this._lastEventId = uuid4());
192+
let finalHint = hint;
193+
194+
// If there's no explicit hint provided, mimick the same thing that would happen
195+
// in the minimal itself to create a consistent behavior.
196+
// We don't do this in the client, as it's the lowest level API, and doing this,
197+
// would prevent user from having full control over direct calls.
198+
if (!hint) {
199+
let syntheticException: Error;
200+
try {
201+
throw new Error(message);
202+
} catch (exception) {
203+
syntheticException = exception as Error;
204+
}
205+
finalHint = {
206+
originalException: message,
207+
syntheticException,
208+
};
209+
}
210+
173211
this._invokeClient('captureMessage', message, level, {
174-
...hint,
212+
...finalHint,
175213
event_id: eventId,
176214
});
177215
return eventId;

packages/hub/test/hub.test.ts

+19
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,25 @@ describe('Hub', () => {
212212
expect(eventId).toBe(hub.lastEventId());
213213
});
214214

215+
test('captureException should generate hint if not provided in the call', () => {
216+
const hub = new Hub();
217+
const spy = jest.spyOn(hub as any, '_invokeClient');
218+
const ex = new Error('foo');
219+
hub.captureException(ex);
220+
expect(spy.mock.calls[0][2].originalException).toBe(ex);
221+
expect(spy.mock.calls[0][2].syntheticException).toBeInstanceOf(Error);
222+
expect(spy.mock.calls[0][2].syntheticException.message).toBe('Sentry syntheticException');
223+
});
224+
225+
test('captureMessage should generate hint if not provided in the call', () => {
226+
const hub = new Hub();
227+
const spy = jest.spyOn(hub as any, '_invokeClient');
228+
hub.captureMessage('foo');
229+
expect(spy.mock.calls[0][3].originalException).toBe('foo');
230+
expect(spy.mock.calls[0][3].syntheticException).toBeInstanceOf(Error);
231+
expect(spy.mock.calls[0][3].syntheticException.message).toBe('foo');
232+
});
233+
215234
test('run', () => {
216235
const currentHub = getCurrentHub();
217236
const myScope = new Scope();

packages/integrations/src/extraerrordata.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class ExtraErrorData implements Integration {
4444
return event;
4545
}
4646

47-
const errorData = this._extractErrorData(hint.originalException);
47+
const errorData = this._extractErrorData(hint.originalException as ExtendedError);
4848

4949
if (errorData) {
5050
let extra = {

packages/node/src/sdk.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export function init(options: NodeOptions = {}): void {
8686
}
8787

8888
if (options.release === undefined) {
89-
const global = getGlobalObject<Window>() as any;
89+
const global = getGlobalObject<Window>();
9090
// Prefer env var over global
9191
if (process.env.SENTRY_RELEASE) {
9292
options.release = process.env.SENTRY_RELEASE;

packages/node/test/index.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,4 @@ describe('SentryNode initialization', () => {
252252
init({ dsn });
253253
expect(global.__SENTRY__.hub._stack[0].client.getOptions().release).toBeUndefined();
254254
});
255-
})
255+
});

packages/types/src/event.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ export type EventType = 'none';
4242
export interface EventHint {
4343
event_id?: string;
4444
syntheticException?: Error | null;
45-
originalException?: Error | null;
45+
originalException?: Error | string | null;
4646
data?: any;
4747
}

packages/types/src/options.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export interface Options {
6666
/** Sets the distribution for all events */
6767
dist?: string;
6868

69-
/**
69+
/**
7070
* The maximum number of breadcrumbs sent with events. Defaults to 30.
7171
* Values over 100 will be ignored and 100 used instead.
7272
*/

packages/utils/src/misc.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import { Event, Mechanism, WrappedFunction } from '@sentry/types';
1+
import { Event, Integration, Mechanism, WrappedFunction } from '@sentry/types';
22

33
/** Internal */
44
interface SentryGlobal {
5+
Sentry?: {
6+
Integrations?: Integration[];
7+
};
8+
SENTRY_ENVIRONMENT?: string;
9+
SENTRY_DSN?: string;
10+
SENTRY_RELEASE?: {
11+
id?: string;
12+
};
513
__SENTRY__: {
614
globalEventProcessors: any;
715
hub: any;

packages/utils/src/polyfill.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const setPrototypeOf =
2-
Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties);
2+
Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties); // tslint:disable-line:no-unbound-method
33

44
/**
55
* setPrototypeOf polyfill using __proto__

0 commit comments

Comments
 (0)