JS: How to track errors where there are many functions calls - javascript

Every function create new Error Object. So how I can get the preivous errors?
For example this is my code:
function main(callback) {
a(function(err) {
if (err) {
callback(new Error('cannot run main function..'));
return
}
})
}
function a(callback) {
b(function(err) {
if (err) {
callback(new Error('cannot run b function'));
return
}
})
}
function b(callback) {
if (1 == 2) callback(new Error('Error in b function'))
}
When I run this, I get only the last error ("cannot run main function') but I want to get all the previous errors. Do you have any best practive for that?
What I am doing is this:
if(err){
err=new Error('cannot run this function.\r' + err.message)
}
I am asking, of you know about any other library or better way for doing that. Something that extend the Error object...
Something like:
err.push(new Error('...'))

There is no "standard" way of doing something like this in Node.js yet. There are various libraries that do what you're describing. The best method I have found is to create a custom error object that extends the default JS Error object, and then define additional methods to it for your purposes. I wrote the x-error library that does just this, you can either use it and extend it (see bottom of README for how to extend it), or just take a look at its code (which is straightforward) and roll your own custom error object implementation.
Note: x-error has a debug method that is similar to what you're looking for.

Related

How can I customize exception formatting in jest in order to pretty-print my Error subclasses?

Writing tests in node.js, I would like to hook into jest to allow custom formatting of unhandled exceptions. I want to do that to pretty-print subclasses of Error that I throw in the code under test. Currently I only see the message property of the base Error get printed on test failure, because for reasons outside my control the subclasses are defined like this:
class SomeCustomError extends Error {
constructor(custom, stuff, message) {
super(message);
this._custom = custom;
this._stuff = stuff;
}
}
For example, I imagine defining toString methods on certain exceptions, and then configuring a jest custom error handler, which would call error.toString() and then print the return value (or a custom formatter, which would return the return value):
toString(): {
return `${this._custom} ${this._stuff} ${this._message}`
}
then maybe something like (in jest.config.js):
module.exports = {
...
unhandledErrorFormatterHook: (error) => `A jest test raised an unhandled exception: ${error.toString()}`,
...
}
How can I do that for every test? Rather than decorating every test case using a higher-order function directly in my test code, I'd prefer to use built-in jest features to do this if possible.
This could be achieved with a custom Reporter.
The catch with a custom reporter is the original Error is serialized into a plain object. Any non enumerable properties of the error are removed like the type, stack, message and name so it might involve some duck typing to detect when a SomeCustomError has occurred.
For any tests with a status of failed, a failureDetails array will be populated containing the serialized error object.
Any of the Reporter interface functions that receive a TestResult will be able to access the failureDetails array directly. Otherwise in an AggregatedResult via:
aggregate_result.testResults[].testResults[].failureDetails[]
There is also the failureMessages property of a TestResult that contains a similar array but of the stringified errors, which does include the name, message and stack information.
MyCustomReporter.js
function logTestFailureDetails(test_result){
if (test_result.status !== 'failed') return
console.log('Failed test:', test_result.fullName)
for (const err of test_result.failureDetails) {
// err will have the properties, like `_custom` and `_stuff`.
console.log('failureDetails', err)
}
}
class MyCustomReporter {
// After each test
onTestCaseResult(test, test_result, aggregate_result){
console.log('MyCustomReporter onTestCaseResult:')
logTestFailureDetails(test_result)
}
// Summary at the end
onRunComplete(contexts, results) {
console.log('MyCustomReporter onRunComplete:')
for (const aggregate_result of results.testResults) {
aggregate_result.testResults.forEach(logTestFailureDetails)
}
}
}
module.exports = MyCustomReporter
Jest package.json config
{
"jest": {
"reporters": [
"<rootDir>/MyCustomReporter.js"
]
}
}
It would be worth setting well defined codes on the the custom errors so they can be detected easily. Maybe even the name if you don't mind the error name becoming enumerable elsewhere.
class CustomError extends Error {
constructor(message){
super(message)
this.code = 'CNX'
this.name = this.constructor.name
}
}
It might also be possible to extend the jest DefaultReporter and friends to produce the required output. The failure message appears to be generated in the core code though, so it might take some string manipulation in the reporters to get you there.

Intercepting and interracting with a custom Error object in javascript

I am using a custom javascript modulue which has it's own Error objects. I would like to intercept those custom Error objects and take the appropriate path in my try{} catch{} block, distinguishing them from Javascript's built in Error objects such as ReferenceError, TypeError etc.
So a bit like this.
try {
// Some code that might produce a traditional javascript error
// or one of the errors raised by the module I am using.
}catch (error){
if(error instanceof ExchangeError){
// Handle this in a way.
}else{
// Probably one of the built in Javascript errors,
// So do this other thing.
}
}
So, in the example above, ExchangeError is a custom error belonging to that specific module, however, I am not able to run the instanceof on my error, despite the fact that when I do error.constructor.name I get ExchangeError.
My javascript scope simply does not know about that ExchangeError. So the question is, how can I intercept those kind of Error objects? I'm sure I can do it with string matching, but just wanted to check if there is a more elegant way.
One thing I tried, I have my own errors module, that has some custom errors in there, I tried to mimic the module's Error object:
class ExchangeError extends Error {
constructor (message) {
super (message);
this.constructor = ExchangeError;
this.__proto__ = ExchangeError.prototype;
this.message = message;
}
}
and import that through my errors module, but that did not work obviously.
By actually implementing my own ExchangeError I actually was doing something really really bad, I was blinding the instanceof check with my own ExchangeError, whereas the ExchangeError instance that was coming from the module, was NOT an instance of my own ExchangeError. That is why my if check was falling silent.
The solution is simply doing this:
const { ExchangeError } = require ('ccxt/js/base/errors');
Importing the error from within the module. Now the instanceof look up is working. I did not know that one can import bits and pieces from a module like that.
Thanks to #FrankerZ for pointing that out.

Writing thrown errors to a file in Javascript

Is there a way to add a default behavior in javascript to the throw event.
Like I am trying to add to a file whenever an error is thrown :
Example :
if (tables.length === 0) {
throw new Error("NO_TABLES_RETRIEVED");
}
I want to write to file first and then throw the error. I know I can add a function and just before throwing I can call that function but just to know more is there something like to add a default behavior with throw?
Error is different from Exception in Javascript w.r.t NodeJS. An error is any instance of the Error class. Errors may be constructed and then passed directly to another function or thrown. When you throw an error, it becomes an exception.2 Here's an example of using an error as an exception:
throw new Error('something bad happened');
but you can just as well create an Error without throwing it:
callback(new Error('something bad happened'));
Since you mentioned in the comment that you don't want to require the error handler file in all the files of the app. You can also make use of NodeJS EventEmitter module or use a error handler middleware
I think your best bet is to use a custom throw. I actually always do it, to be able to write
_throw("MyErrorMessage")
So I would do something like that:
//Should use something like dot-env with the path to your errors
require('dotenv').config()
//I'm just gonna fake it to make it work on your machine:
process.env.error_file_path = './myErrors.txt'
//throwLib.js
const util = require('util')
const fs = require('fs')
const writeFile = util.promisify(fs.appendFile)
_throw = (stringError) => {
writeFile(process.env.error_file_path, "Error : " + stringError + "\n").then(err => {
if (err)
console.log(err)
throw new Error(stringError)
}
)
}
//import this in your files.
//myFile.js
//someStuff
_throw('someMessage1')
_throw('someMessage2')
_throw('someMessage3')
You can create your own custom error and do some logic in the constructor.
function MyError(){
//do some logic herer (e.g. write to file)
console.log("some logic");
}
throw new MyError()
If you are using a NodeJS application, you can centrally manage all your thrown errors.
You should also name your errors:
class ApiError extends Error {
constructor (message, code) {
super(message);
this.name = 'ApiError';
this.code = code;
}
}
Similarly use other names for other error types.
For an express application,
app.use(routes);
// place this after your routes in express app. This will catch all your thrown errors.
app.use(function (err, req, res, next) {
console.log(err);
switch (err.name) {
case 'ApiError':
// write to file here
return res.status(err.code || 500).send({error: err.message});
case 'Some other error':
// handle differently
break;
default:
res.status(err.status || 500).render('500', {error: err});
}
});
Note if you are throwing from within a Promise, async/await, this won't catch your error. You will have to catch them centrally some other way, possibly by catching all Unhandled Promise Rejections in your app
process.on('unhandledRejection', (reason) => {
console.log(reason);
// log error in file
});
Similarly, you should also catch all uncaught exceptions centrally
process.on('uncaughtException', (err) => {
console.log(err);
// log error in file
});
Suggestion:
As far as logging errors in file are concerned, it is a great way to do that only if you're parsing your file by some other way, sending your file to logstash etc.
When you're not planning to parse your file programmatically, log your errors in an errordb / error-table. They are much easier to query that way :)

require.js check if unnamed module is specified/defined [duplicate]

I am trying to load some content using require.js. If the content doesn't exist I'd like to catch the error and notify the user.
In firebug I can see two errors:
"NetworkError: 404 Not Found
...and then a few seconds later:
var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#
Load timeout for modules: modules/messages/messages
http://requirejs.org/docs/errors.html#timeout
My code resembles:
require([path], function(content){
//need to catch errors as this will not be called;
});
How would one bind to requirejs events? Any idea?
It is also possible to use errbacks to have customized error handling appropriate to the specific use of require. Errbacks are documented here http://requirejs.org/docs/api.html#errbacks. Basically, you can add to require a function to be called if the load fails. It comes right after the function to be called if the load is successful.
Chin's case could be handled as:
require([path], function(content){
//need to catch errors as this will not be called;
}, function (err) {
//display error to user
});
Here's an example that tries loading from multiple places:
require([mode_path], onload, function (err) {
if (mode_path.indexOf("/") !== -1)
// It is an actual path so don't try any further loading
throw new Error("can't load mode " + mode_path);
var path = "./modes/" + mode_path + "/" + mode_path;
require([path], onload,
function (err) {
require([path + "_mode"], onload);
});
});
In this example onload would be the function called once the required code loads, and mode_path is a string identifying the mode. What you see there is code attempting to load a mode module for an editor from 3 different locations. If mode_path is foo, it will try to load foo, then ./modes/foo/foo and then ./modes/foo/foo_mode.
The example at requirejs.org shows how one might handle a case where they want to try multiple locations for a resource they want to make available with a well-known identifier. Presumably the entire code-base in that example requires jQuery by requiring "jquery". Whatever location jQuery happens to be located at, it becomes available to the whole code-base as "jquery".
My example does not care about making the mode known to the entire code-base through a well-known identifier because in this specific case there's no good reason to do so. The onload function stores the module it gets into a variable and the rest of the code base gets it by calling a getMode() method.
set the requirejs onError function:
requirejs.onError = function (err) {
if (err.requireType === 'timeout') {
// tell user
alert("error: "+err);
} else {
throw err;
}
};
If you want to setup an event you could bind to and trigger a global object. Such as:
$("body").bind("moduleFail",function(){
alert("Handling Event")
});
requirejs.onError = function (err) {
if (err.requireType === 'timeout') {
$("body").trigger({type:"moduleFail",err:err})
} else {
throw err;
}
};
require(["foo"],function(foo){
alert("loaded foo" + foo)
})
Did you try to override the requirejs.onError like shown here?
It worked for me after setting catchError as true like this:
require.config({catchError:true});
before calling any define() or require() functions.
You can use the requirejs.onError function as :
requirejs.onError = function (err) {
if (err) {
//Reload
}
else {
throw err;
}
};
You can also use err.requireType to catch specific errors like timeouts

Get stacktrace for Ember Application in in production mode

I am trying to debug emberjs and ember-data application in production server. I am listening on window.onerror so when something breaks I get callback where I can error message, line no and file. But window.onerror behavior is not same across different browsers. Also it doesnot provide stacktrace
So I am using the below function to wrap the ember boundary functions so I can get full stack trace.
function tryCatchWrapper (func, name) {
// Else wrap the function and return it
function wrapped() {
try {
return func.apply(this, arguments);
} catch (e) {
// Report the errors
console.log((name ? name + ": " : "") + e.message);
// Get stacktrace
throw e;
}
}
return wrapped;
};
So what all functions I can wrap using above function so as to get information about all the errors happen in the application without affecting anything?
UPDATE
Added JS Fiddle
Why not use the Ember.onerror event?
Cfr this answer

Categories

Resources