How to make a proper logging in nodejs - javascript

I Have a service that uses wrapper class for Winston logger to log the HTTP calls, internal failers, and so on to be able to maintain the service on production
the behavior of logging is something like this
function getUser(req, res, next) {
try {
logger.info("user::api::getUser", "controller called");
// do some stuff here, call the service related and return response
} catch(err) {
logger.error("user::api::getUser", err);
}
}
and also this logger is called in all subsequent functions along with the app, such as services, db access layers, controllers, middlewares, and so on
Actually, I am disappointed about calling logger in each function I write which I feel like polluting the code and don't make single responsibility principle also makes the code violates closed to modification principle` since if I updated the logger API for example, then I have to go through all the functions that the logger used inside and update it to the new syntax which is not good
I thought about if I can use event-driven, I mean event emitters to emit events on each failure, call and the handlers of these events will write the appropriate log
for example something like this
function getUser(req, res, next) {
try {
eventEmitter("info", "controller called");
// do some stuff here, call the service related and return response
} catch(err) {
eventEmitter.emit("error", err);
}
}
and here is the listener
eventEmitter.on("error", (err) => {
logger.error("error", err);
});
I see this syntax hides the implementation of calling the logger into one function instead of calling it in each part of the app, but still, the functions are polluted because I still have to call the event emitter inside them to emit logging event
I don't know if there is an intelligent way to implement logging without calling the logger in each part of the app like this !!
Also, I am wondering how giant companies handle these cases in their applications
I hope someone respond to me and guide me to the right direction

Related

Meteor error handling

How is it possible to add a global exception / error handler in Meteor.js. I looked through so much code, but noone explains a global method... Every one just do a try catch around every Meteor.call or add a async callback to it. But I'm lazy I just want one piece of code that handles all my Meteor.Errors. Mostly it's already a client readable error. So I just have to show it to him.
I tryed to use:
$(window).error(function(error) {
const errorText = T9n.get("Exception." + error.originalEvent.error.error);
View.toast(errorText);
});
but its just working for normal javascript errors not for Metero.Error.. seems to be that Meteor catches it, before I can catch it there.
I don't know if this is exactly what you need but, here is a solution.
In every Meteor.call(), have it like this:
Meteor.call('contactForm', arg1, arg2, function(err, res){
handleError(err, res);
});
Define a reusable error handler in your client side:
handleError = function (err, res){
if(err){
//do something with the error sent from server. not the ugly alert() like this code.
alert('error!')
} else{
//do something if no errors.
alert('done!')
}
}
Of course, you have to define your errors and results in your methods but this solves writing the same things over and over again in client side. You can also define helpers like handleError above in your server side. For example, I have checkUser() in my server like this:
checkUser = function (){
if(!Meteor.user()){
throw new Meteor.Error(400, 'You are not a unicorn yet! I mean, user.')
}
}
and in methods I just write checkUser(); to use it.
EDIT:
Those global functions are not inside any other code block. Just have them standalone

Node.js Should Functions be Declared outside of other functions? (With express)

