Free Blog Themes and Blog Templates
 

AJAX Logfile Tailer & Viewer

Recently I had a need for a simple logfile viewer for use in some stuff we have planned at Freepository. But this log file viewer had a few requirements that made it unique: it had to get the log file contents from the server in small chunks, not tie up the browser (such as an old-style synchronous request would do), and refresh in the browser without reloading the page.

I thought I could easily find one that someone had already written, but Google was not my friend. I found nothing even close, so I wrote my own. Here it is.

Working example:  https://freepository.com/ajax-logtail-viewer/ajax-logtail-viewer.php


/* logtail.js
an ajax log file tailer / viewer
copyright 2007 john minnihan.

http://freepository.com

Released under these terms
1. This script, associated functions and HTML code ("the code") may be used by you ("the recipient") for any purpose.
2. This code may be modified in any way deemed useful by the recipient.
3. This code may be used in derivative works of any kind, anywhere, by the recipient.
4. Your use of the code indicates your acceptance of these terms.
5. This notice must be kept intact with any use of the code to provide attribution.
*/

function getLog(timer) {

var url = "http://your.system.yourdomain.com/logtail.php";
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
startTail(timer);
}


function startTail(timer) {
if (timer == "stop") {
stopTail();
} else {
t= setTimeout("getLog()",4000);
}
}

function stopTail() {
clearTimeout(t);
var pause = "The log viewer has been paused. To begin viewing logs again, click the Start Viewer button.";
logDiv = document.getElementById("log");
var newNode=document.createTextNode(pause);
logDiv.replaceChild(newNode,logDiv.childNodes[0]);
}

function updatePage() {
if (request.readyState == 4) {
if (request.status == 200) {
var currentLogValue = request.responseText.split("\n");
eval(currentLogValue);
logDiv = document.getElementById("log");
var logLine = ' ';
for (i=0; i < currentLogValue.length - 1; i++) {
logLine += currentLogValue[i] + '<br/>\n';
}
logDiv.innerHTML=logLine;
} else
alert("Error! Request status is " + request.status);
}
}

This is implemented via a div named log, two buttons (Start & Stop) and of course the javascript files themselves. Here’s the HTML snippet:

<html>
<head>
...
<script type="text/javascript" src="js/ajax.js"> </script>
<script type="text/javascript" src="js/logtail.js"> </script>
...
</head>
<body>
...

<button onclick="getLog('start');">Start Log</button>
<button onclick="stopTail();">Stop Log</button>

...
<div id="log" style="border:solid 1px #dddddd; margin-left:25px; font-size:9px;
padding-left:5px; padding-right:10px; padding-top:10px; padding-bottom:20px;
margin-top:10px; margin-bottom:10px; width:90%; text-align:left;">
This is the Log Viewer. To begin viewing the log live in this window, click Start Viewer. To stop the window refreshes, click Pause Viewer.
</div>
<p>...</p>
</body>
</html>

For completeness, here is the source for ajax.js. I did not write this myself; I think it came from Brett McLaughlin.

