2 # helper tool to make gnunet logs more readable
3 # try 'gnunet-logread -h' for usage
7 my $DEFAULT_SOCKET = '/tmp/gnunet-logread-ipc.sock';
9 print STDERR <<X if -t STDIN and $#ARGV == -1;
10 *** For a usage message, try '$0 -h'.
11 *** For documentation, try 'perldoc $0'.
12 *** Listening for GNUNET_log events on STDIN. Type CTRL-D to terminate.
17 my (%opts, $name, $ipc, $msg_level, $msg_regex);
18 getopts ('i:x:n:s:L:m:fhq', \%opts);
20 use Pod::Usage qw( pod2usage );
21 die pod2usage if $opts{h};
25 use Term::ANSIColor qw(:constants :pushpop);
26 $Term::ANSIColor::AUTOLOCAL = 1;
28 my %levels = ( NONE => 0, ERROR => 1, WARNING => 2, INFO => 4, DEBUG => 8 );
30 # Message type numbers to names
32 my $prefix = $ENV{GNUNET_PREFIX} || '/usr';
33 my $filename = "$prefix/include/gnunet/gnunet_protocols.h";
34 $ipc = $opts{s} || $DEFAULT_SOCKET;
36 if (open HEADER, $filename)
40 $msgtypes{$2} = $1 if /^\s*#define\s+GNUNET_MESSAGE_TYPE_(\w+)\s+(\d+)/i;
45 Could not read $filename for message codes:
47 Please provide a \$GNUNET_PREFIX environment variable to replace "/usr".
48 Try also '$0 -h' for help.
53 die "You can't read and write the socket at the same time"
54 if exists $opts{f} and exists $opts{n};
56 if ((exists $opts{n} or exists $opts{f}) and not -r $ipc) {
58 die "Could not mkfifo $ipc: $!" unless mkfifo $ipc, 0600;
59 system('chgrp', 'gnunet', $ipc);
60 die "Could not chgrp $ipc to 'gnunet': $!" if $!;
62 die "Could not chmod $ipc to allow gnunet group writes: $!" if $!;
65 if (exists $opts{n}) {
67 $msg_level = $opts{L} && exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
68 $msg_regex = $opts{m};
69 print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
70 open O, '>', $ipc or die "Cannot write to $ipc: $!";
73 if (exists $opts{f}) {
74 open(I, $ipc) or die "Cannot read from $ipc: $!";
86 my ($time, $type, $size, $from, $to, $level, $msg);
87 if (($time, $type, $size, $from, $to) =
88 /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)\ util-client-.*\b
89 (?: Received | Transmitting )\ message \b.*?\b
90 type \s+ (\d+) \b.*?\b
91 size \s+ (\d+) \b.*?\b
97 my ($time, $type, $size, $from, $to) = ($1, $2, $3,
98 $4 || $name, $5 || $name);
99 my $msg = exists $msgtypes{$type} ? $msgtypes{$type} : $type;
101 print O "$time\t$from -> $to\t$msg ($size)\n";
105 if (($time, $level, $msg) =
106 /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)
107 \s+\S+\s+(\S+)\s+(.+)/x
108 and (exists $levels{$level}
109 && $levels{$level} <= $msg_level
110 && (!defined $msg_regex || $msg =~ /$msg_regex/i)))
112 print O "$time\t$name\t$level: $msg\n";
115 return if $opts{x} and /$opts{x}/io;
116 return if $opts{i} and not /$opts{i}/io;
118 # Timestamp (e.g. Nov 01 19:36:11-384136)
119 s/^([A-Z][a-z]{2} .[0-9] [0-9:]{8}(?:-[0-9]{6})?)/YELLOW $1/e;
122 s/\b(ERROR )\b/RED $1/ex;
123 s/\b(WARNING)\b/YELLOW $1/ex;
124 s/\b(INFO )\b/GREEN $1/ex;
125 s/\b(DEBUG )\b/BRIGHT_BLACK $1/ex;
128 # TODO: might read the list from $GNUNET_PREFIX/libexec/gnunet/
129 s/\b(multicast|psyc|psycstore|social)\b/BLUE $1/gex;
131 # Add message type names
133 $1 . BRIGHT_CYAN (exists $msgtypes{$2} ? $msgtypes{$2} : 'UNKNOWN') .
137 s/(\s+)([A-Z_]+)( \(\d+\))$/$1 . BRIGHT_CYAN $2 . CYAN $3/e;
148 gnunet-logread - a GNUnet log analyzer, colorizer and aggregator
152 <gnunet-service> |& $0 [<options>]
154 $0 [<options>] [<logfile>]
157 -f Follow input from IPC FIFO socket.
159 Regular screen output options:
160 -i <regex> Include only messages that match <regex>.
161 -x <regex> Exclude all messages that match <regex>.
162 -q Quiet: Do not show usage advice to new users.
164 Options to forward messages to the IPC FIFO socket:
165 -n <component_name> Name of the component we are forwarding messages for.
166 -s </path/to/ipc.sock> Default = $DEFAULT_SOCKET
167 -L <LOGLEVEL> Minimum level of messages to forward:
168 Log levels: NONE, ERROR, WARNING, INFO, DEBUG.
169 -m <regex> Only forward messages matching a regular expression.
171 See 'perldoc gnunet-logread' for a longer explanation.
175 GNUnet debug logs are a tedious read, but given a complex system that we
176 cannot run all parts of in a debugger all the time, some gathering and
177 structuring of events and message passing is useful.
179 At first, this tool simply makes logs easier to read. Both if viewed in
180 real-time or taken from disk. Then it also allows to extract all message
181 passing events from it and forward them to a special process that aggregates
182 all message passing events and therefore helps you make sense of all the
183 inter-process communication (IPC) happening between the various pieces of
184 the GNUnet system beast.
186 That master process is simply an extra gnunet-logread that you run in a
187 separate window and adorn it with the '-f' flag. The submitting processes
188 instead need to be given a '-n' flag. That is because from the GNUnet logs
189 it isn't clear which process events belong to. For example you may be
190 having events taking place in the 'util' subsystem of gnunet-psyc-service
191 just as much as in the 'util' subsystem of gnunet-multicast-service. In
192 order to make sense of them it is necessary to manually add that info. This
193 could be remedied by extending the semantics of the GNUNET_log facility
194 instead, but that is still subject to further consideration.