7

On my client (a phone with a browser) I want to see the stats of the server CPU,RAM & HDD and gather info from various logs.

I'm using ajax polling.

On the client every 5 sec (setInterval) I call a PHP file:

  1. scan a folder containing N logs

  2. read the last line of each log

  3. convert that to JSON

Problems:

  1. Open new connection every 5 sec.
  2. Multiple AJAX calls.
  3. Request headers (they are also data and so consume bandwidth)
  4. Response headers (^)
  5. Use PHP to read files every 5 sec. even if nothing changed.

The final JSON data is less than 5 KB, but I send it every 5 sec, and there are the headers and new connection every time, so basically every 5 sec., I have to send 5-10 KB to get 5 KB which are 10-20 KB.

Those are 60 sec / 5 sec = 12 new connections per minute and about 15 MB per hour of traffic if I leave the app open.

Lets say I have 100 users that I let monitor / control my server that would be around 1.5 GB outgoing traffic in one hour.

Not to mention that the PHP server is reading multiple files 100 times every 5 sec.

I need something that on the server reads the last lines of those logs every 5 sec and maybe writes them to a file, then I want to push this data to the client only if it's changed.


SSE (server sent events) with PHP

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
while(true){
 echo "id: ".time()."\ndata: ".ReadTheLogs()."\n\n";
 ob_flush();
 flush();
 sleep(1);
}

In this case after the connection is established with the first user the connection keeps open (PHP is not made for that) and so I save some space (request headers,response headers). This work on my server bu most server don't allow to keep the connection open for long time.

Also with multiple users I read the log multiple times.(slowing down my old server) And I can't control the server ... I would need to use ajax to send a command...

I need WebSockets!!!


node.js and websockets

using node.js, from what i understand, i can do all this without consuming alot of resources and bandwich. The connection keeps open so no unnecessary headers, i can recieve and send data.it handles multiple users very well.

And this is where i need your help.

  1. the node.js server should in background update, and store the logs data every 5 sec if the files are modified.OR should that do the operating system with (iwatch,dnotify...)

  2. the data should be pushed only if changed.

  3. the reading of the logs should be happen only one time after 5 sec ... so not triggered by each user.


this is the first example i have found.....and modified..

var ws=require("nodejs-websocket");
var server=ws.createServer(function(conn){

    var data=read(whereToStoreTheLogs);
    conn.sendText(data)// send the logs data to the user 
    //on first connection.

    setTimeout(checkLogs,5000);
    /*
     here i need to continuosly check if the logs are changed.
     but if i use setInterval(checkLogs,5000) or setTimeout
     every user invokes a new timer and so having lots of timers on the server
     can i do that in background?         
    */
    conn.on("text",function(str){
     doStuff(str); // various commands to control the server.
    })
    conn.on("close",function(code,reason){
     console.log("Connection closed")
    })
}).listen(8001);

var checkLogs=function(){
 var data=read(whereToStoreTheLogs);
 if(data!=oldData){
  conn.sendText(data)
 }
 setTimeout(checkLogs,5000);
}

the above script would be the notification server, but i also need to find a solution to store somwhere the info of those multiple logs and do that everytime something is changed, in the background.

How would you do to keep the bandwich low but also the server resources.

How would you do?

EDIT Btw. is there a way to stream this data simultaneosly to all the clinets?

EDIT

About the logs: i also want to be able to scale the time dilatation between updates... i mean if i read the logs of ffmpeg i ned the update every sec if possible... but when no conversion is active.. i need to get the basic machine info every 5min maybe ... and so on...

