create real-time server monitoring app with angularjs and nodejs

In this Tutorial, we implement the server application. This application should be able to monitor files and communicate with multiple clients at the same time. These are the perfect requirements to use an event-driven, nonblocking I/O application platform such as Node.js. The fact that we can also code the server application in JavaScript is another huge advantage. Additionally, the built-in package manager npm provides a variety of useful and easy to use packages.

Preview of our app

The dashboard application

 

Setting up a Node.js application

First, we need to install Node.js on our development machine. We can download and install the latest binaries from http://nodejs.org/. Node.js automatically installs its npm package manager, which we will use to install all the required packages for the server application.

To create a Node.js application, we will first create a package.json file, a file that contains all metainformation about the application (such as name, version number, and dependencies):

{
  "name": "webserver-monitor",
  "version": "0.0.1",
  "description": "Webserver Monitor Application",
  "dependencies": {
  }

}

For now, we leave the dependencies section empty and add the dependencies automatically when we install packages via npm and the --save flag.

Setting up a web server that serves static files

In this book, we will use the excellent Node.js web framework Express and the serve-static package to kick off a web server in under 10 lines of code. I will not go into the details about Express, but we will see that it’s very easy and straightforward to use for our purpose.

So, let’s add both the packages to our application. To do so, we open the terminal in the root directory of the project and execute the following commands in the terminal:

npm install --save express
npm install --save serve-static

These commands will add both the packages and their current versions as dependencies to the package.json file and download and install them in the npm_packages directory. The native Node.js function require(), which imports packages and modules, will automatically look for third-party libraries in this folder.

We can now implement the web server, so we create a server.js file:

/* server.js */
var app = require('express')();
var http = require('http').Server(app);
var serveStatic = require('serve-static');

// Serve all files of the root directory
app.use(serveStatic('.', {'index': ['index.html']}));

// Listen on port 3000
http.listen(3000, function(){
  console.log('listening on 0.0.0.0:3000');
});

I will quickly guide you through the steps in the preceding code. First, we load the express package and initialize it by calling (). It returns the app reference for the web framework. In the second line, we load the internal http module and use the .Server() method to handle all requests with the Express framework. The third line loads the serve-static package. In the following step, we create an instance of the serve-static module and add it as a middleware to Express. We do this to tell Express to look for every URL for static files in the root directory and it’s subfolders. The last line finally starts the server application on port 3000.

We can now run the server by calling node server.js and navigate to http://localhost:3000/ to open the client application (we will do this a little bit later).

 

Adding server push with WebSockets

In the title of this tutorial, we referred to a real-time application, meaning changes in log files should be available on the client in real time/immediately. Thus, we cannot use standard http requests anymore because they are unidirectional from the client to the server. It’s not possible to notify the client about data changes.

Real-time applications are usually implemented with a bidirectional communication between the web server and the client; thus, the WebSockets technology is exactly what we need. WebSocket is a standardized implementation of a bidirectional TCP connection for the Web. We do not want to deal with low-level protocols or compatibility issues, so we will use the awesome Socket.IO library, a wrapper for WebSockets with an extra compatibility layer.

Note

Socket.IO uses long polling to simulate a server push behavior in older browsers.

Let’s add Socket.IO to our server application and package.json file:

npm install --save socket.io

We can now add the Socket.IO module to our server.js file:

/* server.js */
var app = require('express')();
var http = require('http').Server(app);
var serveStatic = require('serve-static');
var io = require('socket.io')(http);

// Serve all files of the root directory
app.use(serveStatic('.', {'index': ['index.html']}));

// Wait for socket connection
io.on('connection', function(socket){
  // do while a client is connected

  socket.on('disconnect', function(){
    // do when client disconnects
  });
});

http.listen(3000, function(){
    console.log('listening on 0.0.0.0:3000');
});

Besides initializing the socket.io module with the http server object, we implement the two event listeners: .on('connection', callback) and .on('disconnect', callback) in the preceding code. These let us execute functions whenever a client connects to the server through WebSockets and lets us cleans up everything when the client disconnects again.

We already saw that Socket.IO waits for events that are triggered by clients (such as connecting or disconnecting clients). The same principle as the .on(type, callback) function can be used to listen for custom events that are triggered by the client, for example, to transfer data from the client to the server. In the callback function, the data that was sent by the client can be accessed with the first argument. To send data from the server to the client, we use the .emit(type, data) function. This function takes an event type and a message object data as arguments.

 

Reading logs and pushing them to the client

Now, it’s time to send some useful data through the WebSockets connection. Therefore, we add the native file system module, fs, to the application in order to read a file and push its content to the client:

var fs = require('fs');
var app = require('express')();
...
// Wait for socket connection
io.on('connection', function(socket){

  // Send the content of a file to the client
  var sendFile = function(name, path) {
    // Read the file
    fs.readFile(path, 'utf8', function (err, data) {
      // Emit the content of the file
      io.emit(name, data);
    });
  };

  // Wait for events on socket
  socket.on('watch', function(obj){
    sendFile(obj.name, obj.path);
  });

  socket.on('disconnect', function(){
    // do when client disconnects
  });
});

In the preceding example, we implement the sendFile()function inside the connection handler. In this function, we call the readFile() function. This function reads a file asynchronously and—once it is finished—pushes the content to the client via .emit() with an event type of the filename. Then, we set up a listener for an event watch whose message object should contain the name and path of a file and return the content of the file.

Now, we can implement a simple client that emits a watch event with the name and path of a log file and listens to an event with the name of the file. This client will look like the following code:

/* example/of/a/client.js */
socket.emit('watch', {
  name: 'nginx.error',
  path: '/var/log/nginx/error.log'
});

socket.on('nginx.error', function(data){
  console.log("Received: " + data);
});

We will use a very similar implementation later for the client. For now, let’s continue with the final step.

 

 

Pin It on Pinterest

Shares

Get the best in web dev

Join dunebook.com and recieve best in web dev , once a week FREE

An email has been Sent to your Inbox ! Please Confirm your Subscription :)