File Coverage

blib/lib/AnyEvent/MP/LogCatcher.pm
Criterion Covered Total %
statement 27 62 43.5
branch 0 14 0.0
condition 0 3 0.0
subroutine 9 18 50.0
pod 1 3 33.3
total 37 100 37.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             AnyEvent::MP::LogCatcher - catch all logs from all nodes
4              
5             =head1 SYNOPSIS
6              
7             use AnyEvent::MP::LogCatcher;
8              
9             =head1 DESCRIPTION
10              
11             This relatively simple module attaches itself to the
12             C<$AnyEvent::Log::COLLECT> context on every node and sends all log
13             messages to the node showing interest via the C function.
14              
15             No attempt to buffer log messages on connection loss, or to retransmit
16             lost messages, is done.
17              
18             =head1 GLOBALS AND FUNCTIONS
19              
20             =over 4
21              
22             =cut
23              
24             package AnyEvent::MP::LogCatcher;
25              
26 1     1   447 use common::sense;
  1         2  
  1         4  
27 1     1   37 use Carp ();
  1         1  
  1         10  
28 1     1   418 use POSIX ();
  1         4951  
  1         21  
29              
30 1     1   5 use AnyEvent ();
  1         1  
  1         12  
31 1     1   469 use AnyEvent::Log ();
  1         3246  
  1         24  
32 1     1   6 use AnyEvent::Util ();
  1         1  
  1         15  
33              
34 1     1   3 use AnyEvent::MP;
  1         2  
  1         154  
35 1     1   6 use AnyEvent::MP::Kernel;
  1         1  
  1         52  
36              
37 1     1   4 use base "Exporter";
  1         1  
  1         654  
38              
39             AE::log 7 => "starting log catcher service.";
40              
41             our $LOGLEVEL;
42             our $MON;
43             our $PROPAGATE = 1; # set to one when messages ought to be send to remote nodes
44             our %LPORT; # local logging ports
45              
46             # other nodes connect via this
47             sub connect {
48 0     0 0   my ($version, $rport, $loglevel) = @_;
49              
50             # context to catch log messages
51             my $ctx = new AnyEvent::Log::Ctx
52             title => "AnyEvent::MP::LogCatcher",
53             level => $loglevel,
54             log_cb => sub {
55 0 0   0     snd $rport, @{ $_[0] }
  0            
56             if $PROPAGATE;
57             },
58             fmt_cb => sub {
59 0     0     [$_[0], $_[1]->title, $_[2], $_[3]]
60             },
61 0           ;
62              
63 0           $AnyEvent::Log::COLLECT->attach ($ctx);
64              
65             # monitor them, silently die if they die
66             mon $rport, sub {
67 0     0     $AnyEvent::Log::COLLECT->detach ($ctx);
68 0           };
69              
70 0           AE::log 8 => "starting to propagate log messages to $rport";
71             }
72              
73             sub mon_node {
74 0     0 0   my ($node) = @_;
75              
76             # don't log messages from ourselves
77 0 0         return if $node eq $NODE;
78              
79 0   0       $LPORT{$node} ||= do {
80             my $lport = port {
81 0     0     my ($time, $ctx, $level, $msg) = @_;
82              
83 0 0         $level = 2 if $level < 2; # do not exit just because others do so
84              
85 0           my $diff = AE::now - $time;
86 0 0         $diff = (abs $diff) < 1e-3 ? "" : sprintf "%+.3fs", $diff;
87              
88 0           local $PROPAGATE; # do not propagate to other nodes
89 0           (AnyEvent::Log::ctx $ctx)->log ($level, "[$node$diff] $msg");
90 0           };
91              
92             mon $lport, sub {
93 0 0   0     delete $LPORT{$node}
94             or return; # do not monitor if node is not there
95 0 0         AE::log error => "@_"
96             if @_; # log error if there really was one
97 0           mon_node ($node); # try to reocnnect
98 0           };
99              
100             # establish connection
101 0           AnyEvent::MP::Kernel::snd_to_func $node, "AnyEvent::MP::LogCatcher::connect", 0, $lport, $LOGLEVEL;
102              
103 0           mon $node, $lport;
104              
105 0           $lport
106             }
107             }
108              
109             =item AnyEvent::MP::LogCatcher::catch [$level]
110              
111             Starts catching all log messages from all nodes with level C<$level> or
112             lower. If the C<$level> is C, then stop catching all messages
113             again.
114              
115             Example: start a node that catches all messages (you might have to specify
116             a suitable profile name).
117              
118             AE_VERBOSE=9 aemp run profilename services '[["AnyEvent::MP::LogCatcher::catch",9]]'
119              
120             =cut
121              
122             sub catch {
123 0     0 1   $LOGLEVEL = $_[0];
124 0           kil $_ for values %LPORT;
125 0           %LPORT = ();
126              
127 0 0         return unless defined $LOGLEVEL;
128              
129             $MON = db_mon "'l" => sub {
130 0     0     my ($family, $add, $chg, $del) = @_;
131              
132             kil delete $LPORT{$_}
133 0           for @$del;
134              
135             mon_node $_
136 0           for @$add;
137 0           };
138              
139             ()
140 0           }
141              
142             =back
143              
144             =head1 LOGGING
145              
146             AnyEvent::MP::LogCatcher logs messages from remote nodes. It logs them
147             into the original logging context and prepends the origin node name
148             and, if the time difference is larger than 1e-4 seconds, also the time
149             difference between local time and origin time.
150              
151             =head1 SEE ALSO
152              
153             L.
154              
155             =head1 AUTHOR
156              
157             Marc Lehmann
158             http://home.schmorp.de/
159              
160             =cut
161              
162             1
163