logread: no buffering
[oweals/gnunet.git] / contrib / gnunet-logread
1 #!/usr/bin/env perl
2
3 # Usage:
4 #   gnunet-service |& gnunet-logread
5 #   gnunet-logread service.log
6 #
7 # Options:
8 #   -n <component_name>         Name of this component to use for IPC logging.
9 #   -i </path/to/ipc.sock>      Path to IPC logging socket.
10 #  Passing on log messages to IPC socket:
11 #   -L <LOGLEVEL>               Minimum level of messages to pass on.
12 #                               Log levels: NONE, ERROR, WARNING, INFO, DEBUG.
13 #   -m <regex>                  Only pass on messages matching a regular expression.
14
15 use strict;
16 use warnings;
17
18 use Getopt::Std;
19 use Term::ANSIColor qw(:constants :pushpop);
20 $Term::ANSIColor::AUTOLOCAL = 1;
21
22 my (%opts, $name, $ipc, $msg_level, $msg_regex);
23 getopts ('n:i:L:m:', \%opts);
24
25 # Message type numbers to names
26 my %msgtypes;
27 my $prefix = $ENV{GNUNET_PREFIX} || '/usr';
28 my $filename = "$prefix/include/gnunet/gnunet_protocols.h";
29
30 if (open HEADER, $filename)
31 {
32     while (<HEADER>)
33     {
34         $msgtypes{$2} = $1 if /^\s*#define\s+GNUNET_MESSAGE_TYPE_(\w+)\s+(\d+)/i;
35     }
36     close HEADER;
37 }
38 else
39 {
40     warn "$filename: $!, try setting \$GNUNET_PREFIX";
41 }
42
43 my %levels = ( NONE => 0, ERROR => 1, WARNING => 2, INFO => 4, DEBUG => 8 );
44 if (exists $opts{n})
45 {
46     $name = $opts{n};
47     $ipc = $opts{i} || '/tmp/gnunet-logread-ipc.sock';
48     $msg_level = exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
49     $msg_regex = $opts{m};
50     print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
51     open IPC, '>', $ipc or die "$ipc: $!\n";
52 }
53
54 while (<>)
55 {
56     if (fileno IPC) {
57         my ($time, $type, $size, $from, $to, $level, $msg);
58         if (($time, $type, $size, $from, $to) =
59             /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)\ util-.*\b
60              (?: Received | Transmitting )\ message \b.*?\b
61              type \s+ (\d+) \b.*?\b
62              size \s+ (\d+) \b.*?\b
63              (?: from \s+ (\S+)
64                | to   \s+ (\S+) ) /x)
65         {
66             $from ||= $name;
67             $to ||= $name;
68             my ($time, $type, $size, $from, $to) = ($1, $2, $3,
69                                                 $4 || $name, $5 || $name);
70             my $msg = exists $msgtypes{$type} ? $msgtypes{$type} : $type;
71             my $ofh = select IPC;
72             print IPC "$time\t$from -> $to\t$msg ($size)\n";
73             $| = 1;
74             select $ofh;
75         }
76         if (($time, $level, $msg) =
77             /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)
78               \s+\S+\s+(\S+)\s+(.+)/x
79             and (exists $levels{$level}
80                  && $levels{$level} <= $msg_level
81                  && (!defined $msg_regex || $msg =~ /$msg_regex/i)))
82         {
83             print IPC "$time\t$name\t$level: $msg\n";
84         }
85     }
86
87     # Timestamp (e.g. Nov 01 19:36:11-384136)
88     s/^([A-Z][a-z]{2} .[0-9] [0-9:]{8}(?:-[0-9]{6})?)/YELLOW $1/e;
89
90     # Log levels
91     s/\b(ERROR  )\b/RED $1/ex;
92     s/\b(WARNING)\b/YELLOW $1/ex;
93     s/\b(INFO   )\b/GREEN $1/ex;
94     s/\b(DEBUG  )\b/BRIGHT_BLACK $1/ex;
95
96     # Service names
97     # TODO: might read the list from $GNUNET_PREFIX/libexec/gnunet/
98     s/\b(multicast|psyc|psycstore|social)\b/BLUE $1/gex;
99
100     # Add message type names
101     s/(\s+type\s+)(\d+)/
102       $1 . BRIGHT_CYAN (exists $msgtypes{$2} ? $msgtypes{$2} : 'UNKNOWN') .
103       CYAN " ($2)"/gei;
104
105     # logread-ipc output
106     s/(\s+)([A-Z_]+)( \(\d+\))$/$1 . BRIGHT_CYAN $2 . CYAN $3/e;
107
108     print;
109 }
110
111 fileno IPC and close IPC;