Tweaked class comments in containerPanel
[ganymede.git] / scripts / logscan.pl.template
blob91d3878a42694ca3d4403bc593bb6a100bc7ddf4
1 #!/usr/bin/perl
3 # This script is designed to assist the Ganymede server by quickly
4 # scanning through the Ganymede log file and printing out only those
5 # lines which the Ganymede server is seeking to retrieve.
7 # The Ganymede server is not very efficient at doing this, and by
8 # using an external filtering program the Ganymede server can provide
9 # object history from its log file much much more quickly than if the
10 # server had to filter out all the irrelevant history details itself
11 # with the current server code.
13 # $Revision$
14 # $Date$
15 # $Name: $
17 # Robbie Sternenberg
18 # robbie@arlut.utexas.edu
20 # Jonathan Abbey
21 # jonabbey@arlut.utexas.edu
23 ############################################################
25 $| = 1;
26 $debug = 0;
28 ##########################################################################
30 # find_arg
31 # input: $token, @args
33 # output: the string argument following the single character
34 # $token.. for instance, if $token is 'f', find_arg will return the
35 # string following -f in the @args list, if it can be found.
37 # if the token can't be found following a dash character, an empty string
38 # will be returned.
41 ##########################################################################
43 sub find_arg {
44 my ($token, @args) = @_;
46 my ($i, $word, $localword, $tokenregexp);
48 $i = 0;
49 $localword = "";
51 $tokenregexp = $token;
52 $tokenregexp =~ s/(\W)/\\$1/g; # backslash escape any special chars
54 while ($i <= $#args) {
55 if ($args[$i] =~ /^-(.*)$/) {
56 $word=$1;
58 if ($word =~ /^$tokenregexp/) {
59 if (length($word)==1) {
60 $localword = $args[($i + 1)];
61 } else {
62 $word =~ /^$tokenregexp(.*)$/;
63 $localword = $1;
66 last;
70 $i++;
73 if ($localword eq "") {
74 $localword = undef;
77 return $localword;
80 ##########################################################################
82 # read_switches
83 # input: $switchlist, @args
85 # The $switchlist string should be a concatenation of the
86 # permissible single-character command line flags.
88 # output: sets flags in the global %switches hash
90 ##########################################################################
92 sub read_switches {
93 my ($switchlist, @args) = @_;
95 my ($i, $word, @switches);
97 $i = 0;
98 $localword = "";
100 while ($i <= $#args && $args[$i] =~ /^-(.*)$/) {
101 $word=$1;
102 $i++;
104 # the switches in the following regexp can accept arguments, so
105 # we'll skip past the next token if we see one of them naked.
107 if ($word =~ /^[ies]/) {
108 if (length($word)==1) {
109 $i++;
111 next;
114 if ($word =~ /(^[$switchlist]+)$/) {
115 @switches= split (//, $1);
116 for $switch (@switches) {
117 $switches{$switch}="-$switch";
119 } else {
120 print "\"$word\" is an invalid command entry!\n\n";
121 oops_usage();
126 ##########################################################################
128 # is_start_of_line
130 # Returns true if FILE is pointing to the first character of a line
131 # (i.e., the character before us is a newline or the start of the file)
133 ##########################################################################
135 sub is_start_of_line {
137 my ($line);
139 my $pos = tell FILE;
141 if ($pos == 0) {
142 return 1;
145 seek(FILE, -1, 1);
146 read(FILE, $line, 1);
148 if ($line eq "\n") {
149 return 1;
152 return 0;
155 ##########################################################################
157 # find_previous_line
159 # This subroutine finds the seek point for the start of the last line
160 # prior to $newpos in FILE
162 ##########################################################################
164 sub find_previous_line {
165 my ($newpos) = @_;
167 $debug && print "find_previous_line($newpos)\n";
169 my ($backpos, $line, $lastfound, $jump);
171 $backpos = $newpos;
172 $jump = -1;
173 $lastfound = -1;
175 # step back 64 bytes at a time from $newpos until we find the
176 # last \n before $newpos
178 while ($lastfound == -1 && $backpos > 0) {
179 $backpos = $backpos - 64;
181 if ($backpos < 0) {
182 $backpos = 0;
185 seek(FILE, $backpos, 0);
187 read(FILE, $line, 64);
189 $jump = -1;
191 do {
192 $lastfound = $jump;
193 $jump = index($line, "\n", $jump + 1);
194 } until ($jump == -1);
197 # and return the location we need to go to
199 return $backpos + $lastfound + 1; # will be 0 on degenerate case
202 ##########################################################################
204 # seek_start_point
206 # This subroutine does a binary search through FILE looking for the
207 # first event after the specified start date.
209 ##########################################################################
211 sub seek_start_point {
212 my ($startdate, $lowpos, $highpos) = @_;
214 my ($pos, $line, $linedate);
216 if ($lowpos == $highpos) {
217 $debug && print "Oops, got stuck";
218 return;
221 $pos = int (($lowpos + $highpos) / 2);
223 seek(FILE, $pos, 0);
225 if (!is_start_of_line()) {
226 $pos = find_previous_line($pos);
227 seek(FILE, $pos, 0);
228 } else {
229 $pos = tell FILE;
232 # read a line for us to check against our target date
234 $line = <FILE>;
236 ($linedate) = split /\|/, $line;
238 # transactions share the same date and we can't use our recursive
239 # algorithm to find the beginning, since we can't differentiate
240 # between lines with the same date. if we have hit on a line that
241 # occurs right on our start time (which is specified with
242 # millisecond accuracy), we'll need to scootch back until we find
243 # the first line that had that date.
245 while ($startdate == $linedate) {
246 $pos = find_previous_line($pos -1);
248 seek FILE, $pos, 0;
250 $line = <FILE>;
252 $debug && print $line;
254 ($linedate) = split /\|/, $line;
256 if (($startdate > $linedate) || ($pos == 0)) {
257 return;
261 if ($startdate < $linedate) {
262 $debug && print "startdate $startdate <= linedate $linedate\n";
264 seek_start_point($startdate, $lowpos, find_previous_line($pos));
265 return;
266 } else {
267 $debug && print "startdate $startdate > linedate $linedate\n";
269 seek_start_point($startdate, tell FILE, $highpos);
270 return;
274 ##########################################################################
276 # oops_usage
278 ##########################################################################
280 sub oops_usage() {
281 print "Usage: $0 [-a] [-l] [-i invid number] [-s start_date in java timecode] [-e end date in java timecode]\n";
282 print "\t-a: Search for admin invids rather than object invids\n";
283 print "\t-l: Only retrieve login/logout type events\n";
284 print "\t-s: Only retrieve events more recent than the start date, which is provided as a Java timecode\n";
285 print "\t-e: Only retrieve events that occur before recent the end date, which is provided as a Java timecode\n";
286 exit 1;
289 ################################################################################
291 $file = "<<LOGFILE>>"; # this will be replaced on install
293 if (@ARGV == 0) {
294 oops_usage();
297 # which field in the log lines are we going to look at for the invid
298 # we're filtering on?
300 $fieldindex = 6;
301 $dologins = 0;
303 # let's figure out our command line options
305 read_switches('al', @ARGV);
307 if (defined $switches{'a'}) {
308 # we're doing an admin invid search, not an object invid search
310 $fieldindex = 3;
313 if (defined $switches{'l'}) {
314 $dologins = 1;
317 $javastartdate = find_arg('s', @ARGV);
318 $debug && print "javastartdate is $javastartdate\n";
320 $javaenddate = find_arg('e', @ARGV);
321 $debug && print "javaenddate is $javaenddate\n";
323 $invid = find_arg('i', @ARGV);
324 $debug && print "invid is $invid\n";
326 if (!defined $invid) {
328 # we didn't get asked for an invid, which may be okay, or it may
329 # mean that we are being called by an earlier version of the
330 # Ganymede server using the old calling sequence, with the invid
331 # being mandatory as the last parameter on our command line.
333 # check for that, using a regexp to recognize what an invid should
334 # look like.
336 $invid = $ARGV[$#ARGV];
338 if ($invid !~ /^[0-9]+:[0-9]+$/) {
339 $invid = undef;
344 # Okay, we've got all of our arguments, now.
346 # If we've got a start date set, we'll want to do a binary
347 # search through the file to find the start of the region we
348 # want to process
351 open FILE, $file || die "Couldn't open $file.\n";
353 if (defined $javastartdate) {
354 ($size) = (stat($file))[7];
355 seek_start_point($javastartdate, 0, $size);
358 while (<FILE>) {
360 # if we're looking for a specific invid, let's see if the line has
361 # invid in it
363 PROCESSLINE: if (!defined $invid || /$invid/) {
365 @fields = split(/\|/);
367 if (defined $javaenddate && $javaenddate < $fields[0]) {
368 close FILE;
369 exit 0;
372 my $token = $fields[2];
374 if ($dologins xor ($token eq "normallogin" ||
375 $token eq "normallogout" ||
376 $token eq "abnormallogout")) {
377 next;
380 if (!(defined $invid) ||
381 ($fields[$fieldindex] =~ /(^|,)$invid(,|$)/) ||
382 ($fields[$fieldindex] =~ /^$invid$/)) {
384 print $_;
386 # we want to show all events in a transaction block, even
387 # the endtransaction events which don't include the object
388 # invids that we are scanning for. So, when we see a
389 # starttransaction, we just print out lines for as long
390 # as we see the transaction id.
392 if (@fields[2] =~ /starttransaction/) {
394 $transaction_label = @fields[5];
396 while (1) {
397 $_ = <FILE>;
399 @fields = split(/\|/);
401 if ($fields[5] eq $transaction_label) {
402 print $_;
403 } else {
404 goto PROCESSLINE;
412 close FILE;
413 exit 0;