DEV Community 👩‍💻👨‍💻

Surya Shakti for Parseable

Posted on

Logging for your Node.js app

Introduction

In this article we will learn how we can store logs of Node.js application into parseable using Winston library. We'll look at what is logging and why it is important.

Table of contents

  1. What is logging?
  2. Using winston in a Node.js application
  3. sending those logs to the parseable

What is logging?

Logging is the process of recording application events and data to a log file or any other sources, for the purpose of analyzing the system.

Logs help developers to find the error, track the source of the bug and fix it. In Node.js it is critical to structure the application logs. when we are at the development phase we can use console.log to find the problems and to get the information you need.

But once the application is in production we cannot use the console.log any more.

Using winston in a Node.js application

I assume you have a node.js application, now to install winston & winston-transport in your project run the following commands.

npm install winston
npm install winston-transport
Enter fullscreen mode Exit fullscreen mode

Now our aim is to replace all the console messages from the application with the winston logger. So Just for example if you have these three event logs in your node.js application which you want to store in parseable using winston library.

connsole.warn('Got mutiple elements with same id');
console.error('Login Failed. Invalid ID');
console.info('Events posted successfully.');
Enter fullscreen mode Exit fullscreen mode

Configuring Winston in Node.js app

Create a 'logger' folder in the root directory where we will configure winston and send the logs to parseable.
Now in logger/index.js add following code

const winston = require("winston");
const { combine, timestamp, label, printf } = winston.format;
const Transport = require("winston-transport");
var axios = require("axios");

const myFormat = printf(({ level, message, label, timestamp }) => {
  return JSON.stringify({
    timestamp: timestamp,
    level: level,
    message: message,
  });
});

class CustomTransport extends Transport {
  constructor(opts) {
    super(opts);
  }
  log(info, callback) {
    console.info(info);
    var data = JSON.stringify([info]);

    var config = {
      method: "post",
      url: `https://demo.parseable.io/api/v1/logstream/${streamName}`,
      headers: {
        "X-P-META-Tag": "Owner",
        "X-P-META-Tag": "Host",
        "X-P-META-Tag": "Host.owner",
        Authorization: `Basic ${key}`,
        "Content-Type": "application/json",
      },
      data: data,
    };

    axios(config)
      .then(function (response) {
        console.log(response.data);
      })
      .catch(function (error) {
        console.log(error);
      });

    callback();
  }
}

const devLogger = () => {
  const transport = new CustomTransport({});

  return winston.createLogger({
    level: "debug",
    format: combine(label(), timestamp(), myFormat),
    transports: [transport],
  });
};


let logger = null;

if (process.env.NODE_ENV !== "production") {
  logger = devLogger()  
}

module.exports = logger;
Enter fullscreen mode Exit fullscreen mode

Here we are configuring winston in our node.js application and sending the logs to parseable.

Let's discuss this code in parts for better understanding.

Initializing winston logger instance

const devLogger = () => {
  const transport = new CustomTransport({});
  return winston.createLogger({
    level: "debug",
    format: combine(label(), timestamp(), myFormat),
    transports: [transport],
  });
};

The snippet above contains the initialization of a Winston logger instance. Here we specify the log level for this specific logger instance using the npm log level standard, format in which logs will be stored and


 that specifies where the logs data will go. In our case we will send it to the parseable.



> **Setting custom format of the log data**
>
>>

 ```js 
const myFormat = printf(({ level, message, label, timestamp }) => {
  return JSON.stringify({
    timestamp: timestamp,
    level: level,
    message: message,
  });
});
Enter fullscreen mode Exit fullscreen mode

The snippet above specifies the format of the log data in which it will be stored.

Sending the log data to parseable

class CustomTransport extends Transport {
  constructor(opts) {
    super(opts);
  }
  log(info, callback) {
    console.info(info);
    var data = JSON.stringify([info]);
    var config = {
      method: "post",
      url: `https://demo.parseable.io/api/v1/logstream/${streamName}`,
      headers: {
        "X-P-META-Tag": "Owner",
        "X-P-META-Tag": "Host",
        "X-P-META-Tag": "Host.owner",
        Authorization: `Basic ${key}`,
        "Content-Type": "application/json",
      },
      data: data,
    };
    axios(config)
      .then(function (response) {
        console.log(response.data);
      })
      .catch(function (error) {
        console.log(error);
      });
    callback();
  }
}

The snippet above is responsible for sending the log data to the parseable. here streamName is the log stream you have created in parseable. and the key is the authentication key for accessing the parseable.

calling the logger function

let logger = null;
if (process.env.NODE_ENV !== "production") {
  logger = devLogger()  
}

You may not want to store the logs in parseable in development phase then you can see them on console to test it and when in production mode you can send it to parseable. The snippet above calls the logger function according to your requirements. you can also call the function directly if you don't want this conditional calling.

Then we can use logger instead of console in our application.

const logger = require('./logger')

logger.warn('Got mutiple elements with same id')
logger.error('Login Failed. Invalid ID')
logger.info('Events posted successfully.')
Enter fullscreen mode Exit fullscreen mode

Conclusion

Hurray!!🥳🥳🥳

You have successfully integrated parseable with your node.js application. now you can run your application and all the events you have replaced with logger will be posted to parseable and you can check in the logstream you created earlier.

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

⭐️🎀 JavaScript Visualized: Promises & Async/Await

async await