Skip to content

Commit b08c5ab

Browse files
committed
Version 1.1.2 - 12-21-2025
1 parent e2fd8bf commit b08c5ab

File tree

4 files changed

+208
-117
lines changed

4 files changed

+208
-117
lines changed

index.cjs

Lines changed: 95 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,95 @@
1-
const logger = require('@eliware/log');
2-
3-
/**
4-
* Registers process-level exception handlers for uncaught exceptions, unhandled rejections, warnings, and exit events.
5-
* @param {Object} options
6-
* @param {Object} [options.processObj=process] - The process object to attach handlers to.
7-
* @param {Object} [options.log=logger] - Logger for output.
8-
* @returns {Object} { removeHandlers } - Function to remove all registered handlers (for testability).
9-
*/
10-
const registerHandlers = ({
11-
processObj = process,
12-
log = logger
13-
} = {}) => {
14-
const handlers = {
15-
uncaughtException: (err) => log.error('Uncaught Exception', {
16-
name: err?.name,
17-
message: err?.message,
18-
stack: err?.stack,
19-
error: err
20-
}),
21-
unhandledRejection: (reason, promise) => log.error('Unhandled Rejection', {
22-
reason: reason instanceof Error ? {
23-
name: reason.name,
24-
message: reason.message,
25-
stack: reason.stack,
26-
error: reason
27-
} : reason,
28-
promise
29-
}),
30-
warning: (warning) => log.warn('Warning', {
31-
name: warning?.name,
32-
message: warning?.message,
33-
stack: warning?.stack,
34-
warning
35-
})
36-
};
37-
processObj.on('uncaughtException', handlers.uncaughtException);
38-
processObj.on('unhandledRejection', handlers.unhandledRejection);
39-
processObj.on('warning', handlers.warning);
40-
const removeHandlers = () => {
41-
processObj.off('uncaughtException', handlers.uncaughtException);
42-
processObj.off('unhandledRejection', handlers.unhandledRejection);
43-
processObj.off('warning', handlers.warning);
44-
};
45-
log.debug('Exception handlers registered');
46-
return { removeHandlers };
47-
};
48-
49-
module.exports = { registerHandlers };
50-
module.exports.default = registerHandlers;
1+
const logger = require('@eliware/log');
2+
3+
/**
4+
* Registers process-level exception handlers for uncaught exceptions, unhandled rejections, warnings, and exit events.
5+
* @param {Object} options
6+
* @param {Object} [options.processObj=process] - The process object to attach handlers to.
7+
* @param {Object} [options.log=logger] - Logger for output.
8+
* @returns {Object} { removeHandlers } - Function to remove all registered handlers (for testability).
9+
*/
10+
const registerHandlers = ({
11+
processObj = process,
12+
log = logger
13+
} = {}) => {
14+
// Safe serializer: shallowly serialize objects without invoking toJSON or other getters
15+
const safeSerialize = (obj) => {
16+
try {
17+
if (obj === null) return null;
18+
if (typeof obj !== 'object') return obj;
19+
const out = {};
20+
for (const k of Object.keys(obj)) {
21+
try {
22+
const v = obj[k];
23+
if (v === null) { out[k] = null; continue; }
24+
if (typeof v === 'object') {
25+
const info = { type: v.constructor && v.constructor.name ? v.constructor.name : 'Object' };
26+
try { if ('id' in v && (typeof v.id === 'string' || typeof v.id === 'number')) info.id = v.id; } catch (e) {}
27+
try { if ('name' in v && typeof v.name === 'string') info.name = v.name; } catch (e) {}
28+
out[k] = info;
29+
} else if (typeof v === 'function') {
30+
out[k] = `[Function: ${v.name || 'anonymous'}]`;
31+
} else {
32+
out[k] = v;
33+
}
34+
} catch (e) {
35+
out[k] = '[Unserializable]';
36+
}
37+
}
38+
return out;
39+
} catch (e) {
40+
try { return String(obj); } catch (ee) { return '[Unserializable]'; }
41+
}
42+
};
43+
44+
const handlers = {
45+
uncaughtException: (err) => {
46+
try {
47+
// Include raw error object for downstream consumers, but also provide safe fields
48+
log.error('Uncaught Exception', {
49+
name: err && err.name,
50+
message: err && err.message,
51+
stack: err && err.stack,
52+
error: err
53+
});
54+
} catch (e) {
55+
try { log.error('Uncaught Exception (logging failed)', { error: String(err) }); } catch (ee) { /* swallow */ }
56+
}
57+
},
58+
unhandledRejection: (reason, promise) => {
59+
try {
60+
if (reason instanceof Error) {
61+
return log.error('Unhandled Rejection', { reason: { name: reason.name, message: reason.message, stack: reason.stack, error: reason }, promise });
62+
}
63+
return log.error('Unhandled Rejection', { reason: safeSerialize(reason), promise: safeSerialize(promise) });
64+
} catch (e) {
65+
try { log.error('Unhandled Rejection (logging failed)', { reason: String(reason) }); } catch (ee) { /* swallow */ }
66+
}
67+
},
68+
warning: (warning) => {
69+
try {
70+
// include raw warning object while also exposing key fields
71+
log.warn('Warning', {
72+
name: warning && warning.name,
73+
message: warning && warning.message,
74+
stack: warning && warning.stack,
75+
warning
76+
});
77+
} catch (e) {
78+
try { log.warn('Warning (logging failed)', { warning: String(warning) }); } catch (ee) { /* swallow */ }
79+
}
80+
}
81+
};
82+
processObj.on('uncaughtException', handlers.uncaughtException);
83+
processObj.on('unhandledRejection', handlers.unhandledRejection);
84+
processObj.on('warning', handlers.warning);
85+
const removeHandlers = () => {
86+
processObj.off('uncaughtException', handlers.uncaughtException);
87+
processObj.off('unhandledRejection', handlers.unhandledRejection);
88+
processObj.off('warning', handlers.warning);
89+
};
90+
log.debug('Exception handlers registered');
91+
return { removeHandlers };
92+
};
93+
94+
module.exports = { registerHandlers };
95+
module.exports.default = registerHandlers;

