Restify - Best practice for accessing logger from a module - node.js

I have looked for the answer to this for a while and just have not come up with a solution. I understand that I have access to the builtin logger from req.log.xxxxx(...), but what about a module that I have required into my controller? For example:
in my controller file, someController.js
var myModule = require('myModule');
SomeController.listUsers = function listUsers(req, res, next){
req.log.info('Some log message'); // <---- this works just fine
//...
}
In myModule.js:
module.exports = {
getUsers: function () {
// ...
// I would like to be able to log from here, but don't have access to the req object.
}
}
I don't really like the idea of passing the log object to the module's method, as that seems sloppy to me. If that's the only solution, then I'll live with it.

Restify uses bunyan to provide logging.
Looking through the documentation, the logger that's used for req.log is the one that's created at server startup (or at least a child of that logger). Since you can also create your own logger instance, I think that this should work:
// logger.js
var bunyan = require('bunyan');
module.exports = bunyan.createLogger(...);
// app.js
var server = restify.createServer({
log : require('./logger')
});
// someController.js
var logger = require('./logger');
...
This shares the same logger between the Restify server and other parts of your application. If you don't necessarily require that the logger is the same, you can also just create a new Bunyan instance in someController.js.

There aren't many options here. Typically I pass the "req" object. Another way around it is utilizing the "this" argument as a context. Something like this:
function listUsers(req, res, next) {
req.log.info('Some log message');
myModule.getUsers.call({log: req.log});
}
and...
module.exports = {
getUsers: function () {
(this.log || logger.log)() // ...
}
}

Usually, loggers get required into modules, implemented in the middleware, or inside a custom error object.
Another option you have in Events. Node.js is an Event driven language. You can just create a logger module that listens for log events. That's called neat programming.
However, I'd choose to require my logger into files, so that when we go into prod I have it deactivated/replaced with another more specific logger object with the exact interface.

Related

When first require() invoked, Does node js do caching? With Next.js

// FILE A.js
let users;
class A () {
static init() {
users = 'abc';
}
static addSomething () {
return users.slice(1);
}
}
module.exports = A;
// FILE A_1.js
const A = require('./A');
A.init();
// FILE A_2.js
const A = require('./A');
A.addSomething();
When I invoke A_2.js file, It throws error Can't call slice on undefined.
I heard something like when first require fired, it's cached.
I re-write module.exports = A to module.exports.default = A;
And const A = require().default;
It doesn't work like before.
What am I missing?
Thank you.
Sorry for the pseudocode on question.
It was split with next.js API dir, and custom model dir.
I found the information.
https://www.reddit.com/r/nextjs/comments/eiykfc/share_database_connection_in_nextjs_api_routes/
It looks like next.js serverless philosophy it's self.
This won't work when Next.js splits each API route into its own bundle with Webpack, will it? For me it did not cache modules between API routes, at least in development mode.

How do I override config values at runtime with node-config?