/* ajax.js */
var request = null;
try {
request = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
if (request == null)
alert("Error creating request object!");

var request = createRequest();

And here is the trivial PHP script (“logtail.php” in the example above) that is called asynchronously:

<?
// logtail.php
$cmd = "tail -10 /path/to/your/logs/some.log";
exec("$cmd 2>&1", $output);
foreach($output as $outputline) {
echo ("$outputline\n");
}
?>

Comments are welcome, and though I hope this is useful to you… I don’t have time to support it, so debugging questions are likely to be ignored. Be sure to check out the working example here

https://freepository.com/ajax-logtail-viewer/ajax-logtail-viewer.php

The obvious question may be

“How do I control the timer? Can I make it update more or less frequently?”

The answer is Yes. Simply adjust the value I have highlighted above. A larger number makes the log viewer refresh less frequently. The default (in red above) is about 4 seconds.

I would have preferred to avoid use of innerHTML in the div refresh, but much to my dismay no other technique I tried worked. innerHTML worked flawlessly and immediately. Hrrumph.

Tags: , , ,

Reblog this post [with Zemanta]

Popularity: 88% [?]

  • Aaron
    Thank you! This is something I too have been searching for and did not find (until I typed the right voodoo into google and found your page, at least).
    A very useful thing to have. The only problem I had was that the content would not update as the browser would cache it forever, so you would only get the first tail and then it just redisplayed the cached content over and over. Maybe a silly way to fix it, but I changed the getLog function slightly to add a random and meaningless variable to the url and now everything works great. Is there a better way to avoid the caching?
  • John Minnihan
    hey Aaron,

    Sorry for the delayed reply to your question.

    The getLog function updates properly for me on Flock, Firefox & Camino on OSX. You may be seeing results of IE's (assuming IE here) aggressive caching. There are two ways to avoid the caching isssue: first, create a truly random URL such that each time the GET is invoked, it will indeed be unique. This is in fact the technique you used.

    The other is to use the NO-CACHE metatag on the page. I've used this elsewhere to prevent IE from caching a page, primarily to prevent it from being accessible in the history. This is discussed here:

    http://support.microsoft.com/kb/q222064/

    Note that to fully implement this technique, you must place a NO-CACHE rule both in the header and at the bottom of the html.
  • Hello

    may I use this
    var url = "logtail.php";
    instead of this
    var url = "http://your.system.yourdomain.com/logtail.php";

    BTW for me it's does not work , do you confirm that all the js files are shown above ?

    Thank you!
  • John Minnihan
    Hey graziano,

    Sure - you may edit the script any way you wish. Have fun with it.

    What part isn't working? Do you see any error messages?
  • John Minnihan
    There was a publishing error in the ajax Javascript.

    The very last line:

    var request = createRequest();

    must be included - very sorry!
  • John Minnihan
  • jherazob
    Just discovered this. Noticed something: It doesn't seem to work with Opera. Tried with firefox 3 and ie6 and worked perfectly, but not with opera. Granted, i'm using the version 10 alpha, but everything else works fine, so there's probably a small compatibility detail there.
  • jherazob
    Sorry, wasn't very specific. It doesn't automatically refresh in opera, it just sits there. It shows the log, shows the pause message when you press stop and removes it when you start again, but the log doesn't refresh at all. I'm not much of a web coder, but if i do find the bug i'll post the fix here.
  • jherazob
    After asking around, it worked perfectly for other people on different opera versions. I tried it with a blank profile on my machine and it worked. So, it's something wrong on my profile.

    False alarm, no worries, if i catch the offending bit of configuration info i'll post it anyway.
  • John Minnihan
    Got it. Thanks for the update.
  • John Minnihan
    Thanks!
  • Lucas
    This is really nice. I was browsing the web for a script doing exactly this but all were dated and incomplete and none were this mature. Amazing this script is not hosted all over the web. Many thanks for your efforts.
  • Lucas
    I just setup the script on my server but sadly it does not work, probably I am missing something. When I press the "Start log" button the contents of the ajax-logtail.php page are displayed in the div area.

    Any ideas what is going wrong?

    Server = apache2 on opensuse
  • John Minnihan
    If you have a link, I'll take a brief look.
  • Lucas
    Hi John,

    That is very kind of you, however I am working on an intranet page.
    I did upload the files I used, including a dir.txt containing the file attributes.
    I hope it is enough.

    http://www.easy-share.com/1903994283/example.tar
  • John Minnihan
    I can only offer educated guesses, then.

    If the contents of the php script are displayed (anywhere) rather than executed, it would seem that your web server isn't properly recognizing the PHP as an executable script.

    Can you hit htttp:/your.internal.server/ajax-logtail.php & get it to execute? If it only displays the contents, then you know your server doesn't have PHP capabilities. Solve that first & then the script should work in the context of the ajax logfile viewer.
  • Lucas
    PHP modules were installed correctly and other PHP pages loaded fine, however you pushed me in the right direction and started thinking why the ajax-logtail.php script was not working.

    The solution proofed to be simple :)
    I had to replace the "<?" header with "<?PHP" (append PHP string)

    When I did that the file was interpreted as a PHP file.

    Thanks for your help, issue solved!
  • John Minnihan
    Excellent.
  • John Minnihan
    Even though only a few have commented or asked questions here, it is obvious from the server logs that many, many people find this script every day. So, perhaps it is all over the Net already...
  • Hello,

    Many thanks for the code, I combined it with another tool to have (I hope) a Netfilter log viewer : NetfilterEyes. I was obliged to do some changes to fit my needs... Hope this can help.
  • John Minnihan
    Hey all -

    To everyone who has visited this page, checked the example and found that it didn't refresh as advertised, please accept my apologies.

    I had made some server-side configuration changes to Apache that resulted in far-too-aggressive caching of page content. This had the affect of not refreshing the logtail <div> in the example.

    There is (and was) nothing wrong with the script itself, so if you had downloaded it & attempted to use it on your own server, it would have worked for you.

    Again, apologies to anyone that was blocked by this server-side configuration error on my part. I've restored the original config & the example now functions as it should.
  • Chris
    Is there a way to get two of these going on the same page with different logs?
  • John Minnihan
    In theory, that should be possible. Create two of each of the functions or more cleanly, allow them to take arguments that point to the correct log file script & div to update.

    Use my reload.php script, the page that opens in the test harness with the big 'Generate Log Output' button, as the way to test:

    <?
    $log = fopen("./ajax-logtail-viewer.log", "a");
    $ip = $_SERVER['REMOTE_ADDR'];
    $page = $_SERVER['SCRIPT_NAME'];
    fwrite($log, "ALFV - " . $ip . " loaded " . $page . " at " . gmstrftime ("%b %d %Y %H:%M:%S", time()) . "\n");
    ?>

    <html>

    <button style="font-size:30px;" onclick="window.location.reload()";>Generate Log Output</button>





    Click the button you see above to reload this page. It will generate log output that may be viewed in the Log Viewer.
    </html>

    Create two of these one, say reload-1.php and reload-2.php and make -1 point to the first log file & -2 point to the second one. This is just a means to generate output & does not actually implement any part of the logtail viewer, so don't get too hung up on it. Make corresponding adjustments in the logtail viewer itself to test this technique.

    If you get it to work like that, let me know.
  • John
    I notice there is a screen/div flicker/back-out when the div updates is there a way to eliminate this?
    I have try'ed to Google something but could not find anything relative.
    Thanks for a great script thought.
  • John Minnihan
    Screen flicker on any div update is usually the result of a collision of heights of the elements that are changing.

    Be sure that there's adequate space (or at least no overlap) between the div you are updating and any adjacent divs. The flicker is caused when the DOM renders the new placement & has to 'adjust' the overlap.
blog comments powered by Disqus