Skip to content

Commit 7b81cf0

Browse files
kamilogorekHazAT
authored andcommitted
feat: CaptureConsole integration (getsentry#1980)
1 parent 7f43a33 commit 7b81cf0

File tree

6 files changed

+106
-13
lines changed

6 files changed

+106
-13
lines changed

packages/browser/src/integrations/breadcrumbs.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ export class Breadcrumbs implements Integration {
7777
if (!('console' in global)) {
7878
return;
7979
}
80-
['debug', 'info', 'warn', 'error', 'log'].forEach(function(level: string): void {
80+
const levels = ['log', 'info', 'warn', 'error', 'debug', 'assert'];
81+
levels.forEach(function(level: string): void {
8182
if (!(level in global.console)) {
8283
return;
8384
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { EventProcessor, Hub, Integration, Severity } from '@sentry/types';
2+
import { getGlobalObject } from '@sentry/utils/misc';
3+
import { fill, normalize } from '@sentry/utils/object';
4+
import { safeJoin } from '@sentry/utils/string';
5+
6+
const global = getGlobalObject<Window | NodeJS.Global>();
7+
8+
/** Send Console API calls as Sentry Events */
9+
export class CaptureConsole implements Integration {
10+
/**
11+
* @inheritDoc
12+
*/
13+
public name: string = CaptureConsole.id;
14+
15+
/**
16+
* @inheritDoc
17+
*/
18+
public static id: string = 'CaptureConsole';
19+
20+
/**
21+
* @inheritDoc
22+
*/
23+
private readonly _levels: string[] = ['log', 'info', 'warn', 'error', 'debug', 'assert'];
24+
25+
/**
26+
* @inheritDoc
27+
*/
28+
public constructor(options: { levels?: string[] } = {}) {
29+
if (options.levels) {
30+
this._levels = options.levels;
31+
}
32+
}
33+
34+
/**
35+
* @inheritDoc
36+
*/
37+
public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
38+
if (!('console' in global)) {
39+
return;
40+
}
41+
42+
this._levels.forEach(function(level: string): void {
43+
if (!(level in global.console)) {
44+
return;
45+
}
46+
47+
fill(global.console, level, function(originalConsoleLevel: () => any): any {
48+
// tslint:disable-next-line:only-arrow-functions
49+
return function(...args: any[]): any {
50+
const hub = getCurrentHub();
51+
52+
if (hub.getIntegration(CaptureConsole)) {
53+
hub.withScope(scope => {
54+
scope.setLevel(Severity.fromString(level));
55+
scope.setExtra('arguments', normalize(args, 3));
56+
scope.addEventProcessor(event => {
57+
event.logger = 'console';
58+
if (event.sdk) {
59+
event.sdk = {
60+
...event.sdk,
61+
integrations: [...(event.sdk.integrations || []), 'console'],
62+
};
63+
}
64+
return event;
65+
});
66+
67+
let message = safeJoin(args, ' ');
68+
if (level === 'assert') {
69+
if (args[0] === false) {
70+
message = `Assertion failed: ${safeJoin(args.slice(1), ' ') || 'console.assert'}`;
71+
scope.setExtra('arguments', normalize(args.slice(1), 3));
72+
hub.captureMessage(message);
73+
}
74+
} else {
75+
hub.captureMessage(message);
76+
}
77+
});
78+
}
79+
80+
// this fails for some browsers. :(
81+
if (originalConsoleLevel) {
82+
Function.prototype.apply.call(originalConsoleLevel, global.console, args);
83+
}
84+
};
85+
});
86+
});
87+
}
88+
}

packages/integrations/src/debug.ts

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Event, EventHint, EventProcessor, Hub, Integration } from '@sentry/types';
2+
import { consoleSandbox } from '@sentry/utils/misc';
23

34
/** JSDoc */
45
interface DebugOptions {
@@ -45,17 +46,19 @@ export class Debug implements Integration {
4546
debugger;
4647
}
4748

48-
if (self._options.stringify) {
49-
console.log(JSON.stringify(event, null, 2));
50-
if (hint) {
51-
console.log(JSON.stringify(hint, null, 2));
49+
consoleSandbox(() => {
50+
if (self._options.stringify) {
51+
console.log(JSON.stringify(event, null, 2));
52+
if (hint) {
53+
console.log(JSON.stringify(hint, null, 2));
54+
}
55+
} else {
56+
console.log(event);
57+
if (hint) {
58+
console.log(hint);
59+
}
5260
}
53-
} else {
54-
console.log(event);
55-
if (hint) {
56-
console.log(hint);
57-
}
58-
}
61+
});
5962
}
6063
return event;
6164
});

packages/integrations/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { Angular } from './angular';
2+
export { CaptureConsole } from './captureconsole';
23
export { Debug } from './debug';
34
export { Dedupe } from './dedupe';
45
export { Ember } from './ember';

packages/utils/src/misc.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ interface ExtensibleConsole extends Console {
238238
/** JSDoc */
239239
export function consoleSandbox(callback: () => any): any {
240240
const global = getGlobalObject<Window>();
241-
const levels = ['debug', 'info', 'warn', 'error', 'log'];
241+
const levels = ['debug', 'info', 'warn', 'error', 'log', 'assert'];
242242

243243
if (!('console' in global)) {
244244
return callback();

packages/utils/src/object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Memo } from './memo';
1313
*/
1414

1515
export function fill(source: { [key: string]: any }, name: string, replacement: (...args: any[]) => any): void {
16-
if (!(name in source) || (source[name] as WrappedFunction).__sentry__) {
16+
if (!(name in source)) {
1717
return;
1818
}
1919

0 commit comments

Comments
 (0)