Skip to content
Grant Carthew edited this page Oct 25, 2024 · 17 revisions

Using the perj Logging Functions

Before you can use perj to log content to JSON you need to create a logger using the Perj constructor.

import Perj from 'perj'
const log = new Perj()

Once you have a logger (I like to use the variable name 'log') you can use the logging functions. By default there are 6 logging functions being fatal, error, warn, info, debug, and trace. You don't have to stick with these functions. You can create your own using the levels option.

Each one of the logging function has a number associated with it. This number is used for filtering purposes.

Here is what the default levels object looks like with the names and numbers:

{
    fatal: 60,
    error: 50,
    warn: 40,
    info: 30,
    debug: 20,
    trace: 10
}

When you create the logger each of these log levels is created as a function. Here is an example using each of the functions and there output:

import Perj from 'perj'
const log = new Perj()

log.level = 'trace'

log.fatal('fatal')
log.error('error')
log.warn('warn')
log.info('info')
log.debug('debug')
log.trace('trace')

/*

Standard out will be:

{"level":"fatal","lvl":60,"time":1526272817616,"msg":"fatal","data":""}
{"level":"error","lvl":50,"time":1526272817620,"msg":"error","data":""}
{"level":"warn","lvl":40,"time":1526272817620,"msg":"warn","data":""}
{"level":"info","lvl":30,"time":1526272817621,"msg":"info","data":""}
{"level":"debug","lvl":20,"time":1526272817621,"msg":"debug","data":""}
{"level":"trace","lvl":10,"time":1526272817621,"msg":"trace","data":""}


*/

There are a couple of points on interest in the above example. Firstly, the log.level was set to 'trace'. If this change was not made the debug and trace messages would not have been seen. Secondly you will see the output contains the 5 default keys being level, lvl, time, msg, and data.

The log.level setting is important. If you set log.level = 'warn' then you will only see fatal, error, and warn log messages sent to the write function (process.stdout by default). This allows you to turn down the verbosity of the logging in production and likewise turn it up for development.

Throughout your code you can write log.info() statements to help understand the flow of processing when debugging and help trace errors. Use the log.error() to report exceptions and the other levels where you see fit.

Log Arguments

I think one of the best features of perj is the flexibility in the logging arguments. You can call each log function with any number of arguments of any type. Here is the logic behind where the log arguments get placed:

  1. The first String message will be assigned to the msg JSON key. The first String message is defined as either a String argument or the message on an Error object.
  2. Extra String messages will be found attached to the data JSON key.
  3. One or more Object arguments will be found attached to the data JSON key.
  4. If there is more than one value attached to the data key the key will be an Array.

Let's see how that works with some code. Here is calling the info and error logging functions with a number of different arguments and their associated output. Note that you can pass Error objects to any log function:

import Perj from 'perj'
const log = new Perj()

log.info('single string')
log.info('first string', 'second string')
log.info('first string', 'second string', 'third string')
log.info('first string', 'second string', 'third string', 'fourth string')
log.info({ first: 'object' })
log.info({ first: 'object' }, { second: 'object' })
log.info({ first: 'object' }, { second: 'object' }, { third: 'object' })
log.info('single string', { first: 'object' })
log.info({ first: 'object' }, 'single string')
log.info({ first: 'object' }, 'first string', 'second string')
log.info({ first: 'object' }, 'single string', { second: 'object' })
log.error(new Error('first error'))
log.error(new Error('first error'), 'custom message after error')
log.error('custom message before error', new Error('first error'))
log.error(new Error('first error'), new Error('second error'))
log.error(new Error('first error'), new Error('second error'), new Error('third error'))

The above code will produce the following output. Note that I have formatted the output to make it easier to read:

{
  "level": "info",
  "lvl": 30,
  "time": 1526274419613,
  "msg": "single string",
  "data": ""
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419615,
  "msg": "first string",
  "data": "second string"
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419616,
  "msg": "first string",
  "data": [
    "second string",
    "third string"
  ]
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419616,
  "msg": "first string",
  "data": [
    "second string",
    "third string",
    "fourth string"
  ]
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419616,
  "msg": "",
  "data": {
    "first": "object"
  }
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419617,
  "msg": "",
  "data": [
    {
      "first": "object"
    },
    {
      "second": "object"
    }
  ]
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419617,
  "msg": "",
  "data": [
    {
      "first": "object"
    },
    {
      "second": "object"
    },
    {
      "third": "object"
    }
  ]
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419617,
  "msg": "single string",
  "data": {
    "first": "object"
  }
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419617,
  "msg": "single string",
  "data": {
    "first": "object"
  }
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419618,
  "msg": "first string",
  "data": [
    {
      "first": "object"
    },
    "second string"
  ]
}
{
  "level": "info",
  "lvl": 30,
  "time": 1526274419618,
  "msg": "single string",
  "data": [
    {
      "first": "object"
    },
    {
      "second": "object"
    }
  ]
}
{
  "level": "error",
  "lvl": 50,
  "time": 1526274419619,
  "msg": "first error",
  "data": {
    "stack": "Error: first error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:33:11)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
    "message": "first error",
    "name": "Error"
  },
  "error": true
}
{
  "level": "error",
  "lvl": 50,
  "time": 1526274419620,
  "msg": "first error",
  "data": [
    {
      "stack": "Error: first error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:34:11)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "first error",
      "name": "Error"
    },
    "custom message after error"
  ],
  "error": true
}
{
  "level": "error",
  "lvl": 50,
  "time": 1526274419621,
  "msg": "custom message before error",
  "data": {
    "stack": "Error: first error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:35:43)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
    "message": "first error",
    "name": "Error"
  },
  "error": true
}
{
  "level": "error",
  "lvl": 50,
  "time": 1526274419622,
  "msg": "first error",
  "data": [
    {
      "stack": "Error: first error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:36:11)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "first error",
      "name": "Error"
    },
    {
      "stack": "Error: second error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:36:37)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "second error",
      "name": "Error"
    }
  ],
  "error": true
}
{
  "level": "error",
  "lvl": 50,
  "time": 1526274419623,
  "msg": "first error",
  "data": [
    {
      "stack": "Error: first error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:37:11)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "first error",
      "name": "Error"
    },
    {
      "stack": "Error: second error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:37:37)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "second error",
      "name": "Error"
    },
    {
      "stack": "Error: third error\n    at Object.<anonymous> (/home/grant/node-perj/quick.js:37:64)\n    at Module._compile (internal/modules/cjs/loader.js:678:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)\n    at Module.load (internal/modules/cjs/loader.js:589:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:520:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)\n    at startup (internal/bootstrap/node.js:228:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)",
      "message": "third error",
      "name": "Error"
    }
  ],
  "error": true
}