How to capture the errors in node.js using uncaughtException - node.js

In my application i want to create own module to capture my application error using uncaughtException.If i create uncaughtException in same module means its capturing errors but if i create that uncaughtException in separate module.Then call that module means its not capturing erros.Can anyone help me to fix this issue.
module1.js
var errorModule=require('./module2');
var err = new Error('Something went terribly wrong');
errorModule.captureError(err);
module2.js
module.exports.captureError=function(err){
process.on('uncaughtException', function(err) {
console.log(err);
});
}

Try this:
// module1.js
var errorModule=require('./module2');
errorModule.captureErrors();
throw Error('Something went terribly wrong');
// module2.js
module.exports.captureErrors = function() {
process.on('uncaughtException', function(err) {
console.log('an error occurred', err);
});
};
A few things to notice:
process.on('uncaughtException', ...) installs an event handler to catch uncaught exceptions; your code tries to pass an error to it, but that seems to defeat what you're writing ('to capture my application error using uncaughtException');
Uncaught exceptions are errors which are thrown (throw Error(...));
If you want the code in your module1 to work, module2 needs to look like this:
module.exports.captureError = function(err) {
console.log(err);
};
But that has nothing to do with uncaughtException.

Related

Catch fails on connection to Mongo

the answer to this question: How to get node to exit when mongo connect fails contains async/wait code for a connection
however, my code (running on node v11.5.0 and mongodb v3.1.13) is failing to catch:
(async function() {
let db;
try {
db = await MongoClient.connect(uri, { useNewUrlParser: true });
console.log("RETURN", db);
} catch (err) {
console.log('EXITING');
process.exit(1);
}
}());
to prove the point I intentionally give a uri without credentials:
mongodb://undefined#cluster0-shard-00-00-z4j9e.azure.mongodb.net:27017,cluster0-shard-00-01-z4j9e.azure.mongodb.net:27017,cluster0-shard-00-02-z4j9e.azure.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true
and what I get is output like this:
/Users/ekkis/dev/mongo/node_modules/mongodb/lib/topologies/replset.js:346
throw err;
^
MongoError: password must be a string
at passwordDigest (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/auth/scram.js:63:43)
at ScramSHA1.ScramSHA.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/auth/scram.js:175:25)
at authenticate (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:232:17)
at authenticateLiveConnections (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:819:7)
at /Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:864:5
at waitForLogout (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:855:34)
at Pool.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:862:3)
at Server.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/server.js:931:20)
at auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/replset.js:1474:19)
at ReplSet.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/replset.js:1492:5)
so if the error had been caught, the console should have displayed the word 'EXITING', but does not. additionally, I contend an exception was thrown because otherwise the returned value would have been printed, which it was not
how can this be? what do I need to do to get it to work?
* Appendix I *
In fact, the promises version of this exhibits the same odd behaviour, it doesn't catch:
MongoClient
.connect(uri, { useNewUrlParser: true })
.then(dbc => {
console.log('SUCCESS');
})
.catch(err => {
console.log('EXITING');
process.exit(1);
});
and yes, I tested the callback version, which also suffers the same malady. Incidentally, passing an empty string for the uri works well. I don't get it
* Appendix II *
In fact, the problem seems to be particular to the credentials passed i.e. if I pass:
mongodb://x:y#cluster0-shard-[...]
I catch a "MongoError: authentication fail" as expected. passing:
mongodb://#cluster0-shard-[...]
interestingly returns a connection but credentials missing a ":" fail in this odd way, so:
mongodb://ekkis#cluster0-shard-[...]
fails to catch
Looks to me like it's a bug with however MongoClient is setting up its connections. You won't be able to use try & catch to handle asynchronously thrown errors within MongoClient code.
const {MongoClient} = require("mongodb");
process.on("uncaughtException", (err) => {
console.log("process err", err);
process.exit(1)
})
async function run () {
let db;
try {
// connection url will throw because password isn't provided
db = await MongoClient.connect("mongodb://myUsername:#localhost", { useNewUrlParser: true });
} catch (err) {
console.log('Exiting from thrown error', err);
process.exit(1);
}
}
run();
Here's a simplified example of what's happening -- the error will end up "uncaught" and caught by the uncaughtException handler
process.on("uncaughtException", (err) => console.log("uncaught", err));
try {
setTimeout(() => {
throw new Error("asynchronously thrown error");
})
} catch (err) {
console.log("Error will not be caught here")
}
When I was using mongo version 3.6.1, it was not an issue and i was able to handle the thrown exception using catch. But after a few days on another project this type of error occurred and was showing as the error thrown from
%project_folder%/node_modules/mongodb/lib/utils.js:668
(Don't mind about the slash in the path string.)
The mongodb version this time is 3.6.3. Upon checking the code in that file at the mentioned line I found the below piece of code. where the caught error is again being thrown.
fn(function(err, res) {
if (err != null) {
try {
callback(err);
} catch (error) {
return process.nextTick(() => {
throw error;
});
}
return;
}
callback(err, res);
});
I changed the throw error to console.error(error) and the problem got resolved. But still you need to be caught somewhere in our code where connect function is called.
I think this is because the above piece of code is checking for the presence of error and passing it to the callback function and then again throwing the same error again. I suppose it is the MongoDB driver developer community's responsibility to resolve this issue.

How to handle node.js errors properly - the standart way

For about developer errors that are made by mistake or undefined or something else that can crash the whole app:
Should I use this:
var domain = require('domain');
var d = domain.create();
d.on('error', function(err) {
console.error(err);
});
d.run(function() {
if (someom.sadjaslkd.asdasd=="yes") console.log("Yes");
// run more other things in the safe area
});
Purposely someom.sadjaslkd.asdasd is undefined.
OR should I use this:
try {
if (someom.sadjaslkd.asdasd=="yes") console.log("Yes");
// run more other things in the safe area
} catch(err) {
// handle the error safely
}
For about operation errors that are made not by mistake but due to client's faults:
Should I use this:
if (somethingWorng) res.status(400).json({status: "400", error: "Some custom error message to the user"});
OR maybe I should pass the error like this:
if (somethingWorng) throw "Some custom error message to the user";
OR maybe
if (somethingWorng) throw new Error("Some custom error message to the user");
Really there tons of ways to make this work. Is there a quick easy, readable, best practice?

node js uncaughtException sends empty object in callback

I have set up an uncaughtException event listener in node js:
process.on('uncaughtException', function (err) {
console.log('uncaughtException: ');
console.log(err);
process.exit(1);
});
To test it I tried the following. At one time:
callNonExistantFunction();
And at another:
throw new Error('test error');
In both cases, the exceptions were caught, but the value of the err parameter in the callback function was an empty object: {}. Is there any way to get the details of the error? I'm working on a Windows machine if it matters.
Thanks.

Domains not properly catching errors while testing nodeJS in mocha

When running tests that utilize domains for error handling, Mocha still appears to be throwing an error even if a domain handler inside a library should have caught the error. If I execute the code outside of Mocha, it functions correctly leading me to believe the problem is Mocha.
Example:
foo.js
module.exports = function(done) {
var domain = require("domain");
var d = domain.create();
d.on("error", function() {
done();
});
d.run(function() {
throw new Error("foo");
});
}
test.js - Error thrown inside foo.js is not being caught by the domain.
describe("test", function() {
it("should succeed", function(done) {
var foo = require("./foo.js");
foo(function() {
console.log("done");
done();
});
});
});
result : error thrown
script.js - error is being properly caught by the domain and bubbled up.
var foo = require("./foo.js");
foo(function() {
console.log("done");
});
result : done
As you can see above, if I node straight to script.js it functions as desired, the error is caught by the domain handler and the code continues. If I run the same block of code inside a Mocha test, the error halts the test and a failure is given. I believe this is because the error is being sent on an uncaughtException handler, or something like it. The other complication is that it works properly in Mocha, if I have a process.nextTick() around the function call, leading me to believe that Mocha is only unable to handle synchronous errors, but works just fine with async errors.
There is some talk of this problem here: https://groups.google.com/forum/#!msg/nodejs/n-W9BSfxCjI/SElI1DJ_6u0J and https://github.com/joyent/node/issues/4375 .
The confusion I have is that all of this discussion seems to state the problem has been resolved months ago. Anyone know of either a simple work-around for the issue, or a why I'm not seeing a bug fixed which other people seem to believe is fixed at this point in time.
I am running node v0.10.18 and Mocha 1.13.0 on CentOS 6.3 Vagrant VirtualBox on Windows 7.
Found the problem. NodeJS domains catch synchronous errors but the event continues to bubble to a try/catch. If you wrap a domain.run() in a try/catch then the domain error handler AND the catch will be executed.
Thus, it seems the best practice is to use process.nextTick inside all domain.run(). This is shown in the docs example, but isn't expressed as explicitly as I would prefer.
Example:
d.run(function() {
process.nextTick(function() {
// do stuff
});
});
In this case, the flaw is not in Mocha.
Proof of NodeJS domains not catching synchronous errors in try/catch: https://gist.github.com/owenallenaz/7141699
nodejs domains do definitely catch synchronous errors
See this simple test case
var domain = require("domain");
var d = domain.create();
d.on("error", function() {
console.log("domain caught");
});
d.run(function() {
throw new Error("foo");
});
// result: domain caught
EDIT: Since writing this answer I have written a blog post describing what is going on with domains and try catch and whether you can use domains as a wholesale replacement for try catch. It summarises most of what has been discussed here.
http://www.lighthouselogic.com/node-domains-as-a-replacement-for-try-catch/
ORIGINAL ANSWER:
Actually there is a problem with Mocha.
I wrote the following test function:
function error(callback){
var d = domain.create().on('error', function(err){
console.log("Caught Error in Domain Handler")
return callback(err);
});
d.enter();
throw new Error("TestError");
d.exit();
}
Then I wrote a simple test without mocha:
error(function(err){
if(err)
{
console.log("Error was returned");
}else
{
console.log("Error was not returned")
}
})
The output I received was:
Caught Error in Domain Handler
Error was returned
When I tested using Mocha:
describe('Domain Tests', function(){
it('Should return an error when testing', function(done){
error(function(err){
if(err)
{
console.log("Error was returned");
}else
{
console.log("Error was not returned")
}
return done();
})
});
});
I received the following output:
․
0 passing (4ms)
1 failing
1) Domain Tests Should return an error when testing:
Error: TestError
at error (/Users/bensudbury/Documents/node_projects/testMochaDomains/test.js:9:11)
at Context.<anonymous> (/Users/bensudbury/Documents/node_projects/testMochaDomains/testMocha.js:6:3)
at Test.Runnable.run (/usr/local/share/npm/lib/node_modules/mocha/lib/runnable.js:194:15)
at Runner.runTest (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:358:10)
at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:404:12
at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:284:14)
at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:293:7
at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:237:23)
at Object._onImmediate (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:261:5)
at processImmediate [as _immediateCallback] (timers.js:330:15)
As you can see: the domain error handler was short circuited.
This problem seems to be related to the following issues:
https://github.com/visionmedia/mocha/issues/513
While the Node issue has been closed, the issue in mocha is still open.
The workaround that was suggested at: https://gist.github.com/mcollina/4443963 didn't resolve the issue in this case.
I dug through the code of Mocha and found that the problem occurs because mocha wraps the tests in a try catch block. This means that the exception is caught and never sent to the uncaughtException or _fatalException handler depending upon the version of node that you are using.
Your workaround is good, but nodejs domains do definitely catch synchronous errors so I wouldn't change your code but instead change your test. Your new test should look like:
describe("test", function() {
it("should succeed", function(done) {
process.nextTick(function(){
var foo = require("./foo.js");
foo(function() {
console.log("done");
done();
});
})
});
});
I haven't tested this code, but similar code for my example works properly:
it('Should return an error when testing', function(done){
process.nextTick(function(){
error(function(err){
if(err)
{
console.log("Error was returned");
}else
{
console.log("Error was not returned")
}
return done();
});
})
});
I have added a comment to the end of the issue in Mocha to see if it can be resolved:
https://github.com/visionmedia/mocha/issues/513

Node.js doesn't display entire error message on uncaughtException, is it possible?

In node.js if you catch uncaughtExceptions, like so:
process.on('uncaughtException', function (error) {
console.log(error);
});
The error message displayed doesn't contain all the information that you receive if you don't catch the error and just let the process crash. When you let the process crash it includes what line caused the error. Is there any way to get the full error message including the line that caused the error so we can log this data using uncaughtException.
Try error.stack
process.on('uncaughtException', function (error) {
console.log(error.stack);
});
Try:
process.on('uncaughtException', function (error) {
console.dir(error);
});

Resources