I'd like to override some values at test-time, specifically setting my retries for an http service to 1 (immediate failure, no retries). Our project uses node-config. According to the docs I can override with NODE_CONFIG env variable:
node myapp.js --NODE_CONFIG='{"Customer":{"dbConfig":{"host":"customerdb.prod"}}}'
Well I would prefer to do this in my test, but not for all tests. The code says that you can allow config mutations by setting ALLOW_CONFIG_MUTATIONS.
process.env.ALLOW_CONFIG_MUTATIONS = "true";
const importFresh = require('import-fresh');
importFresh("config");
process.env.NODE_CONFIG = JSON.stringify({httpServices:{integration:{enrich: {retryInterval: 1, retries: 1}}}});
expect(process.env.NODE_CONFIG, 'NODE_CONFIG not set').to.exist();
expect(process.env.NODE_CONFIG, 'NODE_CONFIG not set').to.match(/retryInterval/);
expect(process.env.ALLOW_CONFIG_MUTATIONS, 'ALLOW_CONFIG_MUTATIONS not set').to.equal("true");
const testConfig = require("config");
console.dir(testConfig.get("httpServices.integration.enrich"));
expect(testConfig.get("httpServices.integration.enrich.retryInterval"), 'config value not set to 1').to.equal(1);
Result:
{ url: 'https://internal-**********',
retryInterval: 5000,
retries: 5 }
`Error: config value not set to 1: Expected 5000 to equal specified value: 1`
How do I get this override to work?
(expect is from Hapi.js Code library)
I'm one of the maintainers of node-config. Your bug is that you used require the second time when you should have used importFresh again.
Your first use of "importFresh()" does nothing different than require() would, because it is the first use of require().
After setting some variables, you call require(), which will return the copy of config already generated and cached, ignoring the effects of the environment variables set.
You only needed to use importFresh() once, where you currently use require(). This will cause a "fresh" copy of the config object to be returned, as you expected.
Simply changing config's property worked for me.
For example:
const config = require( 'config' );
config.httpServices.integration.enrich.retryInterval = 1;
// Do your tests...
UPD: Make sure that overrides are done before anyone calls the first config.get(), because the config object is made immutable as soon as any client uses the values via get().
Joining late, but other answers did not fit with the testing standard in my project, so here is what I came up with
TL;DR
Use mocks..
Detailed Answer
node-config uses a function get to get the configuration values.
By mocking the function get you can easily modify any configuration you see fit..
My personal favorite library is sinon
Here is an implementation of a mock with sinon
const config = require('config');
const sinon = require('sinon');
class MockConfig {
constructor () {
this.params = {};
this.sandbox = sinon.sandbox.create();
}
withConfValue (confKey, confValue) {
this.params.confValues[confKey] = confValue;
return this;
}
reset () {
this.params.confValues: {};
return this;
}
restore() {
this.sandbox.restore();
}
apply () {
this.restore(); // avoid duplicate wrapping
this.sandbox.stub(config, 'get').callsFake((configKey) => {
if (this.params.confValues.hasOwnProperty(configKey)) {
return this.params.confValues[configKey];
}
// not ideal.. however `wrappedMethod` approach did not work for me
// https://stackoverflow.com/a/57017971/1068746
return configKey
.split('.')
.reduce((result, item) => result[item], config)
});
}
}
const instance = new MockConfig();
MockConfig.instance = () => instance;
module.exports = MockConfig;
Usage would be
const mockConfig = require('./mock_config').instance();
...
beforeEach(function () {
mockConfig.reset().apply();
})
afterEach(function () {
mockConfig.reset().clear();
})
it('should do something') {
mockConfig.withConfValue('some_topic.some_field.property', someValue);
... rest of the test ...
}
Assumptions
The only assumption this approach makes is that you adhere to node-config way of reading the configuration (using the get function) and not bypass it by accessing fields directly.
It's better to create a development.json, production.json et test.json in your config folder node-config will use it your app configuration.
you just net to set your NODE_ENV to use the specific file.
Hope it helps :)

What is exports.install in node js?

Hi I found a framework where they use a lot this pattern.
exports.install = function(){
//code
}
but usually you see this pattern in nodejs
module.exports = {
//code
}
Is this the same thing or is this something else ?
exports is the object corresponding to module.exports before you do anything to it. I think it's due to some legacy code, but basically folks use module.exports if they want to replace the whole object with their own object or a function, while they use exports if they just want to hang functions off the module. It's a little confusing at first, but essentially exports.install just means that calling code would do something like:
const mod = require('that-module');
mod.install(params, callback); // call that function
The framework you're looking at is probably using it as part of a bootstrapping process, afaik it doesn't have significance to the node engine itself.
Yes, it is the same thing. You can use one of 2 ways to setup your code.
The different thing is memory. They point to same memory. You can think exports like a variable and you can not use this way to export your module:
Given this module:
// test.js
exports = {
// you can not use this way to export module.
// because at this time, `exports` points to another memory region
// and it did not lie on same memory with `module.exports`
sayHello: function() {
console.log("Hello !");
}
}
The following code will get the error: TypeError: test.sayHello is not a function
// app.js
var test = require("./test");
test.sayHello();
// You will get TypeError: test.sayHello is not a function
The correct way you must use module.exports to export your module:
// test.js
module.exports = {
// you can not use this way to export module.
sayHello: function() {
console.log("Hello !");
}
}
// app.js
var test = require("./test");
test.sayHello();
// Console prints: Hello !
So, it just is style of developer.

How to get list of all routes I am using in restify server

