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;
}