Improved: select the number of lines to show.
authorHeiko Schlittermann <hs@schlittermann.de>
Tue, 27 Jan 2009 22:30:02 +0100
changeset 4 47d496816ba7
parent 3 a00ff9ea5ad6
child 5 dd3de44e993a
Improved: select the number of lines to show. Added Manpage and Help.
hlog
--- a/hlog	Tue Jan 27 21:28:55 2009 +0100
+++ b/hlog	Tue Jan 27 22:30:02 2009 +0100
@@ -24,9 +24,10 @@
 use IO::Socket::INET;
 use Pod::Usage;
 
-my $opt_addr = "0.0.0.0";
-my $opt_port = 8080;
-my $logfile  = "hlog.log";
+my $opt_addr  = "0.0.0.0";
+my $opt_port  = 8080;
+my $opt_lines = 10;
+my $logfile   = "hlog.log";
 my $FILE;
 
 sub handle_request($);
@@ -37,10 +38,14 @@
 MAIN: {
 
     GetOptions(
-        "addr=s" => \$opt_addr,
-        "port=i" => \$opt_port,
+        "addr=s"  => \$opt_addr,
+        "port=i"  => \$opt_port,
+        "lines=i" => \$opt_lines,
+	"help" => sub { pod2usage(-verbose => 1, -exitval => 0) },
+	"man" => sub { pod2usage(-verbose => 2, -exitval => 0) },
     ) or pod2usage();
 
+
     open(LOG, ">>$logfile");
     print LOG localtime() . " started\n";
 
@@ -57,12 +62,13 @@
     warn "listener $opt_addr:$opt_port\n";
     while (my $client = $listener->accept) {
 
-        print LOG $_ = localtime()
+        print LOG $_ =
+            localtime()
           . " access from "
           . $client->peerhost . ":"
           . $client->peerport . "\n";
 
-	warn $_;
+        warn $_;
 
         my $pid = fork();
         die "Can't fork: $!\n" if not defined $pid;
@@ -81,7 +87,7 @@
     local $_ = <$client>;
 
     # should be HTTP/x.x
-    if (not s/HTTP\/\S+\s*$//) {
+    if (not s/\s+HTTP\/\S+\s*$//) {
         $client->print(bad_request);
         return;
     }
@@ -91,18 +97,66 @@
         $client->print(http "400 Bad Request" => bad_request);
     }
 
-    open(my $file, $FILE);
+    my $lines = /(\d+)$/ ? $1 : $opt_lines;
+
+    # read the header(s) and discard
+    while (<$client>) { last if /^\s*$/ }
+
+    # number of lines to show
 
-    $client->print(http "200 OK" => join "", <<__EOF, <$file>);
+    my %file = analyze($FILE);
+    if (!%file) {
+        $client->print(http "500 internal error");
+        print LOG $@;
+        return;
+    }
+
+    seek($file{fh}, -($lines + 1) * $file{avglen}, 2);
+    $file{fh}->getline;
+
+    $client->print(http "200 OK" => join "", <<__EOF, $file{fh}->getlines);
 # Proof of concept ;-)
 # see https://keller.schlittermann.de/hg/hlog
 #
-# FILE: $FILE 
+# FILE:    @{[sprintf "%s", $file{name}]}
+# LENGTH:  @{[sprintf "%5d", $file{size}]}
+# LINES:   @{[sprintf "%5d approx", $file{lines}]}
+# LENGTH:  @{[sprintf "%5d approx", $file{avglen}]}
+# DISPLAY: @{[sprintf "%5d approx", $lines]}
+# 
+# append /<number> to your request to select the number of displayed
+# lines
 #
 __EOF
 
 }
 
+sub analyze($) {
+    my %r;
+    $r{name} = shift;
+    $r{size} = -s $r{name};
+    open($r{fh}, $r{name}) or do {
+        $@ = "Can't open $r{name}: $!\n";
+        return ();
+    };
+
+    if ($r{size} == 0) {
+        $r{lines} = 0;
+    }
+    else {
+        my $s;
+        while (defined($_ = $r{fh}->getline)) {
+            $s += length;
+            last if $. == 100;
+        }
+        $r{avglen} = $s / $.;
+        $r{lines}  = int($r{size} / $r{avglen});
+    }
+
+    seek($r{fh}, 0, 0);
+    return %r;
+}
+
 sub http($@) {
     my $code = shift;
     my $date = date1123();
@@ -149,11 +203,30 @@
 
 =head1 SYNOPSIS
     
-    hlog [-p|--port port] [-a|--address address] file
+    hlog [--lines n] [-p|--port port] [-a|--address address] file
+    hlog [-h|--help] [-m|--man]
 
 =head1 DESCRIPTION
 
 This script should run as a server providing access to 
 the last lines of a logfile. It should understand basic HTTP/1.x.
 
+=head1 OPTIONS
+
+=over
+
+=item B<-p>|B<--port> I<port>
+
+The port to listen on. (default: 8080)
+
+=item B<-a>|B<--address> I<address>
+
+The address to listen on. (default: 0.0.0.0)
+
+=item B<--lines> I<lines>
+
+The number of lines to show. (default: 10)
+
+=back
+
 =cut