index.mjs

Lines changed: 95 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,95 @@
1-
import logger from '@eliware/log';
2-
3-
/**
4-
* Registers process-level exception handlers for uncaught exceptions, unhandled rejections, warnings, and exit events.
5-
* @param {Object} options
6-
* @param {Object} [options.processObj=process] - The process object to attach handlers to.
7-
* @param {Object} [options.log=logger] - Logger for output.
8-
* @returns {Object} { removeHandlers } - Function to remove all registered handlers (for testability).
9-
*/
10-
export const registerHandlers = ({
11-
processObj = process,
12-
log = logger
13-
} = {}) => {
14-
const handlers = {
15-
uncaughtException: (err) => log.error('Uncaught Exception', {
16-
name: err?.name,
17-
message: err?.message,
18-
stack: err?.stack,
19-
error: err
20-
}),
21-
unhandledRejection: (reason, promise) => log.error('Unhandled Rejection', {
22-
reason: reason instanceof Error ? {
23-
name: reason.name,
24-
message: reason.message,
25-
stack: reason.stack,
26-
error: reason
27-
} : reason,
28-
promise
29-
}),
30-
warning: (warning) => log.warn('Warning', {
31-
name: warning?.name,
32-
message: warning?.message,
33-
stack: warning?.stack,
34-
warning
35-
})
36-
};
37-
processObj.on('uncaughtException', handlers.uncaughtException);
38-
processObj.on('unhandledRejection', handlers.unhandledRejection);
39-
processObj.on('warning', handlers.warning);
40-
const removeHandlers = () => {
41-
processObj.off('uncaughtException', handlers.uncaughtException);
42-
processObj.off('unhandledRejection', handlers.unhandledRejection);
43-
processObj.off('warning', handlers.warning);
44-
};
45-
log.debug('Exception handlers registered');
46-
return { removeHandlers };
47-
};
48-
49-
export default registerHandlers;
1+
import logger from '@eliware/log';
2+
3+
/**
4+
* Registers process-level exception handlers for uncaught exceptions, unhandled rejections, warnings, and exit events.
5+
* @param {Object} options
6+
* @param {Object} [options.processObj=process] - The process object to attach handlers to.
7+
* @param {Object} [options.log=logger] - Logger for output.
8+
* @returns {Object} { removeHandlers } - Function to remove all registered handlers (for testability).
9+
*/
10+
export const registerHandlers = ({
11+
processObj = process,
12+
log = logger
13+
} = {}) => {
14+
// Safe serializer: shallowly serialize objects without invoking toJSON or other getters
15+
const safeSerialize = (obj) => {
16+
try {
17+
if (obj === null) return null;
18+
if (typeof obj !== 'object') return obj;
19+
const out = {};
20+
for (const k of Object.keys(obj)) {
21+
try {
22+
const v = obj[k];
23+
if (v === null) { out[k] = null; continue; }
24+
if (typeof v === 'object') {
25+
const info = { type: v.constructor && v.constructor.name ? v.constructor.name : 'Object' };
26+
try { if ('id' in v && (typeof v.id === 'string' || typeof v.id === 'number')) info.id = v.id; } catch (e) {}
27+
try { if ('name' in v && typeof v.name === 'string') info.name = v.name; } catch (e) {}
28+
out[k] = info;
29+
} else if (typeof v === 'function') {
30+
out[k] = `[Function: ${v.name || 'anonymous'}]`;
31+
} else {
32+
out[k] = v;
33+
}
34+
} catch (e) {
35+
out[k] = '[Unserializable]';
36+
}
37+
}
38+
return out;
39+
} catch (e) {
40+
try { return String(obj); } catch (ee) { return '[Unserializable]'; }
41+
}
42+
};
43+
44+
const handlers = {
45+
uncaughtException: (err) => {
46+
try {
47+
// Include raw error object for downstream consumers, but also provide safe fields
48+
log.error('Uncaught Exception', {
49+
name: err?.name,
50+
message: err?.message,
51+
stack: err?.stack,
52+
error: err
53+
});
54+
} catch (e) {
55+
try { log.error('Uncaught Exception (logging failed)', { error: String(err) }); } catch (ee) { /* swallow */ }
56+
}
57+
},
58+
unhandledRejection: (reason, promise) => {
59+
try {
60+
if (reason instanceof Error) {
61+
return log.error('Unhandled Rejection', { reason: { name: reason.name, message: reason.message, stack: reason.stack, error: reason }, promise });
62+
}
63+
return log.error('Unhandled Rejection', { reason: safeSerialize(reason), promise: safeSerialize(promise) });
64+
} catch (e) {
65+
try { log.error('Unhandled Rejection (logging failed)', { reason: String(reason) }); } catch (ee) { /* swallow */ }
66+
}
67+
},
68+
warning: (warning) => {
69+
try {
70+
// include raw warning object while also exposing key fields
71+
log.warn('Warning', {
72+
name: warning?.name,
73+
message: warning?.message,
74+
stack: warning?.stack,
75+
warning
76+
});
77+
} catch (e) {
78+
try { log.warn('Warning (logging failed)', { warning: String(warning) }); } catch (ee) { /* swallow */ }
79+
}
80+
}
81+
};
82+
83+
processObj.on('uncaughtException', handlers.uncaughtException);
84+
processObj.on('unhandledRejection', handlers.unhandledRejection);
85+
processObj.on('warning', handlers.warning);
86+
const removeHandlers = () => {
87+
processObj.off('uncaughtException', handlers.uncaughtException);
88+
processObj.off('unhandledRejection', handlers.unhandledRejection);
89+
processObj.off('warning', handlers.warning);
90+
};
91+
log.debug('Exception handlers registered');
92+
return { removeHandlers };
93+
};
94+
95+
export default registerHandlers;

package-lock.json

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@eliware/errors",
33
"type": "module",
4-
"version": "1.1.1",
4+
"version": "1.1.2",
55
"description": "A generic handler for catching uncaught errors, warnings, and rejections.",
66
"main": "index.cjs",
77
"module": "index.mjs",

0 commit comments

Comments
 (0)