I have a app designed as follows;
//server.js =====================================================
var restify = require('restify'),
route1 = require('./routes/route1),
route2 = require('./routes/route2),
....
....
....
var server = restify.createServer({
name: 'xyz_server'
});
route1(server);
route2(server);
Now each route file looks like belwo
//route1.js =====================================================
module.exports = function(server) {
server.get('/someRoute',function(req,res,next){
//.. do something
});
server.get('/anotherRoute',function(req,res,next){
//..something else
});
};
Now the issue is tht we have dozen's of route files and hundreds of routes in total.
There are multiple developers working on this project and several routes are being added daily.
Is there a function in restify gives me a list of all routes in the system ?
What i am looking for is something like:
server.listAllRoutes();
Is anyone aware of this ?
Try something like this
function listAllRoutes(server){
console.log('GET paths:');
server.router.routes.GET.forEach(
function(value){console.log(value.spec.path);}
);
console.log('PUT paths:');
server.router.routes.PUT.forEach(
function(value){console.log(value.spec.path);}
);
}
listAllRoutes(server);
This should list all GET and PUT paths, adding POST and DELETE should be easy :)
2019 update: server.router.routes is no longer available instead we have server.router.getRoutes() which returns a Map. So we can log all the routes using:
function listAllRoutes(server) {
Object.values(server.router.getRoutes()).forEach(value =>
console.log(
`ENDPOINT REGISTERED :: ${value.method} :: ${server.url}${value.path}`
)
);
}
http://restify.com/docs/server-api/#server
There is a router.getRoutes() method, but it returns an object which is not the best to work with for listing things. You could fiddle around with that to turn it into an array with the shape that you like.
Alternatively, you can access all the routes as an array and then map them, even better if you use a lib like better-console to give you console.table in node. The following is working nicely for me in restify#8.3.0:
import console from 'better-console';
function listRoutes(server) {
const { routes } = server.router._registry._findMyWay; // beware these are probably meant to be private APIs, they could be subject to change
const mapped = routes.map(({ method, path }) => ({ method, path }));
console.table(mapped.sort((a, b) => a.method > b.method));
}

How to avoid memory conflicts on ExpressJS/Node.js

I'm using Express and Passport for node.js to build a simple web server, I coded a simple module and then I loaded the module inside a GET request, everything works great until more than one user access the request.
I use to believe that a "var" inside an "app.get" function was removed from memory after the function finished, but isn't the case, I use some local variables inside the external module and the values are being shared between users, the module looks like this:
var some_value=0;
function some_method(){
some_value++;
return some_value;
}
exports.some_method = some_method;
And the Express request code looks like this:
app.get('/someurl', function(req, res) {
var some_extermal_module = require('/some_extermal_module'); // <-----Right way?
var data = some_extermal_module.some_method();
res.render('view', {
title : 'Title',
data_to_vew: data
});
});
An object inside a "app.get" request stays always in memory regardless of is being accessed by a different user?
How to clean a "var" object after it runs?
How can I avoid this memory conflicts?
Do I have to code differently the module or call differently the module?
Thanks a lot.
UPDATE: I guess this is a proper solution but I need the review of some node.js/Express expert for approval it or correction.
app.js:
var ext_mod = require('./module');
var express = require('express');
var app = express();
app.get('/', function(req, res){
var ex_mod_instance = new ext_mod({});
ex_mod_instance.func_a({},function(ret){
res.send('Hello World: '+ret);
});
ex_mod_instance = null; // clean
});
app.listen(8080);
console.log('Listening on port 8080');
module.js:
var node_module = function(config) {
this.config = config;
this.counter=0;
};
node_module.prototype = {
func_a: function(param,done) {
this.counter++;
done(this.counter);
},
func_b: function(param,done) {
}
};
module.exports = node_module;
Is this the best way to save memory (leaks)?
Every time a function is called you do get "clean" local variables in the local scope. Modules are for the purpose of writing clean, organized code, so that you do not have every function and variable in the global scope. I believe require does cache the module, so maybe you are having a problem with variables in the closure around the function exported from the module. You'll have to include more code.
One way you could solve this is by exporting a function that creates the module. That function could be your constructor, which will scope your counter locally.
Again, this is one solution.
Your variable 'some_value' is global in the context of the module. So each time a request use this module, it uses the same variable.
(Require does cache the modules wich are loaded only the first time)
I can think of 2 ways to achieve this:
either you want one variable per request, and you declare this variable in the module function, or in the res.locals.some_value if you want to use it in many functions during the same request
either you want one variable per user, and then you need to use express session middleware, and add the variable to req.session.some_value

Resources