1

I am working on logging helper (in Node.JS) witch have few exported functions (error, warn, etc...). I have for example two other scripts what using this my "module": test1, test2

I need when I initialize my logging module (let log = require("./log.js");) in both scripts to get error messages like this: [time][ERROR][TEST1] actual message...

I can use non-singleton approach and add constructor to my logging module what will take TEST1 so every script can have his own logger. But when there will be 100 scripts using logger, there will also be 100 logger instances.

So is there better approach to get same result, every file CAN have his own defined prefix?

Baterka
  • 622
  • 4
  • 9
  • 20
  • 1
    You could make an init function in your logger. Then do like `let log=require('./log.js'); log.init('test1')`. That might make it more explicit that something is happening when you load it. – sbrass Aug 09 '18 at 22:09
  • 1
    I had this approach but when I do `log.init('test1')` on file test1.js and `log.init('test2')` in file test2.js and test1.js will call `log.error(blah)`, you will get prefix of test2, because its singleton – Baterka Aug 09 '18 at 22:12
  • 1
    Ohh okay, sorry. You could try something like in https://stackoverflow.com/questions/16697791/nodejs-get-filename-of-caller-function and related questions to get the name of the file that called the logging function – sbrass Aug 09 '18 at 22:22
  • 1
    Yea filename is good idea when u always want to have prefix=filename, but I need custom prefix – Baterka Aug 09 '18 at 22:24
  • 1
    Or also no prefix at all – Baterka Aug 09 '18 at 22:25
  • 1
    Hmm interesting. So you could add prefix as a parameter to the functions, but if it never changes that could be annoying. You could also maybe use currying to have each method return a new method with the prefix filled in. Like `let log=require('./log.js'); logError=log.error('test1'); logError('blah')` and in log.js: `function error(pre){return function(msg){console.log(pre+msg)}}` or something like that? – sbrass Aug 09 '18 at 22:32

2 Answers2

1

The module needs to export factory function or a constructor; a parameters need to be passed somehow in order for test1 instance to be created.

Instances can be handled either by a user with modules which provide singletons naturally:

const loggerFactory = require('./log');

module.exports = loggerFactory('test1');

Or by the library itself:

loggerFactory.instances = new WeakMap();

function loggerFactory(name) {
  if (!loggerFactory.instances.has(name)) {
    loggerFactory.instances.set(name, ...);
  }

  return loggerFactory.instances.get(name);
}

The second case is exactly what renowned debug library does, although it handles a map of instances with regular object instead of WeakMap for compatibility reasons.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • 1
    But this methods will still create one instance of logger for every script right? Is it ok to use this for many scripts? – Baterka Aug 10 '18 at 10:03
  • 1
    It doesn't deal with 'scripts'. It creates one instance per namespace (`name` param). i.e. `loggerFactory('test') === loggerFactory('test')`. You can create as many or few instances as you need, for every script or not. I'm still not sure if this what you wanted, the question is quite ambiguous. – Estus Flask Aug 10 '18 at 10:29
0

Hope this helps for some of your cases...

const log = console.log;
export default function middleWare(optionalStringExtension = '') {
    console.log = (...args) => {
        log(...args, optionalStringExtension);
    }
}
Vontei
  • 1,727
  • 2
  • 14
  • 16