Ionut Eugen
Ionut Eugen

Reputation: 501

NodeJS http server metrics

I have as an assignment to do a nodeJS HTTP server with some form of metrics on it.

For this assignment, I am not allowed to use any form of external libraries & as the metric of the request I'll store the response time.

For route handling ill use a simple switch statement comparing the URL of the request

const http  = require("http");

var metrics = []

http.createServer((req, res) => {
   switch(req.url){
      case "/route"
         var start = Date.now();
         // some code to process the request, maybe some requests to the database, maybe retrieve some files etc
         res.end();
         metrics.push(Date.now() - start);
         break;
   }
}).listen(8080,()=>console.log("Server running!"))

The thing is, if I want to do this app with one or a low number of requests this method would be ok, however, in any other normal scenarios, this would be awful for any further changes to those metrics & much more.

I'm thinking of trying to solve this with some sort of event listeners that I would call at the beginning & the end of my request. Something that would store information about the request at the beginning & launch an event at the end to stop processing the metrics.

server.on('end', (data)=>{
   //end metrics somehow
})

Although it seems a little hard to implement, especially as I don't really want to overwrite a nodeJS event to add some data on it ( for instance I may want to add an id of the request, or a timestamp )

Is there a way to properly do this with nodeJS HTTP?

Upvotes: 0

Views: 599

Answers (2)

hoangdv
hoangdv

Reputation: 16127

You can handle it by finish event of res object. The event will be called when you call res.end() (or something like that).

My recommendation, to metrics an API service, you will need more information than response times.

const http = require("http");

var metrics = []

http.createServer((req, res) => {
  const startPoint = Date.now();
  res.on("finish", () => {
    if (req.url === "/metrics") {
      return; // no metrics for metrics route
    }
    metrics.push({
      path: req.url,
      method: req.method,
      status: res.statusCode,
      dateTime: startPoint,
      times: Date.now() - startPoint,
    });
  });

  switch (req.url) {
    case "/route":
      // some code to process the request, maybe some requests to the database, maybe retrieve some files etc
      setTimeout(() => {
        res.end();
      }, 1000);
      break;
    case "/metrics":
      res.setHeader('Content-Type', 'application/json');
      res.write(JSON.stringify(metrics));
      res.end()
      break;
    default:
      res.statusCode = 404;
      res.end();
      break;
  }
}).listen(8080, () => console.log("Server running!"))

As you can see, when you call GET http://localhost:8080/metrics api, the response will look like this:

[
  {
    "path": "/test",
    "method": "GET",
    "status": 404,
    "dateTime": 1613631702906,
    "times": 1
  },
  {
    "path": "/route",
    "method": "GET",
    "status": 200,
    "dateTime": 1613631702906,
    "times": 1004
  }
]

Upvotes: 1

Pingoo
Pingoo

Reputation: 36

create your own middleware on each routes, if you can't use framework like express or koa

Note: this is the simplest example, but it gives a clue of research

class Middleware {
    use(func) {
        this.next_func = (
          (stack) =>
            (next) =>
              stack(
                func.bind(this, next.bind(this)),
              )
        )(this.next_func);
    }
    next_func = (next) => next();
}

Upvotes: 1

Related Questions