123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- #!@PERLEXE@
- # helper tool to make gnunet logs more readable
- # try 'gnunet-logread -h' for usage
- use strict;
- use warnings;
- my $DEFAULT_SOCKET = '/tmp/gnunet-logread-ipc.sock';
- print STDERR <<X if -t STDIN and $#ARGV == -1;
- *** For a usage message, try '$0 -h'.
- *** For documentation, try 'perldoc $0'.
- *** Listening for GNUNET_log events on STDIN. Type CTRL-D to terminate.
- X
- use Getopt::Std;
- my (%opts, $name, $ipc, $msg_level, $msg_regex);
- getopts ('i:x:n:s:L:m:fhq', \%opts);
- use Pod::Usage qw( pod2usage );
- die pod2usage if $opts{h};
- use POSIX qw(mkfifo);
- use Term::ANSIColor qw(:constants :pushpop);
- $Term::ANSIColor::AUTOLOCAL = 1;
- my %levels = ( NONE => 0, ERROR => 1, WARNING => 2, INFO => 4, DEBUG => 8 );
- # Message type numbers to names
- my %msgtypes;
- my $prefix = $ENV{GNUNET_PREFIX} || '@SUBSTPREFIX@';
- my $filename = "$prefix/include/gnunet/gnunet_protocols.h";
- $ipc = $opts{s} || $DEFAULT_SOCKET;
- if (open HEADER, $filename)
- {
- while (<HEADER>)
- {
- $msgtypes{$2} = $1 if /^\s*#define\s+GNUNET_MESSAGE_TYPE_(\w+)\s+(\d+)/i;
- }
- close HEADER;
- } else {
- warn <<X;
- Could not read $filename for message codes:
- $!.
- Please provide a \$GNUNET_PREFIX environment variable to replace "/usr".
- Try also '$0 -h' for help.
- X
- }
- die "You can't read and write the socket at the same time"
- if exists $opts{f} and exists $opts{n};
- if ((exists $opts{n} or exists $opts{f}) and not -r $ipc) {
- undef $!;
- die "Could not mkfifo $ipc: $!" unless mkfifo $ipc, 0600;
- system('chgrp', 'gnunet', $ipc);
- die "Could not chgrp $ipc to 'gnunet': $!" if $!;
- chmod 0660, $ipc;
- die "Could not chmod $ipc to allow gnunet group writes: $!" if $!;
- }
- if (exists $opts{n}) {
- $name = $opts{n};
- $msg_level = $opts{L} && exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
- $msg_regex = $opts{m};
- print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
- open O, '>', $ipc or die "Cannot write to $ipc: $!";
- }
- if (exists $opts{f}) {
- open(I, $ipc) or die "Cannot read from $ipc: $!";
- &perform while <I>;
- close I;
- } else {
- &perform while <<>>;
- }
- fileno O and close O;
- exit;
- sub perform {
- if (fileno O) {
- my ($time, $type, $size, $from, $to, $level, $msg);
- if (($time, $type, $size, $from, $to) =
- /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)\ util-client-.*\b
- (?: Received | Transmitting )\ message \b.*?\b
- type \s+ (\d+) \b.*?\b
- size \s+ (\d+) \b.*?\b
- (?: from \s+ (\S+)
- | to \s+ (\S+) ) /x)
- {
- $from ||= $name;
- $to ||= $name;
- my ($time, $type, $size, $from, $to) = ($1, $2, $3,
- $4 || $name, $5 || $name);
- my $msg = exists $msgtypes{$type} ? $msgtypes{$type} : $type;
- my $ofh = select O;
- print O "$time\t$from -> $to\t$msg ($size)\n";
- $| = 1;
- select $ofh;
- }
- if (($time, $level, $msg) =
- /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)
- \s+\S+\s+(\S+)\s+(.+)/x
- and (exists $levels{$level}
- && $levels{$level} <= $msg_level
- && (!defined $msg_regex || $msg =~ /$msg_regex/i)))
- {
- print O "$time\t$name\t$level: $msg\n";
- }
- }
- return if $opts{x} and /$opts{x}/io;
- return if $opts{i} and not /$opts{i}/io;
- # Timestamp (e.g. Nov 01 19:36:11-384136)
- s/^([A-Z][a-z]{2} .[0-9] [0-9:]{8}(?:-[0-9]{6})?)/YELLOW $1/e;
- # Log levels
- s/\b(ERROR )\b/RED $1/ex;
- s/\b(WARNING)\b/YELLOW $1/ex;
- s/\b(INFO )\b/GREEN $1/ex;
- s/\b(DEBUG )\b/BRIGHT_BLACK $1/ex;
- # Service names
- # TODO: might read the list from $GNUNET_PREFIX/libexec/gnunet/
- s/\b(multicast|psyc|psycstore|social)\b/BLUE $1/gex;
- # Add message type names
- s/(\s+type\s+)(\d+)/
- $1 . BRIGHT_CYAN (exists $msgtypes{$2} ? $msgtypes{$2} : 'UNKNOWN') .
- CYAN " ($2)"/gei;
- # logread-ipc output
- s/(\s+)([A-Z_]+)( \(\d+\))$/$1 . BRIGHT_CYAN $2 . CYAN $3/e;
- print;
- }
- __END__
- =pod
- =head1 NAME
- gnunet-logread - a GNUnet log analyzer, colorizer and aggregator
- =head1 SYNOPSIS
- <gnunet-service> |& $0 [<options>]
- or
- $0 [<options>] [<logfile>]
- Options:
- -f Follow input from IPC FIFO socket.
- Regular screen output options:
- -i <regex> Include only messages that match <regex>.
- -x <regex> Exclude all messages that match <regex>.
- -q Quiet: Do not show usage advice to new users.
- Options to forward messages to the IPC FIFO socket:
- -n <component_name> Name of the component we are forwarding messages for.
- -s </path/to/ipc.sock> Default = $DEFAULT_SOCKET
- -L <LOGLEVEL> Minimum level of messages to forward:
- Log levels: NONE, ERROR, WARNING, INFO, DEBUG.
- -m <regex> Only forward messages matching a regular expression.
- See 'perldoc gnunet-logread' for a longer explanation.
- =head1 MOTIVATION
- GNUnet debug logs are a tedious read, but given a complex system that we
- cannot run all parts of in a debugger all the time, some gathering and
- structuring of events and message passing is useful.
- At first, this tool simply makes logs easier to read. Both if viewed in
- real-time or taken from disk. Then it also allows to extract all message
- passing events from it and forward them to a special process that aggregates
- all message passing events and therefore helps you make sense of all the
- inter-process communication (IPC) happening between the various pieces of
- the GNUnet system beast.
- That master process is simply an extra gnunet-logread that you run in a
- separate window and adorn it with the '-f' flag. The submitting processes
- instead need to be given a '-n' flag. That is because from the GNUnet logs
- it isn't clear which process events belong to. For example you may be
- having events taking place in the 'util' subsystem of gnunet-psyc-service
- just as much as in the 'util' subsystem of gnunet-multicast-service. In
- order to make sense of them it is necessary to manually add that info. This
- could be remedied by extending the semantics of the GNUNET_log facility
- instead, but that is still subject to further consideration.
- =head1 AUTHORS
- tg & lynX
|