GOALS: 1. performant way to read & store somewhere the logs data (only if clinets connected...[mysql,file, it's possible to store this info inside the ram(with node.js??)]). 2. performant way to stream the data to the various clients (simultanously). 3. be able to send commands to the server.. (bidirectional) 4. using web languages (js,php...), lunix commands( something that is easy to implement on multiple machines).. free software if needed.

best approach would be:

read the logs, based on current activity, to the system memory and stream simultaneously and continuosly, with an already open connection, to the various clients with webSockets.

i'don't know anything that could be faster.

UPDATE

The node.js server is up and running, using the http://einaros.github.io/ws/ webSocketServer implementation, as it appears to be the fastest one. I wrote with the help of @HeadCode the following code to handle properly the client situation & to keep the process as low as possible. checking various things inside the broadcast loop. Now the pushing & the client handling is at a good point.

var 
wss=new (require('ws').Server)({port:8080}),
isBusy,
logs,
clients,
i,
checkLogs=function(){
 if(wss.clients&&(clients=wss.clients.length)){
  isBusy||(logs=readLogs()/*,isBusy=true*/);
  if(logs){
   i=0;
   while(i<clients){
    wss.clients[i++].send(logs)
   }
  }
 } 
};
setInterval(checkLogs,2000);

But atm i'm using a really bad way to parse the logs.. (nodejs->httpRequest->php).. lol. After some googling i found out that i totally could stream the output of linux software directly to the nodejs app ... i didn't checked... but maybe that would be the best way to do it. node.js also has a filesystem api where icould read the logs. linux has it's own filesystem api.

the readLogs()(can be async) function is still something i'm not happy with.

  1. nodejs filesystem?
  2. linuxSoftware->nodejs output implementation
  3. linux filesystem api.

keep in mind that i need to scan various folders for logs and then parse somehow the outputted data, and this every 2 seconds.

ps.: i adde isBusy to the server variables in case the logReading sytem is async.

EDIT

Answer is not complete.

Missing:

  1. A performant way to read,parse and store the logs somewhere (linux filesystem api, or nodejs api, so the i store directly into system memory)
  2. An explaination if it's possible to stream data directly to multiple users . apparently nodejs loops trough the clients and so (i think) sending multiple times the data.

btw is it possible/worth to close the node server if there are no clients and restart on new connections on the apache side. (ex: if i connect to the apache hosted html file a script launches the nodejs server again). doing so would further reduce the memory leaking???right?

EDIT

After some experimenting with websockets (some videos are in the comments) i learned some new stuff. Raspberry PI has the possibility to use some CPU DMA channels to to high frequency stuff like PWM... i need to somehow understand how that works.

When using sensors and stuff like that i should store everything inside the RAM, nodejs already does that?? (in a variable inside the script)

websocket remains the best choice as it's basically easely accessible from any device now, simply using a browser.

cocco
  • 16,442
  • 7
  • 62
  • 77
  • 1
    Did you consider using nagios or other monitoring tool? – Keo Mar 05 '15 at 10:21
  • Are you doing does because you actually need to monitor a server, or does it have some sort an academic / recreational purpose ? – Willem D'Haeseleer Mar 05 '15 at 10:22
  • @Keo i'm monitoring the logs of ffmpeg. – cocco Mar 05 '15 at 10:37
  • @Willem D'haeseleer i love to learn new stuff in my spare time. don't earn money with this if is that what your asking.. i have my ubuntu headless server in a virtual machine that has ffmpeg on it... and as i finally made it to properly read those logs while converting i found out that it takes alot of resources... and as i think i can write js node.js would be nice. – cocco Mar 05 '15 at 10:38
  • i didnt wrote about ffmpeg... because done that i will improve the websocket system to control the machine... – cocco Mar 05 '15 at 10:40
  • I also always try to get the best performance out of what i write... that is the most important part. i have old pc's and slow internet – cocco Mar 05 '15 at 10:45
  • @cocco it doesn't matter what you are trying to log. You just provide anything(program, script,...) with proper output to nagios and it will take care of rest. – Keo Mar 05 '15 at 10:48
  • 1
    its free? low resources? update frequency? does it output json over websockets? btw i like to write it myself...use native commands... don't use plugins. i don't use jquery or stuff like that to make everything simple.- – cocco Mar 05 '15 at 10:49
  • i think it's not that hard, linux server should read the logs every time something changed, websocket server should push to every client the info using as low as possible resources. node.js is made for that right? i need to avoid multiple unnecessary reads and also avoid the timer for each client. – cocco Mar 05 '15 at 10:54
  • i could use php to read the logs, maybe a c script , maybe there is a native linux command that can monitor folders.. what is the best? maybe there is some other way to directly stream the log data to each client?? – cocco Mar 05 '15 at 10:57
  • i'm not totally shure about the techniques i choosed... – cocco Mar 05 '15 at 10:58
  • node.js app is stored/cached inside the ram... so it should be very fast.. – cocco Mar 05 '15 at 10:59
  • aww that naigos costs 1k$ lol, nah, i'm just doing some fun coding...btw that software would destroy my old server...i like to keep stuff minimal. – cocco Mar 05 '15 at 11:14
  • have you looked into SNMP at all? – glend Mar 09 '15 at 11:13
  • example ? is that better than websockets on node.js server with multiple clients? btw i need to handle everything with php or js or basic linux commands. – cocco Mar 09 '15 at 11:16
  • For log monitoring i use [log.io](http://logio.org/), maybe it help you or give to you a new idea about the code – Victor Mar 09 '15 at 11:52
  • you can watch the files or folder for changes, and then grab only the last 5kb from each changed log (might need to memorize filedates first). or even on a 2-sec interval, a filedate check could potentially cut down a ton of extra effort; don't check/load/send anything that hasn't changed. you can also use the memorized old filedate to crop the logs you're sending out so that they have only new data. lastly, you should make sure your client is still connected before you send() (or try() it) or else the whole thing can crash. – dandavis Mar 12 '15 at 17:07
  • atm i'm using a custom tail function to read only the last line of the each log. but i use php for that... maybe reading the file with nodejs or with the native linux filesystem api... – cocco Mar 12 '15 at 18:32
  • for the rest i already do alot of scaling checks to reduce the load... – cocco Mar 12 '15 at 18:32
  • While trying to find solution for this question i stumbled upon some new stuff to experiment... here are some websocket experiments that control a raspberry remotely.AAAAaaand yep wesocket is really fast!!!! https://www.youtube.com/playlist?list=PLL9y8ZNSfDQxqg37X4-2A9T-r98RcAOAs – cocco May 17 '15 at 20:44

6 Answers6

1

I haven't used nodejs-websocket, but it looks like it will accept an http connection and do the upgrade as well as creating the server. If all you care about receiving is text/json then I suppose that would be fine, but it seems to me you might want to serve a web page along with it.

Here is a way to use express and socket.io to achieve what you're asking about:

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

app.use(express.static(__dirname + '/'));
app.get('/', function(req, res){
    res.sendfile('index.html');
});

io.on('connection', function(socket){

    // This is where we should emit the cached values of everything
    // that has been collected so far so this user doesn't have to
    // wait for a changed value on the monitored host to see
    // what is going on.
    // This code is based on something I wrote for myself so it's not
    // going to do anything for you as is.  You'll have to implement
    // your own caching mechanism.
    for (var stat in cache) {
        if (cache.hasOwnProperty(stat)) {
            socket.emit('data', JSON.stringify(cache[stat]));
        }
    }
});

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

(function checkLogs(){
    var data=read(whereToStoreTheLogs);
    if(data!=oldData){
        io.emit(data)
    }
    setTimeout(checkLogs,5000);
})();

Of course, the checkLogs function has to be fleshed out by you. I have only cut and pasted it in here for context. The call to the emit function of the io object will send the message out to all connected users but the checkLogs function will only fire once (and then keep calling itself), not every time someone connects.

In your index.html page you can have something like this. It should be included in the html page at the bottom, just before the closing body tag.

<script src="/path/to/socket.io.js"></script>
<script>

    // Set up the websocket for receiving updates from the server
    var socket = io();

    socket.on('data', function(msg){
        // Do something with your message here, such as using javascript
        // to display it in an appropriate spot on the page.
        document.getElementById("content").innerHTML = msg;
    });

</script>

By the way, check out the Nodejs documentation for a variety of built-in methods for checking system resources (https://nodejs.org/api/os.html).

Here's also a solution more in keeping with what it appears you want. Use this for your html page:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>WS example</title>
</head>
<body>
<script>
var connection;
window.addEventListener("load", function () {
    connection = new WebSocket("ws://"+window.location.hostname+":8001")
    connection.onopen = function () {
        console.log("Connection opened")
    }
    connection.onclose = function () {
        console.log("Connection closed")
    }
    connection.onerror = function () {
        console.error("Connection error")
    }
    connection.onmessage = function (event) {
        var div = document.createElement("div")
        div.textContent = event.data
        document.body.appendChild(div)
    }
});
</script>
</body>
</html>

And use this as your web socket server code, recently tweaked to use the 'tail' module (as found in this post: How to do `tail -f logfile.txt`-like processing in node.js?), which you will have to install using npm (Note: tail makes use of fs.watch, which is not guaranteed to work the same everywhere):

var ws = require("nodejs-websocket")
var os = require('os');
Tail = require('tail').Tail;
tail = new Tail('./testlog.txt');

var server = ws.createServer(function (conn) {
    conn.on("text", function (str) {
        console.log("Received " + str);
    });
    conn.on("close", function (code, reason) {
        console.log("Connection closed");
    });
}).listen(8001);


setInterval(function(){ checkLoad(); }, 5000);


function broadcast(mesg) {
    server.connections.forEach(function (conn) {
        conn.sendText(mesg)
    })
}

var load = '';
function checkLoad(){
    var new_load = os.loadavg().toString();
    if (new_load === 'load'){
        return;
    }
    load = new_load;
    broadcast(load);
}

tail.on("line", function(data) {
    broadcast(data);
});

Obviously this is very basic and you will have to change it for your needs.

Community
  • 1
  • 1
HeadCode
  • 2,770
  • 1
  • 14
  • 26
  • what means "the checkLogs function has to be fleshed out by you"? – cocco Mar 09 '15 at 20:31
  • fleshed out... bad english .. sry.. anyway this is a good start, if the checkLogs function is executed once every 5 sec... in the last part of the answer... can't i use the native syntax with socket.io ... "new WebSocket("ws://url:port");" ? – cocco Mar 09 '15 at 20:41
  • the client html is rendered with apache or nginx. i would use node only for the data part. so just a small json file – cocco Mar 09 '15 at 20:42
  • @ cocoo I update my answer to include something that I think is exactly what you're looking for. – HeadCode Mar 11 '15 at 04:30
  • thank you, while everything works better now with node.js, i'm curious about the fact if i could further reduce the broadcasted data that happens inside the checkLogs loop example that i just posted.repeating me, using some sort of stream, as for now it loops trough the clients and so sends multiple times the data. so every 2 sec lets say (5kb*clients) – cocco Mar 11 '15 at 14:23
  • Also the part of reading properly the logs is a mystery for now... btw thx for the nodejs os implementation hint – cocco Mar 11 '15 at 14:25
  • Even if the answer is incomplete as i don't have a proper way to read the logs and the broadcasting apparently has to send the data to each user in a loop this is the most complete answer. i would be happy if you can investigate further about those 2 things.Anyway thx – cocco Mar 16 '15 at 11:41
  • @cocco Thank you, but please re-read my answer. A while ago I added code for watching logs. As for streaming, I think you're worrying too much about that. If you use something like socket.io you are doing exactly what most chat apps are doing. You don't need streaming or broadcasting. – HeadCode Mar 16 '15 at 16:00
  • it would be better to have broadcasting/streaming as where i live the internet is very slow. home upload is .3mb/s but if i use a phone i can only use the oldest type of connection ... so it's basically slower than the mythological 14.4k modems. thats why i'm worring. to read the file i use a custom tail function with php ... should i rewrite that one to use it with nodejs or use a different approach? – cocco Mar 16 '15 at 16:29
  • @cocco I may actually not fully understand what it is you're trying to do. Please just try an experiment using the last two code blocks in my answer and see how that works. It addresses log checking and server load and should be a good start. Streaming will NOT reduce the amount of data you have to send and broadcasting will only work if you have permission to send to the broadcast IP address on a particular sub net. – HeadCode Mar 17 '15 at 05:20
  • i need to understand if 1. streaming is possible with websockets.. or something similar... example: 5kb to send to each user (100user) ; with streaming i send 5kb and with a loop i send 500kb. atm i think node sends 500kb.. right? 2. is it better to read a file, tail, parse with nodejs , linux filesystem , php or something else. As i'm using nodejs now i think reading the file inside the app is better than reading it with a linux command, tail & parse it ...and then reread the result with node... – cocco Mar 17 '15 at 13:14
  • what about memory leaks?? i mean nodejs is more subjet to memory leaks than the native linux commands... – cocco Mar 17 '15 at 13:16
  • it's actually not reading the cpu's temp for now, but some sensors, and It allows me control/monitor also other stuff, not just the server!! ;) anyway, i updated the question, i need to find out how to do things even faster, without using the SDHC card of the server (or slower hdd's). – cocco May 17 '15 at 22:54
1

I had made a similar implementation recently using Munin . Munin is a wonderful server monitoring tool, open source too which also provides a REST API. There several plugins available for your needs monitoring CPU, HDD and RAM usage of your server.

vorillaz
  • 6,098
  • 2
  • 30
  • 46
0

You need to build a push notification server. All clients who are listening, will then get a push notification when new data is updated. See this answer for more information: PHP - Push Notifications

As to how you would update the data, I'd suggest using OS-based tools to trigger a PHP script (command line) that will generate an "push" the json file out to any client currently listening. Any new client logging on to "listen" will get served the current json available, until it's updated.

This way you're not subject to 100 users using 100 connections and how much ever bandwidth to poll your server every 5 seconds, and only get updated when they need to know there's an update.

Community
  • 1
  • 1
user3036342
  • 1,023
  • 7
  • 15
  • yes i'm trying to write my own push server with modern technologies. php is not the best for realtime applications like websockets and push stuff.btw my idea is to push the logs inside the system memory when needed so it does not even need to read the created logfileinfo.. – cocco Mar 09 '15 at 12:07
  • yea, that was just an example. check out: http://socket.io/demos/chat/ which is what you want. – user3036342 Mar 09 '15 at 14:01
0

How about a service that reads all the log info (via IPMI, Nagios or whatever) and creates the output files on some schedule. Then anyone that wants to connect can just read this output rather than hammering the server logs. Essentially have one hit on the server logs then everyone else just reads a web page.

This could be implemented pretty easily.

BTW: Nagios has a v nice free edition

ethrbunny
  • 10,379
  • 9
  • 69
  • 131
  • what do you think that naigos does in background??? you think it invents the various logs??? naigos also needs to read the logs somehow. btw i don't want to use a 1000$ software. read the question again. – cocco Mar 09 '15 at 12:05
  • There are all manner of connectors for Nagios out there. If you want to skip that part just read the IPMI data (or SNMP if you want) directly using the scheduled service. Having Nagios in the loop just takes care of part of it. – ethrbunny Mar 09 '15 at 12:10
  • the point is that installing thirt party software implies further use of the system resources. probably many useless (for me) background processes and maybe also the monitoring system is not up to date with the latest technologies like websockets. but most of all i'm trying to create it by myself. plus, from what i know those snmp ipmi are not designed for multiple(many) users. they are intresting but not what i need.it should also work on other platforms like arm processors... – cocco Mar 09 '15 at 16:38
  • thats why node.js should be better than snmp & ipmi. but maybe i'm wrong ... do you have some other sources wich show the performance (with multiple users) compared to node.js? – cocco Mar 09 '15 at 16:38
  • Websockets are not a new technology. This is not a new problem. If you don't like Nagios there is a [growing list](http://www.slideshare.net/vo_mike/the-opensource-monitoring-landscape) of tools which you might like better. – Roger Halliburton Mar 10 '15 at 23:34
0

Answering just these bits of your question:

  1. performant way to stream the data to the various clients (simultanously).
  2. be able to send commands to the server.. (bidirectional)
  3. using web languages (js,php...), lunix commands( something that is easy to implement on multiple machines).. free software if needed.

I'll recommend the Bayeux protocol as made simple by the CometD project. There are implementations in a variety of languages and it's really easy to use in its simplest form.

Meteor is broadly similar. It's an application development framework rather than a family of libraries, but it solves the same problems.

Paul Hicks
  • 13,289
  • 5
  • 51
  • 78
  • comet uses ajax ... ajax needs to send request headers every time right? websockets don't? am i wrong? – cocco Mar 16 '15 at 11:34
  • btw are there some benchmarks like nodejs vs comet or meteor? – cocco Mar 16 '15 at 11:37
  • No CometD doesn't use ajax, it uses long-requests from the client. Ajax-like, but fewer requests and more responsive (at the cost of keeping a connection open even if there's no traffic pending). I"m not aware of benchmarks, but if you find any, please update the answer, I'm sure they'd be useful to others. – Paul Hicks Mar 16 '15 at 18:41
0

Some suggestions:

  • Munin for charts
  • NetSNMP (used by Munin, but you can also use Bash and Cron to build traps that send SMS texts on alerts)
  • Pingdom for remote alerts about how well the server is responding to ping and HTTP checks. It can SMS text you or call a phone, as well as have call escalation rules.
Volomike
  • 23,743
  • 21
  • 113
  • 209