Nondeterministic Polynomial Munchies
Miss any of our Open RFC calls?Watch the recordings here! »

decogger

1.0.3 • Public • Published

NPM version Build Status Dependency Status Coverage percentage

decogger

Centralizes the tracking of logs in a single point.

Motivation

Normally when we have to get logs to report the application status we have to mess up many functions adding code logs.

That makes it more difficult to test and change the logger dependency because we have to look for it manually in all the code.

// in user.js
 
const logger = require("some-logger")
const DB = require("./DB")
 
const byId = async id => {
  logger.info(`Getting user with id: ${id}`)
  const user = await DB.User.find({ id })
  logger.info(`obtained user: ${user.name}`)
  return user
}
 
module.exports = {
  byId
}
// in main.js
 
const user = require("./src/user")
const someUser = await user.byId(1) // get logs

It could be interesting to have the logs of decoupled functions and inputs of the code

// in user.js
 
const DB = require("./DB")
 
const byId = async id => {
  const user = await DB.User.find({ id })
  return user
}
 
module.exports = {
  byId
}
// in main.js
 
const decogger = require("decogger")
const config = require("./logger.config.js")
decogger(config) // apply logs for modules in configuration
 
const user = require("./src/user")
const someUser = await user.byId(1)
 
/*
when the method is executed, a log is automatically obtained in a single point previously defined
 
  function: 'byId',
  tag: 'src.user',
  start: 1534967702289,
  end: 1534967702289,
  executionTime: 234,
  input: [ 1 ],
  output: {
      id: 1
      name: Sara,
      email: sara@email.com,
  }
}
 
*/
// logger.config.js
 
const logger = require("some-logger")
 
module.exports = {
  logger: log => logger.info(log),
  modules: [
    {
      module: require("./src/user"),
      tag: "src.user",
      io: true,
      time: true
    }
  ]
}

Install

To install:

npm i -S decogger

Usage

In logger.config.js

module.exports = {
  logger: console.log,
  logErrors: true,
  modules: [
    {
      module: require("./src/user"),
      tag: "src.user",
      time: true,
      oi: true
    }
  ]
}

In the entry point decogger Must be the first module required.

const decogger = require("decogger")
const config = require("./logger.config")
decogger(config)
 
const user = require("./src/user")
// ...

Features

How does it work

  • Must to be the first module required in main file
  • For asynchronous functions WORKS ONLY WITH PROMISES
  • If the module is a function, the function is decorate with log configuration
  • If the module is an object(POJOs) or class instance all properties that are functions are decorated
  • If the module is a constructor function all the static methods and all the props that are functions in each instance are decorated
  • if the module is a primitive data type it does not do anything

Configuration options

module.exports = {
  logger: console.log // function to define the global logger
  logErrors: console.error // define the function to log errors and unhandled errors, if is true it will use the global logger
  modules: [
    // each module log definition
      {
        module: require('some-module'), // the module to apply logs
        logger: (log) => console.log('specific logger', log) // define the specific logger of this module
        tag: 'some-module', // tag to show in the log
        isConstructor: false // define the logs for the static methods of the class and each of its instances
        io: true, // Defines if the input parameters and the returned value for the method are shown in the log
        time: true, // define if the execution time of a method is shown
        omit: ['_privateMethod'] // if the module is an object, it defines which methods do not apply the logs. It can be an array or a predicate
    },
    {
      // this module will use the global logger
        module: require('other-module'),
        tag: 'other-module', // tag to show in the log
        isConstructor: true
        io: true,
        time: true,
        omit: (methodName, method, obj) => (
                    methodName.includes('_') &&
                    typeof method === 'function' &&
                    typeof obj === 'object'
                ) // using a predicate
    }
  ]
}

Log structure

{
  function: 'double', // the name of function executed
  tag: 'module.function', // te tag defined by "tag" config
  start: 1534973718974, // time in milliseconds of start method execution, defined by 'time' config
  end: 1534973718978, // time in milliseconds of end method execution, defined by 'time' config
  executionTime: 16, // time in milliseconds of method execution time , defined by 'time' config
  input: [ 2 ], // arguments of the call to the method, defined by 'io' config
  output: 4 // result of the call to the method, defined by 'io' config
}

Define a global logger

// the global logger will be used for all modules that do not contain their specific logger.
 
module.exports = {
  logger: log => console.log("Global logger", log) // global logger
  modules: [{
      module: require('some-module'),
      tag: 'some-module',
      io: true,
      time: true
  }]
}
// if the global logger is different to a function, and there are no specific loggers defined no action is executed
 
module.exports = {
  logger: false // global logger
  modules: [{
      module: require('some-module'),
      tag: 'some-module',
      io: true,
      time: true
  }]
}

Define a specific logger for each module

// the specific logger will be used for the module. If logger is not defined, use the global logger
.
 
module.exports = {
  logger: log => console.log("Global logger", log) // global logger
  modules: [{
      module: require('some-module'), // will use the global logger
      tag: 'some-module'
      io: true,
      time: true
  },
  {
      module: require('other-module'),
      tag: 'other-module'
      io: true,
      time: true,
      logger: (log) => console.log('specific logger for other-module', log) // will use the specific logger
 
  }]
}
// if the specific logger is different to a function, and dont have global loggers defined does not execute any action
 
module.exports = {
  logger: false // global logger
  modules: [{
      module: require('some-module'),
      tag: 'some-module',
      io: true,
      time: true,
      logger: false // specific logger
  }]
}

Tracking all errors and unhandled errors

// Will capture all new errors or unhandled errors with the global logger
 
module.exports = {
  logger: log => console.log(log), // global logger
  logErrors: true, // activate error capture
  modules: [
    {
      module: require("some-module"),
      tag: "some-module",
      io: true,
      time: true
    }
  ]
}
// in main.js
 
const decogger = require("decogger")
const config = require("./logger.config.js")
decogger(config) // apply logs for modules in configuration
 
new Error("some message")
 
/*
global logger capture the error or events uncaughtException and uncaughtRejection
 
    Error: some message
    at Object.construct (/git/core/logger/lib/index.js:136:43)
    at main (/git/core/logger/examples/index.js:30:17)
    at <anonymous>
*/
// logErrors can be a specific function to log errors
 
module.exports = {
  logger: log => console.log(log), // global logger
  logErrors: e => console.error(e), // will be used to log errors
  modules: [
    {
      module: require("some-module"),
      tag: "some-module",
      io: true,
      time: true
    }
  ]
}

Tracking constructors and instances

// in CustomNumber.js
module.exports = class CustomNumber {
  constructor(n) {
    this.value = n
  }
 
  double() {
    return this.value * 2
  }
 
  static asyncDouble(n) {
    return Promise.resolve(* 2)
  }
}
module.exports = {
  logger: log => console.log(log),
  modules: [
    {
      module: require("./CustomNumber"),
      tag: "CustomNumber",
      io: true,
      time: true,
      isConstructor: true // enable the logs for the static methods and all the instances of the class
    }
  ]
}
// in main.js
 
const decogger = require("decogger")
const config = require("./logger.config.js")
decogger(config)
 
const CustomNumber = require("./CustomNumber")
const five = new CustomNumber(5)
 
five.double() // apply logs
await CustomNumber.asyncDouble(5) // apply logs

License

MIT © Maurice Domínguez

Install

npm i decogger

DownloadsWeekly Downloads

10

Version

1.0.3

License

MIT

Unpacked Size

21.2 kB

Total Files

6

Last publish

Collaborators

  • avatar