=head1 NAME AnyEvent::MP::LogCatcher - catch all logs from all nodes =head1 SYNOPSIS use AnyEvent::MP::LogCatcher; =head1 DESCRIPTION This relatively simple module attaches itself to the C<$AnyEvent::Log::COLLECT> context on every node and sends all log messages to the node showing interest via the C function. No attempt to buffer log messages on connection loss, or to retransmit lost messages, is done. =head1 GLOBALS AND FUNCTIONS =over 4 =cut package AnyEvent::MP::LogCatcher; use common::sense; use Carp (); use POSIX (); use AnyEvent (); use AnyEvent::Log (); use AnyEvent::Util (); use AnyEvent::MP; use AnyEvent::MP::Kernel; use base "Exporter"; AE::log 7 => "starting log catcher service."; our $LOGLEVEL; our %lport; # local logging ports # other nodes connect via this sub connect { my ($version, $rport, $loglevel) = @_; my $ctx = new AnyEvent::Log::Ctx title => "AnyEvent::MP::LogCatcher", level => $loglevel, log_cb => sub { snd $rport, @{ $_[0] }; }, fmt_cb => sub { [$_[0], $_[1]->title, $_[2], $_[3]] }, ; $AnyEvent::Log::COLLECT->attach ($ctx); # monitor them, silently die mon $rport, sub { $AnyEvent::Log::COLLECT->detach ($ctx); }; } sub mon_node { my ($node, $is_up) = @_; return unless $is_up; my $lport = $lport{$node} = port { my ($time, $ctx, $level, $msg) = @_; $level = 2 if $level < 2; # do not exit because others do so my $diff = $time - AE::now; $diff = $diff < 1e-4 ? "" : sprintf ", %gs", $diff; AE::log $level, "[$node$diff] $msg"; }; # establish connection AnyEvent::MP::Kernel::snd_to_func $node, "AnyEvent::MP::LogCatcher::connect", 0, $lport, $LOGLEVEL; mon $node, $lport; } =item AnyEvent::MP::LogCatcher::catch [$level] Starts catching all log messages from all nodes with level C<$level> or lower. If the C<$level> is C, then stop catching all messages again. Example: start a node that catches all messages (you might have to specify a suitable profile name). aemp run profilename services '[["AnyEvent::MP::LogCatcher::catch",9]]' =cut sub catch { $LOGLEVEL = $_[0]; kil $_, "restart" for values %lport; %lport = (); return unless defined $LOGLEVEL; mon_node $_, 1 for up_nodes; mon_nodes \&mon_node; () } =back =head1 SEE ALSO L. =head1 AUTHOR Marc Lehmann http://home.schmorp.de/ =cut 1