extends 'Log::Contextual';
exports(qw( ____ router arg_levels ));
-#exception log - log a message then die with that message
-export_tag elog => ('____');
-#fatal log - log a message then call exit(1)
-export_tag flog => ('____');
sub router {
our $Router_Instance ||= do {
sub before_import {
my ($class, $importer, $spec) = @_;
my $router = $class->router;
+ our $DID_INIT;
- $class->SUPER::before_import($importer, $spec);
-
- my @levels = @{$class->arg_levels($spec->config->{levels})};
- for my $level (@levels) {
- if ($spec->config->{elog}) {
- $spec->add_export("&Elog_$level", sub (&) {
- my ($code, @args) = @_;
- $router->handle_log_request({
- controller => $class,
- package => scalar(caller),
- caller_level => 1,
- level => $level,
- }, $code);
- #TODO this should get fed into a logger so it can be formatted
- croak $code->();
- });
- }
- if ($spec->config->{flog}) {
- #TODO that prototype isn't right
- $spec->add_export("&Flog_$level", sub (&@) {
- my ($code, $exit_value) = @_;
- $exit_value = 1 unless defined $exit_value;
- #don't let it going wrong stop us from calling exit()
- eval { $router->handle_log_request({
- controller => $class,
- package => scalar(caller),
- caller_level => 1,
- level => $level,
- }, $code) };
- warn "could not deliver log event during Flog_$level: $@" if $@;
- eval { carp $code->() };
- warn "could not emit warning during Flog_$level: $@" if $@;
- exit($exit_value);
- });
- }
+ unless($DID_INIT) {
+ $DID_INIT = 1;
+ init_logging();
}
+
+ $class->SUPER::before_import($importer, $spec);
}
sub _parse_selections {
- my ($selections_string) = @_;
- my %log_ok;
+ my ($selections_string) = @_;
+ my %log_ok;
- #example string:
- #" * -Object::Remote::Logging Foo::Bar::Baz "
- foreach(split(/\s+/, $selections_string)) {
- next if $_ eq '';
- if ($_ eq '*') {
- $log_ok{$_} = 1;
- } elsif (s/^-//) {
- $log_ok{$_} = 0;
- } else {
- $log_ok{$_} = 1;
- }
+ #example string:
+ #" * -Object::Remote::Logging Foo::Bar::Baz "
+ foreach(split(/\s+/, $selections_string)) {
+ next if $_ eq '';
+ if ($_ eq '*') {
+ $log_ok{$_} = 1;
+ } elsif (s/^-//) {
+ $log_ok{$_} = 0;
+ } else {
+ $log_ok{$_} = 1;
}
+ }
- return %log_ok;
+ return %log_ok;
}
#this is invoked on all nodes
my $level = $ENV{OBJECT_REMOTE_LOG_LEVEL};
my $format = $ENV{OBJECT_REMOTE_LOG_FORMAT};
my $selections = $ENV{OBJECT_REMOTE_LOG_SELECTIONS};
+ my $test_logging = $ENV{OBJECT_REMOTE_TEST_LOGGER};
my %controller_should_log;
+
+ unless (defined $ENV{OBJECT_REMOTE_LOG_FORWARDING} && $ENV{OBJECT_REMOTE_LOG_FORWARDING} ne '') {
+ $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 1;
+ }
+
+ if ($test_logging) {
+ require Object::Remote::Logging::TestLogger;
+ router->connect(Object::Remote::Logging::TestLogger->new(
+ min_level => 'trace', max_level => 'error',
+ level_names => Object::Remote::Logging->arg_levels(),
+ ));
+ }
+
+ {
+ no warnings 'once';
+ if (defined $Object::Remote::FatNode::REMOTE_NODE) {
+ #the connection id for the remote node comes in later
+ #as the controlling node inits remote logging
+ router()->_remote_metadata({ connection_id => undef });
+ }
+ }
- return unless defined $level;
+ return unless defined $level && $level ne '';
+
$format = "[%l %r] %s" unless defined $format;
$selections = __PACKAGE__ unless defined $selections;
%controller_should_log = _parse_selections($selections);
-
+
my $logger = Object::Remote::Logging::Logger->new(
min_level => lc($level), format => $format,
level_names => Object::Remote::Logging::arg_levels(),
#this is invoked by the controlling node
#on the remote nodes
-sub init_logging_forwarding {
+sub init_remote_logging {
my ($self, %controller_info) = @_;
- router()->_remote_metadata({ connection_id => $controller_info{connection_id} });
- #TODO having an instance of an object in the remote interpreter causes it to hang
- #on exit intermitently or leave a zombie laying around frequently - not a bug limited
- #to log forwarding
+ router()->_remote_metadata(\%controller_info);
router()->_forward_destination($controller_info{router}) if $ENV{OBJECT_REMOTE_LOG_FORWARDING};
}
=head1 SYNOPSIS
- use Object::Remote::Logging qw( :log :dlog :elog :flog arg_levels router );
+ use Object::Remote::Logging qw( :log :dlog arg_levels router );
@levels = qw( trace debug verbose info warn error fatal );
@levels = arg_levels(); #same result
$ENV{OBJECT_REMOTE_LOG_FORMAT} = '%l %t: %p::%m %s'; #and more
$ENV{OBJECT_REMOTE_LOG_SELECTIONS} = 'Object::Remote::Logging Some::Other::Subclass';
$ENV{OBJECT_REMOTE_LOG_SELECTIONS} = '* -Object::Remote::Logging';
- $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 0 || 1; #default 0
+ $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 0; #default 1
log_info { 'Trace log event' };
Dlog_verbose { "Debug event with Data::Dumper::Concise: $_" } { foo => 'bar' };
- Elog_error { 'Error event that calls die() with this string' };
- Flog_fatal { 'Fatal event calls warn() then exit()' } 1;
=head1 DESCRIPTION
Sub-classes of Object::Remote::Logging will have log messages forwarded automatically.
Loggers receive forwarded log messages exactly the same way as non-forwarded messages
except a forwarded message includes extra metadata about the remote interpreter. Log
-forwarding is not currently enabled by default; to enable it set the
-OBJECT_REMOTE_LOG_FORWARDING environment variable to 1. See L<Object::Remote::Logging::Router>.
+forwarding is enabled by default but comes with a performance hit; to disable it set the
+OBJECT_REMOTE_LOG_FORWARDING environment variable to 0. See L<Object::Remote::Logging::Router>.
=head1 EXPORTABLE SUBROUTINES
Works just like log_ and Dlog_ except returns only the first argument as a scalar value.
- my $beverage = log_info { "Customer ordered $_[0]" } 'Coffee';
-
-=item Elog_<level>
-
-Log an event and then generate an exception by calling die() with the log message.
-
- Elog_error { "Could not open file: $!" };
-
-=item Flog_<level>
-
-Log the event, generate a warning with the log message, then call exit(). The exit
-value will default to 1 or can be specified as an argument.
-
- Flog_fatal { 'Could not lock resource' } 3;
+ my $beverage = logS_info { "Customer ordered $_[0]" } 'Coffee';
=back