ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/LogCatcher.pm
Revision: 1.7
Committed: Thu Mar 22 22:57:50 2012 UTC (12 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-2_02, rel-2_01, rel-2_0, HEAD
Changes since 1.6: +9 -9 lines
Log Message:
*** empty log message ***

File Contents

# Content
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<catch> 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 use common::sense;
27 use Carp ();
28 use POSIX ();
29
30 use AnyEvent ();
31 use AnyEvent::Log ();
32 use AnyEvent::Util ();
33
34 use AnyEvent::MP;
35 use AnyEvent::MP::Kernel;
36
37 use base "Exporter";
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 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 snd $rport, @{ $_[0] }
56 if $PROPAGATE;
57 },
58 fmt_cb => sub {
59 [$_[0], $_[1]->title, $_[2], $_[3]]
60 },
61 ;
62
63 $AnyEvent::Log::COLLECT->attach ($ctx);
64
65 # monitor them, silently die if they die
66 mon $rport, sub {
67 $AnyEvent::Log::COLLECT->detach ($ctx);
68 };
69
70 AE::log 8 => "starting to propagate log messages to $rport";
71 }
72
73 sub mon_node {
74 my ($node) = @_;
75
76 # don't log messages from ourselves
77 return if $node eq $NODE;
78
79 $LPORT{$node} ||= do {
80 my $lport = port {
81 my ($time, $ctx, $level, $msg) = @_;
82
83 $level = 2 if $level < 2; # do not exit just because others do so
84
85 my $diff = AE::now - $time;
86 $diff = (abs $diff) < 1e-3 ? "" : sprintf "%+.3fs", $diff;
87
88 local $PROPAGATE; # do not propagate to other nodes
89 (AnyEvent::Log::ctx $ctx)->log ($level, "[$node$diff] $msg");
90 };
91
92 mon $lport, sub {
93 delete $LPORT{$node}
94 or return; # do not monitor if node is not there
95 AE::log error => "@_"
96 if @_; # log error if there really was one
97 mon_node ($node); # try to reocnnect
98 };
99
100 # establish connection
101 AnyEvent::MP::Kernel::snd_to_func $node, "AnyEvent::MP::LogCatcher::connect", 0, $lport, $LOGLEVEL;
102
103 mon $node, $lport;
104
105 $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<undef>, 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 $LOGLEVEL = $_[0];
124 kil $_ for values %LPORT;
125 %LPORT = ();
126
127 return unless defined $LOGLEVEL;
128
129 $MON = db_mon "'l" => sub {
130 my ($family, $add, $chg, $del) = @_;
131
132 kil delete $LPORT{$_}
133 for @$del;
134
135 mon_node $_
136 for @$add;
137 };
138
139 ()
140 }
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<AnyEvent::MP>.
154
155 =head1 AUTHOR
156
157 Marc Lehmann <schmorp@schmorp.de>
158 http://home.schmorp.de/
159
160 =cut
161
162 1
163