# HG changeset patch # User Heiko Schlittermann # Date 1233091802 -3600 # Node ID 47d496816ba7145e58cf463181552efe5fab9c77 # Parent a00ff9ea5ad6c788d4051b14c756c0cb5b245fce Improved: select the number of lines to show. Added Manpage and Help. diff -r a00ff9ea5ad6 -r 47d496816ba7 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 / 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 + +The port to listen on. (default: 8080) + +=item B<-a>|B<--address> I
+ +The address to listen on. (default: 0.0.0.0) + +=item B<--lines> I + +The number of lines to show. (default: 10) + +=back + =cut