3 # I have finally got sick of typing something like:
5 # tail -f logs/debug/2014/0623.log | grep -i mdip | grep -vi p[io]ng
7 # Do a tail -f of one of the current day's log files, the default is 'debug' but
8 # one can follow any of the others by putting enough of the directory
9 # as an argument so that it can find it eg:
11 # logf [perl regex] ...
12 # logf sys [perl regex] ...
13 # logf -100 [dir] [perl regex] ...
15 # NOTE: You can have many regexes and they all have to match (an implied '&&')
16 # NOTE: Also you preceed any regex with the '!' character to indicate negation (like "| grep -v regex")
18 # logf udpr - yields all udpr messages
19 # logf \!udpr - yields everything except udpr messages. Note the shell escape character
20 # logf udpr ping - yields udpr ping messages
21 # logf udpr \!p[io]ng - yields all udpr messages that aren't pings
23 # Copyright (c) 2014 Dirk Koopman, Tobit Computer Co Ltd
32 my $me = fileparse($0);
33 my $cwd = fileparse(getcwd);
38 if (@ARGV[0] =~ /^-[\?h]/) {
39 print "usage: $0 [-<count>] [<directory name fragment>] [<regex>]\n";
42 print " $0 -100 cdr\n";
44 print " $0 sys tcp\n";
45 print "\n any regexes are caseless\n\n";
46 print "default: $0 -40 debug\n";
51 my $lines = shift if ($ARGV[0] =~ /\-\d+/);
54 my $sort = shift || "debug";
58 opendir(my $dh, $base) or die "cannot open log directory '$base' ($!)";
59 @dirs = grep {!/^\./} readdir($dh);
63 my ($dir) = grep {/^$sort/} @dirs;
67 @pattern = ($sort, @ARGV);
71 my $s = IO::Select->new;
76 $SIG{TERM} = $SIG{INT} = sub {++$end};
80 my ($dd,$mm,$yy) = (gmtime)[3,4,5];
84 my $fn = sprintf "$base/$dir/%04d/%02d%02d", $yy, $mm, $dd;
87 } elsif (-e "$fn.csv") {
91 print "Waiting for $fn to appear...\n";
101 # open the file, seek to the end, then seek backward from the end a bit and start reading
102 # but ignore the first line 'cos it will be incomplete.
103 open I, $fn or die "cannot open $fn ($!)\n";
104 my $pos = sysseek(I, 0, 2);
105 if ($pos <= int(abs($lines * 80))) {
108 sysseek(I, $pos + ($lines * 80), 0); # remember lines is (-)ve
116 my $r = sysread(I, $l, 4096);
117 if (defined $r && length $l) {
118 my @lines = split /\cM?\cJ/, $l;
119 foreach my $s (@lines) {
131 if (wait_for_stdin(0.1)) {
133 print $state ? "\nRunning..." : "\nStopped...";
138 # move onto the next file if we roll over midnight
139 my ($d) = (gmtime)[3];
151 foreach my $p (@pattern) {
153 my $r = substr $p, 1;
154 last if $_[0] =~ m{$r}i;
156 last unless $_[0] =~ m{$p}i;
160 return $count == @pattern;
166 if ($s->can_read($t)) {