Skip to content

Commit 0c9a73f

Browse files
committed
fix
1 parent ca73ec9 commit 0c9a73f

File tree

2 files changed

+85
-62
lines changed

2 files changed

+85
-62
lines changed

src/addons/consoleCatcher.ts

Lines changed: 78 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,96 @@
22
* @file Module for intercepting console logs with stack trace capture
33
*/
44

5-
import type { ConsoleLogEvent } from '@hawk.so/types/build/src/base/event/addons/javascript';
5+
import type { ConsoleLogEvent } from '@hawk.so/types';
66

7-
const MAX_LOGS = 20;
8-
const consoleOutput: ConsoleLogEvent[] = [];
7+
const createConsoleCatcher = () => {
8+
const MAX_LOGS = 20;
9+
const consoleOutput: ConsoleLogEvent[] = [];
10+
let isInitialized = false;
911

10-
let isInitialized = false;
11-
12-
/**
13-
* Initializes the console catcher by overriding console methods
14-
* to capture logs with stack traces.
15-
*/
16-
export function initConsoleCatcher(): void {
17-
if (isInitialized) {
18-
return;
12+
const addToConsoleOutput = (logEvent: ConsoleLogEvent) => {
13+
if (consoleOutput.length >= MAX_LOGS) {
14+
consoleOutput.shift();
15+
}
16+
consoleOutput.push(logEvent);
1917
};
2018

21-
isInitialized = true;
22-
const consoleMethods = ['log', 'warn', 'error', 'info', 'debug'];
19+
const createConsoleEventFromError = (
20+
event: ErrorEvent | PromiseRejectionEvent
21+
): ConsoleLogEvent => {
22+
if (event instanceof ErrorEvent) {
23+
return {
24+
method: 'error',
25+
timestamp: new Date(),
26+
type: event.error?.name || 'Error',
27+
message: event.error?.message || event.message,
28+
stack: event.error?.stack || '',
29+
fileLine: event.filename
30+
? `${event.filename}:${event.lineno}:${event.colno}`
31+
: '',
32+
};
33+
}
2334

24-
consoleMethods.forEach((method) => {
25-
if (typeof window.console[method] !== 'function') {
26-
return;
35+
return {
36+
method: 'error',
37+
timestamp: new Date(),
38+
type: 'UnhandledRejection',
39+
message: event.reason?.message || String(event.reason),
40+
stack: event.reason?.stack || '',
41+
fileLine: '',
2742
};
43+
};
2844

29-
const oldFunction = window.console[method].bind(window.console);
30-
31-
window.console[method] = function (...args): void {
32-
if (consoleOutput.length >= MAX_LOGS) {
33-
consoleOutput.shift();
45+
return {
46+
initConsoleCatcher(): void {
47+
if (isInitialized) {
48+
return;
3449
}
3550

36-
const stack = new Error().stack?.split('\n').slice(2).join('\n') || '';
51+
isInitialized = true;
52+
const consoleMethods = ['log', 'warn', 'error', 'info', 'debug'];
3753

38-
const logEvent: ConsoleLogEvent = {
39-
method,
40-
timestamp: new Date(),
41-
type: method,
42-
message: args
43-
.map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg))).join(' '),
44-
stack,
45-
fileLine: stack.split('\n')[0]?.trim(),
46-
};
54+
consoleMethods.forEach((method) => {
55+
if (typeof window.console[method] !== 'function') {
56+
return;
57+
}
4758

48-
consoleOutput.push(logEvent);
49-
oldFunction(...args);
50-
};
51-
});
59+
const oldFunction = window.console[method].bind(window.console);
5260

53-
window.addEventListener('error', function (event) {
54-
if (consoleOutput.length >= MAX_LOGS) {
55-
consoleOutput.shift();
56-
}
61+
window.console[method] = function (...args): void {
62+
const stack =
63+
new Error().stack?.split('\n').slice(2).join('\n') || '';
5764

58-
const logEvent: ConsoleLogEvent = {
59-
method: 'error',
60-
timestamp: new Date(),
61-
type: event.error?.name || 'Error',
62-
message: event.error?.message || event.message,
63-
stack: event.error?.stack || '',
64-
fileLine: event.filename
65-
? `${event.filename}:${event.lineno}:${event.colno}`
66-
: '',
67-
};
65+
const logEvent: ConsoleLogEvent = {
66+
method,
67+
timestamp: new Date(),
68+
type: method,
69+
message: args
70+
.map((arg) =>
71+
typeof arg === 'string' ? arg : JSON.stringify(arg)
72+
)
73+
.join(' '),
74+
stack,
75+
fileLine: stack.split('\n')[0]?.trim(),
76+
};
6877

69-
consoleOutput.push(logEvent);
70-
});
71-
}
78+
addToConsoleOutput(logEvent);
79+
oldFunction(...args);
80+
};
81+
});
82+
},
7283

73-
/**
74-
* Returns the stack of captured console logs.
75-
*
76-
* @returns {ConsoleLogEvent[]} Array of logged console events.
77-
*/
78-
export function getConsoleLogStack(): ConsoleLogEvent[] {
79-
return [ ...consoleOutput ];
80-
}
84+
addErrorEvent(event: ErrorEvent | PromiseRejectionEvent): void {
85+
const logEvent = createConsoleEventFromError(event);
86+
addToConsoleOutput(logEvent);
87+
},
88+
89+
getConsoleLogStack(): ConsoleLogEvent[] {
90+
return [...consoleOutput];
91+
},
92+
};
93+
};
94+
95+
const consoleCatcher = createConsoleCatcher();
96+
export const { initConsoleCatcher, getConsoleLogStack, addErrorEvent } =
97+
consoleCatcher;

src/catcher.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { JavaScriptCatcherIntegrations } from './types/integrations';
1616
import { EventRejectedError } from './errors';
1717
import type { HawkJavaScriptEvent } from './types';
1818
import { isErrorProcessed, markErrorAsProcessed } from './utils/event';
19-
import { getConsoleLogStack, initConsoleCatcher } from './addons/consoleCatcher';
19+
import { addErrorEvent, getConsoleLogStack, initConsoleCatcher } from './addons/consoleCatcher';
2020

2121
/**
2222
* Allow to use global VERSION, that will be overwritten by Webpack
@@ -228,6 +228,12 @@ export default class Catcher {
228228
* @param {ErrorEvent|PromiseRejectionEvent} event — (!) both for Error and Promise Rejection
229229
*/
230230
private async handleEvent(event: ErrorEvent | PromiseRejectionEvent): Promise<void> {
231+
/**
232+
* Add error to console logs
233+
*/
234+
235+
addErrorEvent(event);
236+
231237
/**
232238
* Promise rejection reason is recommended to be an Error, but it can be a string:
233239
* - Promise.reject(new Error('Reason message')) ——— recommended

0 commit comments

Comments
 (0)