How to monitor incoming and outgoing network bytes from express & socket.io servers

Tags: , , ,



I have an express server which also contains socket.io on it. I want to know how many bytes going outside and coming inside on each clients’ requests including HTTP and Socket (WSS). I’m looking for a solution with open source technologies.

I found many tutorials online to get the read bytes inside the createServer method but here I’m not using this method since I use express.js. Please refer to my below code and assist me.

We use Nginx for our production server.

const express = require('express')
const app = express()
const http = require('http').Server(app)
const io = require('socket.io')(http)

app.get('/', (req, res) => {
    res.render('index')
})

http.listen(8080, () => console.log(`Server is running at 0.0.0.0:8080`))

Answer

If you want to capture socket.io stats too you need to got on the tcp layer. A tcp socket in node js has handy properties for these: bytesRead & bytesWritten: https://nodejs.org/dist/latest-v12.x/docs/api/net.html#net_socket_bytesread

When a client close the socket, use these to calculate the whole amount of transferred stuff.

const http = require('http');
const express = require('express');

const app = express();
const stats = new Map();

setInterval(() => {
    console.log("stats", stats);
}, 3000)

const web = http.createServer(app);

web.on("connection", (socket) => {
    console.log("new connection")

    if (!stats[socket.remoteAddress]) {
        stats[socket.remoteAddress] = {
            receive: 0,
            transmit: 0
        };
    }

    socket.on("close", () => {
        console.log("Save stats")
        stats[socket.remoteAddress].receive += socket.bytesRead;
        stats[socket.remoteAddress].transmit += socket.bytesWritten;
    });
});

web.listen(8080, "127.0.0.1", () => {
    console.log("Running")
});

const io = require("socket.io")(web);

io.on('connection', socket => {
    socket.on("timestamp", (data) => {
        console.log(data)
    });
});

app.get('/', (req, res) => {

    let html = '<script src="/socket.io/socket.io.js"></script>';
    html += '<script>';
    html += '   const socket = io("http://127.0.0.1:8080");';
    html += '   setInterval(() => {socket.emit("timestamp", Date.now())}, 1000)';
    html += '</script>';

    res.end(html);
});

Note that this measure everything, incl. http header & other overhead. I don’t know what happens when the socket is not closed properly (timeout, etc.)

That’s not “fail save”, you need to add error handling and timeout stuff so you don’t miss any transferred byte(s).

If you need anything to be changed or it doesn’t work like expected, let me know!


Updated answer based on the comment/”chat”

const http = require('http');
const express = require('express');

const app = express();
const stats = new Map();

setInterval(() => {
    console.log("stats", stats);
}, 3000)



const web = http.createServer(app);


web.listen(8080, "127.0.0.1", () => {
    console.log("Running")
});


const io = require("socket.io")(web);



app.get('/', (req, res) => {

    const { socket } = req;

    if (!stats[socket.remoteAddress]) {
        stats[socket.remoteAddress] = {
            receive: 0,
            transmit: 0
        };
    }

    socket.once("close", () => {
        console.log("Save stats")
        stats[socket.remoteAddress].receive += socket.bytesRead;
        stats[socket.remoteAddress].transmit += socket.bytesWritten;
    });

    res.end("Hello World");

});

This count only http request on the route /, no websockets just plain http.



Source: stackoverflow