Because Node runs the code inside a require call and then exports the members defined in it, it seems like it would be better to define functions outside of functions when that module is required or used multiple times.
For instance, take the following two codes using express:
router.get('/', function (req, res) {
function logTest () {
console.log('log test');
}
});
And
function logTest () {
console.log('log test');
}
router.get('/', function (req, res) {
logTest () {
});
It seems like the code in the second answer would be more efficient because logTest is only defined one time as opposed to being defined every time a get request is made. Is this true? Are there any best practices about where to define these functions?
I have looked around other answers and not found anything that really gets to my question here.
EDIT:
In addition to performance gains, (for which, in Node, the answer seems to be little to none) I am interested in style / maintainability and if one technique is preferred to the other in this respect.
Thank you

Yeoman - Delaying logging until after task completion

I'm getting frustrated with part of a Yeoman Generator I'm building. As it's my first, I have no doubt I'm missing something obvious, but here it goes.
Simply put, I'm trying to log a message, Do Thingsā„¢ and then log another message only when those things have been done.
Here's the method:
repos: function () {
var self = this;
this.log(highlightColour('Pulling down the repositories'));
// Skeleton
this.remote('user', 'skeleton', 'master', function(err, remote) {
if (!err) {
remote.bulkDirectory('.', self.destinationRoot());
} else {
self.log('\n');
self.log(alertColour('Failed to pull down Skeleton'));
repoErr = true;
}
});
//
// Three more near identical remote() tasks
//
if (!repoErr) {
self.log(successColour('Success!'));
self.log('\n');
} else {
self.log(alertColour('One or more repositories failed to download!'));
}
},
Each of the individual remote() tasks are working fine, but I get both the first and last self.log() messages before the file copying happens. It seems trivial, but I simply want the success message to come after everything has been completed.
For example, in the terminal I see:
Pulling down the repositories
Success!
file copying results
It should be:
Pulling down the repositories
file copying results
Success!
I thought it could be something to do with using this.async() with done() at the end of each remote() task, and I tried that, but whenever I do, none of the code fires at all.
I've even tried breaking everything (including the messages) into separate methods, but still no luck.
Such a simple goal, but I'm out of ideas! I'd be grateful for your help!
EDIT: In case you're wondering, I know the messages are coming first because any alerts regarding file conflicts are coming after the messages :)
This is not an issue related to Yeoman. You have asynchronous code, but you're handling it as if it was synchronous.
In the example you posted here, just do the logging as part of this.remote callback:
repos: function () {
var self = this;
this.log(highlightColour('Pulling down the repositories'));
// Skeleton
this.remote('user', 'skeleton', 'master', function(err, remote) {
if (!err) {
remote.bulkDirectory('.', self.destinationRoot());
self.log(successColour('Success!'));
self.log('\n');
} else {
self.log('\n');
self.log(alertColour('Failed to pull down Skeleton'));
self.log(alertColour('One or more repositories failed to download!'));
}
});
},
Maybe your actual use case is more complex; in this case you can use a module like async (or any other alternative) to handle more complex async flow. Either way, Yeoman doesn't provide helpers to handle asynchronous code as this is the bread and butter of Node.js.

Custom event listeners in an express route

What is the best way of handling custom event listeners in an express route?
I'm probably doing it all wrong but here's what I have at the moment:
module.exports = {
get: function(req, res, next) {
MyModel.on('error', function(err) {
res.send(501)
})
MyModel.on('found', function() {
res.send(200)
})
MyModel.on('notFound', function() {
res.send(404)
})
MyModel.findByName(req.params.name);
}
}
I can see this is totally wrong since each event listener will be added on each request.
It also feels wrong to start passing the response object around to facilitate responding when an event is fired.
I could just use callbacks on the findByName method but I really like tying into the event system but I'm just wondering how to handle this situation better.
Don't use event bindings for this, use the callback function:
module.exports = {
get: function(req, res, next) {
MyModel.findByName(req.params.name, function (error, model) {
if (error) {
return res.status(501).send(error);
}
if (!model) {
return res.status(404).send('Not found');
}
res.send(model.toJSON());
});
}
}
To add some clarification based on the comments, your example is using express and mongoose, both by the same original author and both primarily oriented with functional style programming and callbacks. While it is possible to design frameworks to use events, callbacks, or both/either (optional), in these 2 specific cases the library forces you to use callbacks because it doesn't provide events for these particular operations. That's why for express and mongoose for these particular calls, callbacks are the idomatic thing.
Now looking at your example, mongoose does emit some events at the Model class level, but those are not associated with an express request/response and thus are more appropriate for error logging and exception handling and some other specialized use cases outside of basic web application response rendering.
So when I said "don't user event bindings for this", I didn't mean event bindings are never appropriate, just that given your specific code snippet, they are neither supported by the libraries you are using nor idiomatic for this example of a basic make-a-db-query-and-send-back-a-web-page scenario.

Wrapping Backbone sync requests

I am writing a Backbone application, and I need to offer some feedback to users whenever a request to the server is made (annoying, I know, but I have no control over this behaviour of the application). The backend always reports an informative (at least in theory) message with every response, like
{
"status":"error",
"message":"something went really wrong"
}
or
{
"status":"success",
"message":"congratulations",
"data":{...}
}
What I would like to understand is where to put a hook for some kind of messaging service.
One possibility is the parse() method for models and collections. To avoid duplication, I would have to put it inside some model base class. It is still a bit annoying since all models and collections have their own parse() anyway.
A more reasonable place to look would be the Backbone.sync function. But I do not want to overwrite it, instead I would like to wrap it inside some other helper function. The problem here is that I cannot find a good hook where to put some logic to be executed with every request.
Do you have any suggestions on how to organize some piece of logic to be executed with every request?
Since Backbone.sync returns whatever $.ajax returns, it is easy to achieve what I want by using jQuery delegates, like this
var originalMethod = Backbone.sync;
Backbone.sync = function(method, model, options) {
var request = originalMethod.call(Backbone, method, model, options);
request.done(function(msg) {
console.log(msg);
});
request.fail(function(jqXHR, textStatus) {
console.log(jqXHR, textStatus);
});
return request;
};
Assuming you are using a recent (>1.5) jquery all results from sync will return the $.ajax promise.
You can do it then without overriding anything in sync by using that promise. For example, if you did a fetch(), you could do:
var p = mymodel.fetch();
p.done(function (res) { ... });
p.fail(function (err) { ... });
Of course you can also use callbacks in fetch options, but I find the above much cleaner. The same pattern applies for say save or anything that uses sync.

Categories

Resources