AJAX Logfile Tailer & Viewer

spyglassRecently 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

See the source here:


Sorry -the working example has been disabled due to abuse. Too many people or bots were hitting it with hundreds of requests a minute.

Open that page (↑) in a new window, follow the instructions and view the source.

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


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 = "https://freepository.com/ajax-logtail-viewer/ajax-logtail.php";
request.open("GET", url, true);
request.onreadystatechange = updatePage;

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

function stopTail() {
var pause = "The log viewer has been paused. To begin viewing again, click the Start Viewer button.\n";
logDiv = document.getElementById("log");
var newNode=document.createTextNode(pause);

function updatePage() {
if (request.readyState == 4) {
if (request.status == 200) {
var currentLogValue = request.responseText.split("\n");
logDiv = document.getElementById("log");
var logLine = ' ';
for (i=0; i < currentLogValue.length - 1; i++) {
logLine += currentLogValue[i] + "
} 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:



<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>

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

function createRequest() {
 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!");
 } else {
   return request;

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:


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 of the timer variable passed to the getLog() function from startTail() -a larger number makes the log viewer refresh less frequently. The value shown (1000) makes the div update about once per second.

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.

Update from Fred in the comments:   “Your script don’t seem to work in IE. I tried the suggestions of using NO-CACHE but that was not the answer. Your working example also does not work in IE. The real answer seems to be in the logtail.js file. The GET needs to be changed to a POST and everything fell into place for both FF and IE for me.

Here’s the change:
request.open(“POST“, url, true);”

Tags: , , ,

Reblog this post [with Zemanta]

John Minnihan

Founder of Freepository

  • http://www.facebook.com/profile.php?id=1028325785 Matt Ackerman

    After debugging this for awhile, you have a typo:

     Line: 41
    var currentLogValue = request1.responseText.split(“n”);

    should be:
    var currentLogValue = request.responseText.split(“n”);

    • http://freepository.com John Minnihan

      Whoops!  Another old cut + paste error… thanks for catching!   Fixed.

      Fortunately, the example has correct, functioning code.

  • http://twitter.com/julio_oa Julio Olivares

    Thanks! easy, clean and fast :D

  • MAC Man

    Anyway to create the start stop button as ONE Toggle ?

  • MAC Man

    I’ve got this working and it works well. I’ve added : fwrite($f,$outputline.”n”); which writes the output to a new log file.
    The issue I have is I end up with multiple lines the same. Any way to stop that from happening ?

    • http://freepository.com John Minnihan

      If you are successfully writing lines to the new log file but are writing the same line over + over, this means that you aren’t exiting the loop (assuming a foreach or similar) to obtain a new line of data before writing it to the new log file.

      Wherever you are grabbing the next line of output + setting it to a var for the subsequent write, ensure that that var gets updated (refreshed with a real new line of log data) again before you write it to the new file. This likely means you’ll move your write operation out of that ‘foreach’ or however you have implemented it.

      • MAC Man

        Thanks. I use foreach($output as $outputline) { to loop through the tail results and then that is echo’d back to my DIV. I also fwrite it to the log file.
        I think that may be an issue with tail return the same lines if the log hasn’t updated. using tail -n 100 returns the last 100 lines, regardless of the log file updating.
        Not sure how to get around that..

  • MAC Man

    I’ve been looking at this : https://github.com/ukhas/js-logtail
    Not as nice as your solution, but I like the idea it only updates the page with the differences in the file between each check, and doesn’t use tail.
    Could your script make use of that ?

    • http://freepository.com John Minnihan

      I’d step back and rethink what you’re trying to accomplish.

      If you just need an up-to-date copy of a log file somewhere on disk, why not handle that inside the config of whatever system is generating the logfile? Just add another logger or whatever.

  • Pingback: Tailing Log File and Write results to new file - PHP Solutions - Developers Q & A

  • Pingback: Live Apache Log Viewer? - Just just easy answers

  • Pingback: Tailing Log File and Write results to new file | Technology & Programming


    I am very new with AJAX and I don’t know how to handle with all those files. Could you zip a folder with the projetc working and send the link for download? Thanks

  • thisisbazz

    I LOVE IT!

  • Pingback: Tail -f realtime log via javascript / jquery - PHP Solutions - Developers Q & A