On Tue, 2002-06-04 at 14:49, Randy.Dunlap wrote: > On Tue, 4 Jun 2002, Marc Britten wrote:
> | helps keep the noise level down when scanning large logs. > | > | I'll post it if anyone is interested. > > Yes, please do. logparse.pl -? to get a rundown, you still need to pipe it through less or more or something
#!/usr/bin/perl -w use strict; use Getopt::Std; # Global variable for line info to avoid passing it all around my $LineNo; # Line number in log file my $LineTime; # Time elapsed when this line was written my $Line; # Rest of line my $PeekFlag = 0; # Lookahead flag (ugh!) my $UrbTime = 0; # Time elapsed when this URB was sent my $LastUrbTime = 0; # Time elapsed when previous URB was sent my $FreeStyle = 0; # Allow lines with no obvious timestamp or line tag my $LastVendor= ''; # Last vendor request my %UrbTypeMap = ( 'URB_FUNCTION_CONTROL_TRANSFER' => 'Control Transfer', 'URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE' => 'Get Descriptor', 'URB_FUNCTION_SELECT_CONFIGURATION' => 'Select Config', 'URB_FUNCTION_VENDOR_INTERFACE' => 'Vendor I/F', ); ############################################################################# # Argument processing my %Opt; getopts( 'qstv', \%Opt ) or Usage(); my $Quiet = $Opt{'q'}; # Very quiet output my $Verbose = $Opt{'v'}; # Verbose output my $ShowSetup = $Opt{'s'}; # Show setup packet data too my $ShowTime = $Opt{'t'}; # Show time information ############################################################################# # Main loop while( PeekLine() ) { if( $Line =~ /^>>>/ ) { ParseOutgoing(); } elsif( $Line =~ /^<<</ ) { ParseIncoming(); } else { print "State error: Unexpected line '$Line' at $LineNo !\n"; ReadLine(); } } print "Done.\n"; exit 0; ############################################################################# sub ParseOutgoing { my $UrbDir = '->'; my ( $UrbId, $UrbType ); # Read and parse the URB direction & number header ReadLine() or die "Read error\n"; if( $Line =~ />> +URB (\d+) going down/ ) { $UrbId = $1; # Save the ID number # Read and parse the URB type ReadLine() or die "Read error\n"; if( $Line =~ /^-- ?(\S+):/ ) { $UrbType = $1; } else { die "State error: Unexpected line '$Line' at $LineNo !\n"; } # Time this outgoing URB as now, save the previous time $LastUrbTime = $UrbTime; $UrbTime = $LineTime; # Print time info if desired if( $ShowTime ) { printf "+ %.3f (%.3f)\n", $UrbTime, $UrbTime - $LastUrbTime; } ReadUrb( $UrbDir, $UrbId, $UrbType ); } else { die "State error: Unexpected line '$Line' at $LineNo !\n"; } } sub ParseIncoming { my $UrbDir = '<-'; my ( $UrbId, $UrbType ); # Read and parse the URB direction & number header ReadLine() or die "Read error\n"; if( $Line =~ /<< +URB (\d+) coming back/ ) { $UrbId = $1; # Save the ID number # Read and parse the URB type ReadLine() or die "Read error\n"; if( $Line =~ /^-- ?(\S+):/ ) { $UrbType = $1; } else { die "State error: Unexpected line '$Line' at $LineNo !\n"; } ReadUrb( $UrbDir, $UrbId, $UrbType ); } else { die "State error: Unexpected line '$Line' at $LineNo !\n"; } } sub ReadUrb { my( $UrbDir, $UrbId, $UrbType ) = @_; my %Params; my %TerseParams; my $Data; while( PeekLine() ) { # Handle 'key = value' lines; if( $Line =~ /^(.*\S)\s*=\s+(.*)/ ) { my $key = $1; my $value = $2; $Params{$key} = $value; # Strip off flag explanations etc for terse version if( $value =~ /^[0-9a-f]+ \(/ ) { $value =~ s/ .*//; } if( $value =~ /^00+/ ) { $value =~ s/^00+/0/; } $TerseParams{$key} = $value; } # Handle hex data (eg transfers) elsif( $Line =~ /^([0-9a-f ]+)$/ ) { if( $Data ) { $Data = "$Data $Line"; } else { $Data = $Line; } } # Anything else must be the end of the URB data else { last; # Break out of the loop, ie cleanup and return } # We only peeked at the line... Now read it so the next peek gets the # next one ReadLine() or die "Read error!\n"; } # Remap URB type name to something nicer if we can my $TypeName = $UrbType; if( $UrbTypeMap{$TypeName} ) { $TypeName = $UrbTypeMap{$TypeName}; } if( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) { # Save vendor IDs as we print them out $LastVendor = $TerseParams{'Request'}; # Put a seperator before request 0x80's to seperate things a bit if( $LastVendor eq '80' ) { print "----------------------------------------------\n"; } } # Decide whether or not to print anything my $DoPrint = 1; if( $Quiet && $LastVendor ) { if( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) { if( ($LastVendor eq '01') || ($LastVendor eq '81' )) { $DoPrint = 0; } } if( $UrbType eq 'URB_FUNCTION_CONTROL_TRANSFER' ) { if( ($LastVendor eq '01') || ($LastVendor eq '80' )) { $DoPrint = 0; } } } if ( $DoPrint ) { # Start of line is common print "$UrbDir $UrbId $TypeName: "; if ( $UrbType eq 'URB_FUNCTION_CONTROL_TRANSFER' ) { print "Buflen=$TerseParams{'TransferBufferLength'} "; unless( $Quiet ) { print "Flags=$TerseParams{'TransferFlags'} "; print "Pipe=$TerseParams{'PipeHandle'} "; } } elsif ( $UrbType eq 'URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE' ) { print "Index=$TerseParams{'Index'} "; print "Type=$TerseParams{'DescriptorType'} "; print "Lang=$TerseParams{'LanguageId'} "; } elsif ( $UrbType eq 'URB_FUNCTION_SELECT_CONFIGURATION' ) { # Nothing here yet :) } elsif ( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) { print "Req=$TerseParams{'Request'} "; unless( $Quiet ) { print "Value=$TerseParams{'Value'} "; print "Index=$TerseParams{'Index'} "; print "Res Bits=$TerseParams{'RequestTypeReservedBits'} "; print "Pipe=$TerseParams{'PipeHandle'} " if( $Params{'PipeHandle'}); } } print "\n"; # Hexdump any setup packets if ( $ShowSetup && $Params{'SetupPacket'} ) { HexDump( " Setup: ", 8, $Params{'SetupPacket'}, 0 ); } # Hexdump any data transferred if ( $Data ) { HexDump( " ", 16, $Data, 1 ); } # In verbose mode print out all the key/values if ( $Verbose ) { foreach my $k (sort keys %Params) { print " $k = $Params{$k}\n"; } print "------------------\n" } if( $UrbDir eq '<-' ) { print "\n"; # Extra blank line for readbility } } # else { # print "--\n"; # } } ############################################################################# # ReadLine() - Read the next line from the file, skipping cruft and tidying # up. sub ReadLine { # If some function peeked ahead, we don't need to actually read the line if( $PeekFlag ) { $PeekFlag = 0; return 1; } while( <> ) { # split out the line number and time fields if( /^(\d+)\s+([0-9.]+)\s+(.*)$/ ) { # "old" usbsnoopy format $LineNo = $1; $LineTime = $2; $Line = $3; $Line =~ s/ : / = /g; # Convert for easier parsing later } elsif( /^\[(\d+) ms\] (.*)$/ ) { # 'new' usbsnoop format $LineTime = $1; $Line = $2; if( $LineNo ) { # Could line numbers ourself $LineNo++; } else { $LineNo = 1; # Count line number ourself $FreeStyle = 1; # Allow 'freestyle' lines } } elsif( $FreeStyle ) { s/^\s*//; s/^[0-9a-f]+: //; # Nasty hack to get rid of markers in hex data $Line = $_; if( $Line =~ /^SetupPacket/ ) { # Even nastier hack for the way setup packets are dumped my $t = <>; if( $t ) { $t =~ s/^\s*//; $t =~ s/\s+$//; $t =~ s/^[0-9a-f]+: //; $Line = "$Line $t"; } } $LineNo++; } else { die "Parse error!"; } next unless $Line; # SKIP blank lines $Line =~ s/^\s*//; # Trim leading whitespace $Line =~ s/\s+$//; # Trim trailing whitespace next if( $Line =~ /^UsbSnoop/ ); # Skip UsbSnoop internal stuff next if( $Line =~ /^fido=/ ); next if( $Line =~ /^fdo=/ ); next if( $Line =~ /^pdx=/ ); next if( $Line =~ /^\d+:\s*$/ ); # Skip hexdump 'count' lines #print "$LineNo/$LineTime '$Line'\n"; return 1; } $Line = undef; return undef; } ############################################################################# # PeekLine() - Peek at the next line, but leave it available for reading. # makes the parsing mess a bit simpler. NB This overwrite the global $Line # etc variables. sub PeekLine { my $result = 1; # If we already peeked we don't need to peek again if( $PeekFlag ) { # Handle the case where a previous peek found EOF $result = undef unless $Line; } else { $result = ReadLine(); $PeekFlag = 1; } return $result; } sub HexDump { my ($prefix, $linemax, $str, $bool) = @_; my @bytes = split( / /, $str ); my $offset = 0; my $size = $#bytes + 1; #print "** $str\n"; while( $size > 0 ) { my $rowsize = ($size > $linemax ) ? $linemax : $size; printf "%s%04x: ", $prefix, $offset; my $i; for( $i = 0; $i < $rowsize; $i++ ) { print "$bytes[$i + $offset] "; } for( ; $i < $linemax; $i++ ) { print " "; } print " "; if($bool) { for( $i = 0; $i < $rowsize; $i++ ) { my $c = '.'; my $b = $bytes[$i + $offset]; if( $b ) { $b = hex $b; # Convert to decimal if( $b >= 32 && $b < 127 ) { $c = chr $b; } } print $c; } } print "\n"; $size -= $rowsize; $offset += $rowsize; } } ############################################################################# sub Usage { print<<EOS; logparse - Try to simplify USBSnoopy logs Usage: logparse [opts] <logfile>\n Options include:- -v Verbose output -q Be extra quiet -s Show setup packets too -t Show packet times too EOS exit 1; }