Monday, May 3, 2010

tail console output with ajax

I finally worked out how to have ajax tail the output from a server side command/script.

First capture the output of the console/command into a database:
#!/usr/local/bin/perl

use DBI;
use FileHandle;
use IPC::Open2;
$pid = open2(*Reader, *Writer, "tail -f /usr/local/logs/access_log" );
#print Writer "stuff\n";
my $dbh = DBI->connect('dbi:mysql:jpscc:localhost:3306','root','password') or die "Connection Error: $DBI::errstr\n";
while ($got = <Reader>)
{
print $got;
$hdl=$dbh->prepare_cached('INSERT INTO test_t (`line`) VALUES (?)');
$hdl->execute($got);
}


Then the server side cgi-script, in this case I used perl. You can use whatever language you want to achieve the same output. The output is a simple XML output:

#!/usr/bin/env perl
print "Content-type:text/xml\r\n\r\n";
use DBI;

my $dbh = DBI->connect('dbi:mysql:jpscc:localhost:3306','root','password') or die "Connection Error: $DBI::errstr\n";

print <<END;
<?xml version="1.0" encoding="ISO-8859-1"?>
END
$query_string = $ENV{'QUERY_STRING'};
print STDERR "query_string=[$query_string]\n";
my %FORM;
@pairs = split(/&/, $query_string);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);

#Converting Hex to English.
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ tr/+/ /;

$FORM{$name} = $value;
print STDERR "input $name => $value\n";
}

print "<CATALOG>\n";
$hdl=$dbh->prepare_cached('SELECT * from test_t where (idx>'.$FORM{"id"}.')' );
print STDERR 'SELECT * from test_t where (idx>'.$FORM{"id"}.')' ;
$hdl->execute();
my $first=0;
my $last =0;
@age = $hdl->fetchrow_array();
$a = $age[2];
$first = $age[1];
chomp($a);
print "<ID>".$first."</ID>\n";
print "<ARTIST>".$a."</ARTIST>\n";
if ($hdl->rows > 0)
{
while (@age = $hdl->fetchrow_array())
{
#print "$age[0] $age[1] $age[2]\n";
$a = $age[2];
$last=$age[1];
chomp($a);
chomp($last);
print "<ID>".$last."</ID>\n";
print "<ARTIST>".$a."</ARTIST>\n";
}
print "</CATALOG>\n";
# delete if single use, otherwise create a cron cleanup
$hdl=$dbh->prepare_cached('DELETE from test_t where (idx >= '.$first.' and idx <= '.$last.')');
$hdl->execute();
#$dbh->commit;
}


Finally the client script request the lines based on the last line number it got.



Finally the client side. The client requests each line based on the line number:

#!/usr/bin/env perl
print "Content-type:text/html\r\n\r\n";

print <<END;
<html>
<head>
<script type="text/javascript">
var last_idx=0;
var timer_id=0;
b2.disabled = true;
function pause_page()
{
clearTimeout(timer_id);
b1.disabled = false;
b2.disabled = true;
}
function loadXMLDoc()
{
b1.disabled = true;
b2.disabled = false;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}

xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
xmlDoc=xmlhttp.responseXML;
var txt="";
x=xmlDoc.getElementsByTagName("ARTIST");
y1=xmlDoc.getElementsByTagName("ID");
for (i=0;i<x.length;i++)
{
last_idx = y1[i].childNodes[0].nodeValue;
txt=txt + last_idx + " "+ i+" ";
txt=txt + x[i].childNodes[0].nodeValue + " "+ i+"<br />";
//txt=txt + x[i].childNodes[0].nodeValue + "\\n";
}
var x = document.getElementById("myDiv").innerHTML;
x = x + txt;
document.getElementById("myDiv").innerHTML=x;
//document.getElementById("myDiv").innerHTML+=txt;
var objDiv = document.getElementById("myDiv");
objDiv.scrollTop = objDiv.scrollHeight;
}
}
xmlhttp.open("GET","get_lines_5.pl?id="+last_idx+"",true);
xmlhttp.send();
timer_id=setTimeout('loadXMLDoc();',5000) ;

}
</script>
</head>
<body>

<div id="myDiv" style="width: 95%; height: 50%; overflow: auto"><h2>Let AJAX change this text</h2></div>
<button type="button" id="b1" onclick="loadXMLDoc()">Change Content</button>

<button type="button" id="b2" onclick="pause_page()">Pause Content</button>


</body>
</html>
END

No comments: