-fix ftbfs if extractor.h present but libextractor.so missing
[oweals/gnunet.git] / contrib / gnunet-logread
1 #!/usr/bin/env perl
2 # helper tool to make gnunet logs more readable
3 # try 'gnunet-logread -h' for usage
4
5 use strict;
6 use warnings;
7 my $DEFAULT_SOCKET = '/tmp/gnunet-logread-ipc.sock';
8
9 use Getopt::Std;
10 my (%opts, $name, $ipc, $msg_level, $msg_regex);
11 getopts ('i:x:n:s:L:m:fh', \%opts);
12
13 die <<X if $opts{h};
14 Usage:
15         <gnunet-service> |& $0 [<options>]
16     or
17         $0 [<options>] [<logfile>]
18
19 Options:
20     -f                          Follow input from IPC FIFO socket.
21
22    Regular screen output options:
23     -i <regex>                  Include only messages that match <regex>.
24     -x <regex>                  Exclude all messages that match <regex>.
25
26    Options to enable message passing to IPC socket:
27     -n <component_name>         Name of this component to use for IPC logging.
28     -s </path/to/ipc.sock>      Default = $DEFAULT_SOCKET
29     -L <LOGLEVEL>               Minimum level of messages to pass on.
30                                 Log levels: NONE, ERROR, WARNING, INFO, DEBUG.
31     -m <regex>                  Only pass messages matching a regular expression.
32 X
33
34 use POSIX qw(mkfifo);
35
36 use Term::ANSIColor qw(:constants :pushpop);
37 $Term::ANSIColor::AUTOLOCAL = 1;
38
39 my %levels = ( NONE => 0, ERROR => 1, WARNING => 2, INFO => 4, DEBUG => 8 );
40
41 # Message type numbers to names
42 my %msgtypes;
43 my $prefix = $ENV{GNUNET_PREFIX} || '/usr';
44 my $filename = "$prefix/include/gnunet/gnunet_protocols.h";
45 $ipc = $opts{s} || $DEFAULT_SOCKET;
46
47 if (open HEADER, $filename)
48 {
49     while (<HEADER>)
50     {
51         $msgtypes{$2} = $1 if /^\s*#define\s+GNUNET_MESSAGE_TYPE_(\w+)\s+(\d+)/i;
52     }
53     close HEADER;
54 } else {
55     warn <<X;
56 Could not read $filename for message codes:
57         $!.
58 Please provide a \$GNUNET_PREFIX environment variable to replace "/usr".
59 Try also '$0 -h' for help
60
61 X
62 }
63
64 die "You can't read and write the socket at the same time"
65   if exists $opts{f} and exists $opts{n};
66
67 if ((exists $opts{n} or exists $opts{f}) and not -r $ipc) {
68     undef $!;
69     die "Could not mkfifo $ipc: $!" unless mkfifo $ipc, 0600;
70     system('chgrp', 'gnunet', $ipc);
71     die "Could not chgrp $ipc to 'gnunet': $!" if $!;
72     chmod 0660, $ipc;
73     die "Could not chmod $ipc to allow gnunet group writes: $!" if $!;
74 }
75
76 if (exists $opts{n}) {
77     $name = $opts{n};
78     $msg_level = $opts{L} && exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
79     $msg_regex = $opts{m};
80     print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
81     open O, '>', $ipc or die "Cannot write to $ipc: $!";
82 }
83
84 if (exists $opts{f}) {
85     open(I, $ipc) or die "Cannot read from $ipc: $!";
86     &perform while <I>;
87     close I;
88 } else {
89     &perform while <>;
90 }
91 fileno O and close O;
92 exit;
93
94
95 sub perform {
96     if (fileno O) {
97         my ($time, $type, $size, $from, $to, $level, $msg);
98         if (($time, $type, $size, $from, $to) =
99             /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)\ util-.*\b
100              (?: Received | Transmitting )\ message \b.*?\b
101              type \s+ (\d+) \b.*?\b
102              size \s+ (\d+) \b.*?\b
103              (?: from \s+ (\S+)
104                | to   \s+ (\S+) ) /x)
105         {
106             $from ||= $name;
107             $to ||= $name;
108             my ($time, $type, $size, $from, $to) = ($1, $2, $3,
109                                                 $4 || $name, $5 || $name);
110             my $msg = exists $msgtypes{$type} ? $msgtypes{$type} : $type;
111             my $ofh = select O;
112             print O "$time\t$from -> $to\t$msg ($size)\n";
113             $| = 1;
114             select $ofh;
115         }
116         if (($time, $level, $msg) =
117             /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)
118               \s+\S+\s+(\S+)\s+(.+)/x
119             and (exists $levels{$level}
120                  && $levels{$level} <= $msg_level
121                  && (!defined $msg_regex || $msg =~ /$msg_regex/i)))
122         {
123             print O "$time\t$name\t$level: $msg\n";
124         }
125     }
126     return if $opts{x} and /$opts{x}/io;
127     return if $opts{i} and not /$opts{i}/io;
128
129     # Timestamp (e.g. Nov 01 19:36:11-384136)
130     s/^([A-Z][a-z]{2} .[0-9] [0-9:]{8}(?:-[0-9]{6})?)/YELLOW $1/e;
131
132     # Log levels
133     s/\b(ERROR  )\b/RED $1/ex;
134     s/\b(WARNING)\b/YELLOW $1/ex;
135     s/\b(INFO   )\b/GREEN $1/ex;
136     s/\b(DEBUG  )\b/BRIGHT_BLACK $1/ex;
137
138     # Service names
139     # TODO: might read the list from $GNUNET_PREFIX/libexec/gnunet/
140     s/\b(multicast|psyc|psycstore|social)\b/BLUE $1/gex;
141
142     # Add message type names
143     s/(\s+type\s+)(\d+)/
144       $1 . BRIGHT_CYAN (exists $msgtypes{$2} ? $msgtypes{$2} : 'UNKNOWN') .
145       CYAN " ($2)"/gei;
146
147     # logread-ipc output
148     s/(\s+)([A-Z_]+)( \(\d+\))$/$1 . BRIGHT_CYAN $2 . CYAN $3/e;
149
150     print;
151 }
152