gnunet-logread.in 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!@PERLEXE@
  2. # helper tool to make gnunet logs more readable
  3. # try 'gnunet-logread -h' for usage
  4. use strict;
  5. use warnings;
  6. my $DEFAULT_SOCKET = '/tmp/gnunet-logread-ipc.sock';
  7. print STDERR <<X if -t STDIN and $#ARGV == -1;
  8. *** For a usage message, try '$0 -h'.
  9. *** For documentation, try 'perldoc $0'.
  10. *** Listening for GNUNET_log events on STDIN. Type CTRL-D to terminate.
  11. X
  12. use Getopt::Std;
  13. my (%opts, $name, $ipc, $msg_level, $msg_regex);
  14. getopts ('i:x:n:s:L:m:fhq', \%opts);
  15. use Pod::Usage qw( pod2usage );
  16. die pod2usage if $opts{h};
  17. use POSIX qw(mkfifo);
  18. use Term::ANSIColor qw(:constants :pushpop);
  19. $Term::ANSIColor::AUTOLOCAL = 1;
  20. my %levels = ( NONE => 0, ERROR => 1, WARNING => 2, INFO => 4, DEBUG => 8 );
  21. # Message type numbers to names
  22. my %msgtypes;
  23. my $prefix = $ENV{GNUNET_PREFIX} || '@SUBSTPREFIX@';
  24. my $filename = "$prefix/include/gnunet/gnunet_protocols.h";
  25. $ipc = $opts{s} || $DEFAULT_SOCKET;
  26. if (open HEADER, $filename)
  27. {
  28. while (<HEADER>)
  29. {
  30. $msgtypes{$2} = $1 if /^\s*#define\s+GNUNET_MESSAGE_TYPE_(\w+)\s+(\d+)/i;
  31. }
  32. close HEADER;
  33. } else {
  34. warn <<X;
  35. Could not read $filename for message codes:
  36. $!.
  37. Please provide a \$GNUNET_PREFIX environment variable to replace "/usr".
  38. Try also '$0 -h' for help.
  39. X
  40. }
  41. die "You can't read and write the socket at the same time"
  42. if exists $opts{f} and exists $opts{n};
  43. if ((exists $opts{n} or exists $opts{f}) and not -r $ipc) {
  44. undef $!;
  45. die "Could not mkfifo $ipc: $!" unless mkfifo $ipc, 0600;
  46. system('chgrp', 'gnunet', $ipc);
  47. die "Could not chgrp $ipc to 'gnunet': $!" if $!;
  48. chmod 0660, $ipc;
  49. die "Could not chmod $ipc to allow gnunet group writes: $!" if $!;
  50. }
  51. if (exists $opts{n}) {
  52. $name = $opts{n};
  53. $msg_level = $opts{L} && exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
  54. $msg_regex = $opts{m};
  55. print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
  56. open O, '>', $ipc or die "Cannot write to $ipc: $!";
  57. }
  58. if (exists $opts{f}) {
  59. open(I, $ipc) or die "Cannot read from $ipc: $!";
  60. &perform while <I>;
  61. close I;
  62. } else {
  63. &perform while <<>>;
  64. }
  65. fileno O and close O;
  66. exit;
  67. sub perform {
  68. if (fileno O) {
  69. my ($time, $type, $size, $from, $to, $level, $msg);
  70. if (($time, $type, $size, $from, $to) =
  71. /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)\ util-client-.*\b
  72. (?: Received | Transmitting )\ message \b.*?\b
  73. type \s+ (\d+) \b.*?\b
  74. size \s+ (\d+) \b.*?\b
  75. (?: from \s+ (\S+)
  76. | to \s+ (\S+) ) /x)
  77. {
  78. $from ||= $name;
  79. $to ||= $name;
  80. my ($time, $type, $size, $from, $to) = ($1, $2, $3,
  81. $4 || $name, $5 || $name);
  82. my $msg = exists $msgtypes{$type} ? $msgtypes{$type} : $type;
  83. my $ofh = select O;
  84. print O "$time\t$from -> $to\t$msg ($size)\n";
  85. $| = 1;
  86. select $ofh;
  87. }
  88. if (($time, $level, $msg) =
  89. /^([A-Z][a-z]{2}\ .[0-9]\ [0-9:]{8}(?:-[0-9]{6})?)
  90. \s+\S+\s+(\S+)\s+(.+)/x
  91. and (exists $levels{$level}
  92. && $levels{$level} <= $msg_level
  93. && (!defined $msg_regex || $msg =~ /$msg_regex/i)))
  94. {
  95. print O "$time\t$name\t$level: $msg\n";
  96. }
  97. }
  98. return if $opts{x} and /$opts{x}/io;
  99. return if $opts{i} and not /$opts{i}/io;
  100. # Timestamp (e.g. Nov 01 19:36:11-384136)
  101. s/^([A-Z][a-z]{2} .[0-9] [0-9:]{8}(?:-[0-9]{6})?)/YELLOW $1/e;
  102. # Log levels
  103. s/\b(ERROR )\b/RED $1/ex;
  104. s/\b(WARNING)\b/YELLOW $1/ex;
  105. s/\b(INFO )\b/GREEN $1/ex;
  106. s/\b(DEBUG )\b/BRIGHT_BLACK $1/ex;
  107. # Service names
  108. # TODO: might read the list from $GNUNET_PREFIX/libexec/gnunet/
  109. s/\b(multicast|psyc|psycstore|social)\b/BLUE $1/gex;
  110. # Add message type names
  111. s/(\s+type\s+)(\d+)/
  112. $1 . BRIGHT_CYAN (exists $msgtypes{$2} ? $msgtypes{$2} : 'UNKNOWN') .
  113. CYAN " ($2)"/gei;
  114. # logread-ipc output
  115. s/(\s+)([A-Z_]+)( \(\d+\))$/$1 . BRIGHT_CYAN $2 . CYAN $3/e;
  116. print;
  117. }
  118. __END__
  119. =pod
  120. =head1 NAME
  121. gnunet-logread - a GNUnet log analyzer, colorizer and aggregator
  122. =head1 SYNOPSIS
  123. <gnunet-service> |& $0 [<options>]
  124. or
  125. $0 [<options>] [<logfile>]
  126. Options:
  127. -f Follow input from IPC FIFO socket.
  128. Regular screen output options:
  129. -i <regex> Include only messages that match <regex>.
  130. -x <regex> Exclude all messages that match <regex>.
  131. -q Quiet: Do not show usage advice to new users.
  132. Options to forward messages to the IPC FIFO socket:
  133. -n <component_name> Name of the component we are forwarding messages for.
  134. -s </path/to/ipc.sock> Default = $DEFAULT_SOCKET
  135. -L <LOGLEVEL> Minimum level of messages to forward:
  136. Log levels: NONE, ERROR, WARNING, INFO, DEBUG.
  137. -m <regex> Only forward messages matching a regular expression.
  138. See 'perldoc gnunet-logread' for a longer explanation.
  139. =head1 MOTIVATION
  140. GNUnet debug logs are a tedious read, but given a complex system that we
  141. cannot run all parts of in a debugger all the time, some gathering and
  142. structuring of events and message passing is useful.
  143. At first, this tool simply makes logs easier to read. Both if viewed in
  144. real-time or taken from disk. Then it also allows to extract all message
  145. passing events from it and forward them to a special process that aggregates
  146. all message passing events and therefore helps you make sense of all the
  147. inter-process communication (IPC) happening between the various pieces of
  148. the GNUnet system beast.
  149. That master process is simply an extra gnunet-logread that you run in a
  150. separate window and adorn it with the '-f' flag. The submitting processes
  151. instead need to be given a '-n' flag. That is because from the GNUnet logs
  152. it isn't clear which process events belong to. For example you may be
  153. having events taking place in the 'util' subsystem of gnunet-psyc-service
  154. just as much as in the 'util' subsystem of gnunet-multicast-service. In
  155. order to make sense of them it is necessary to manually add that info. This
  156. could be remedied by extending the semantics of the GNUNET_log facility
  157. instead, but that is still subject to further consideration.
  158. =head1 AUTHORS
  159. tg & lynX