$spec->add_export("&Flog_$level", sub (&@) {
my ($code, $exit_value) = @_;
$exit_value = 1 unless defined $exit_value;
- $router->handle_log_request({
+ #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);
- #TODO this should get fed into a logger so it can be formatted
- #don't let it going wrong stop us from calling exit()
+ }, $code) };
+ warn "could not deliver log event during Flog_$level: $@" if defined $@;
eval { carp $code->() };
+ warn "could not emit warning during Flog_$level: $@" if defined $@;
exit($exit_value);
});
}
sub init_logging {
my $level = $ENV{OBJECT_REMOTE_LOG_LEVEL};
my $format = $ENV{OBJECT_REMOTE_LOG_FORMAT};
- #TODO allow the selections value to be * so it selects everything
my $selections = $ENV{OBJECT_REMOTE_LOG_SELECTIONS};
my %controller_should_log;
router()->connect(sub {
my $controller = $_[1]->{controller};
- return unless $controller_should_log{'*'} || $controller_should_log{$controller};
+ return unless $controller_should_log{'*'} || $controller_should_log{$controller};
#skip things from remote hosts because they log to STDERR
#when OBJECT_REMOTE_LOG_LEVEL is in effect
return if $_[1]->{remote}->{connection_id};
}
1;
+
__END__
=head1 NAME
$ENV{OBJECT_REMOTE_LOG_LEVEL} = 'trace'; #or other level name
$ENV{OBJECT_REMOTE_LOG_FORMAT} = '%l %t: %p::%m %s'; #and more
- $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 0 || 1; #default 0
$ENV{OBJECT_REMOTE_LOG_SELECTIONS} = 'Object::Remote::Logging Some::Other::Subclass';
+ $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 0 || 1; #default 0
log_info { 'Trace log event' };
Dlog_verbose { "Debug event with Data::Dumper::Concise: $_" } { foo => 'bar' };
which implements log rendering and output and L<Object::Remote::Logging::Router>
which delivers log events to the loggers.
+=head1 USAGE
+
+Object::Remote logging is not enabled by default. If you need to immediately start
+debugging set the OBJECT_REMOTE_LOG_LEVEL environment variable to either 'trace'
+or 'debug'. This will enable logging to STDERR on the local and all remote Perl
+interpreters. By default STDERR for all remote interpreters is passed through
+unmodified so this is sufficient to receive logs generated anywhere Object::Remote
+is running.
+
+Every time the local interpreter creates a new Object::Remote::Connection the connection
+is given an id that is unique to that connection on the local interpreter. The connection
+id and other metadata is available in the log output via a log format string that can
+be set via the OBJECT_REMOTE_LOG_FORMAT environment variable. The format string and
+available metadata is documented in L<Object::Remote::Logging::Logger>. Setting this
+environment variable on the local interpreter will cause it to be propagated to the
+remote interpreter so all logs will be formated the same way.
+
+This class is designed so any module can create their own logging sub-class using it.
+With out any additional configuration consumers of this logging class will automatically
+be enabled via OBJECT_REMOTE_LOG_LEVEL and formated with OBJECT_REMOTE_LOG_FORMAT but
+those additional log messages are not sent to STDERR. By setting the
+OBJECT_REMOTE_LOG_SELECTIONS environment variable to a list of class names seperated
+by spaces then logs generated by packages that use those classes will be sent to STDERR.
+This is also a configuration item that is forwarded to the remote interpreters so all
+logging is consistent.
+
+Regardless of OBJECT_REMOTE_LOG_LEVEL the logging system is still active and loggers
+can access the stream of log messages to format and output them. Internally
+OBJECT_REMOTE_LOG_LEVEL causes an L<Object::Remote::Logging::Logger> to be built
+and connected to the L<Object::Remote::Logging::Router> instance. It is also possible
+to manually build a logger instance and connect it to the router. See the documentation
+for the router and logger class.
+
+The logging system also supports a method of forwarding log messages from remote
+interpreters to the local interpreter. Forwarded log messages are generated in the
+remote interpreter and the logger for the message is invoked in the local interpreter.
+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>.
+
=head1 EXPORTABLE SUBROUTINES
=over 4
to the block as the argument list and returned from the log method as a list.
log_trace { "A fine log message $_[0] " } 'if I do say so myself';
- $hashref = Dlog_trace { "Very handy: $_" } { foo => 'bar' };
+ %hash = Dlog_trace { "Very handy: $_" } ( foo => 'bar' );
=item logS_<level> and DlogS_<level>
as soon as possible. Tripple quiet operation (-q -q -q).
=back
-
-=head1 ENVIRONMENT
-
-=over 4
-
-=item OBJECT_REMOTE_LOG_LEVEL
-
-By default Object::Remote will generate log events but messages will not be
-output to STDERR. If there is a defined value for this variable then logs will
-be sent to STDERR if they are at this level or higher.
-
-=item OBJECT_REMOTE_LOG_FORMAT
-
-If logging output is enabled and this value is defined then the logger will
-use this format string instead of the default '[%l %r] %s'; See
-L<Object::Remote::Logging::Logger> for documentation on the format string.
-
-=item OBJECT_REMOTE_LOG_SELECTIONS
-
-By default Object::Remote log output will only be enabled for messages generated inside
-Object::Remote packages. If logs should be generated for other log messages instead of just
-Object::Remote messages set this variable to the names of any Object::Remote::Logging subclass or
-Object::Remote::Logging itself seperated by a space. To output all logs generated set the value
-to *.
-
-=item OBJECT_REMOTE_LOG_FORWARDING
-
-Object::Remote can forward log events from the remote Perl interpreter to the local Perl
-interpreter in a transparent way. Currently this feature is disabled by default but
-that will change Really Soon Now(TM); to enable it set the variable to '1'.
-
-=back
-
has format => ( is => 'ro', required => 1, default => sub { '%l: %s' } );
has level_names => ( is => 'ro', required => 1 );
-has min_level => ( is => 'ro', required => 1 );
-has max_level => ( is => 'ro', required => 1, deafult => sub { 'info' } );
+has min_level => ( is => 'ro', required => 1, default => 'info' );
+has max_level => ( is => 'lazy', required => 1 );
has _level_active => ( is => 'lazy' );
sub BUILD {
$self->_install_methods unless $METHODS_INSTALLED;
}
+sub _build_max_level {
+ my ($self) = @_;
+ return $self->level_names->[-1];
+}
+
sub _build__level_active {
my ($self) = @_;
my $should_log = 0;
c => $metadata->{controller}, p => $metadata->{package}, m => $method,
f => $metadata->{filename}, i => $metadata->{line},
h => $metadata->{hostname}, P => $metadata->{pid},
-
};
}
print STDERR $content;
}
-
1;
+__END__
+
+=head1 NAME
+
+Object::Remote::Logging::Logger - Format and output a log message
+
+=head1 SYNOPSIS
+
+ use Object::Remote::Logging::Logger;
+ use Object::Remote::Logging qw( router arg_levels );
+
+ my $app_output = Object::Remote::Logging::Logger->new(
+ level_names => arg_levels, format => '%t %s',
+ min_level => 'verbose', max_level => 'info',
+ );
+
+ #Selector method can return 0 or more logger
+ #objects that will receive the messages
+ my $selector = sub {
+ my ($generating_package, $metadata) = @_;
+ return unless $metadata->{controller} eq 'App::Logging::Subclass';
+ return $app_output;
+ };
+
+ #true value as second argument causes the selector
+ #to be stored with a weak reference
+ router->connect($selector, 1);
+
+ #disconnect the selector from the router
+ undef($selector);
+
+ #router will hold this logger forever
+ #and send it all log messages
+ router->connect(Object::Remote::Logging::WarnLogger->new(
+ level_names => arg_levels, format => '%s at %f line %i, log level: %l'
+ min_level => 'warn', max_level => 'error',
+ ));
+
+=head1 DESCRIPTION
+
+This class receives log messages from an instance of L<Object::Remote::Log::Router>,
+formats them according to configuration, and then outputs them to STDERR. In between
+the router and the logger is a selector method which inspects the log message metadata
+and can return 0 or more loggers that should receive the log message.
+
+=head1 USAGE
+
+A logger object receives the log messages that are generated and converts them to
+formatted log entries then displays them to the end user. Each logger has a set
+of active log levels and will only output a log entry if the log message is at
+an active log level.
+
+To gain access to the stream of log messages a connection is made to the log router.
+A logger can directly connect to the router and receive an unfiltered stream of
+log messages or a selector closure can be used instead. The selector will be executed
+for each log message with the message metadata and returns a list of 0 or more loggers
+that should receive the log message. When the selector is executed the first argument
+is the class name of the package that generated the log message and the second argument
+is a hash reference containing the message metadata.
+
+=head1 METADATA
+
+The message metadata is a hash reference with the following keys:
+
+=over 4
+
+=item level
+
+Name of the log level of the message.
+
+=item controller
+
+Name of the sub-class of Object::Remote::Logging in use by
+the generating package.
+
+=item package
+
+Name of the package that generated the log message.
+
+=item method
+
+Name of the method the message was generated inside of.
+
+=item timestamp
+
+Unix time of the message generation.
+
+=item pid
+
+Process id of the Perl interpreter the message was generated in.
+
+=item hostname
+
+Hostname of the system where the message was generated.
+
+=item filename
+
+Name of the file the message was generated in.
+
+=item line
+
+Line of the source file the message was generated at.
+
+=item object_remote
+
+This is a reference to another hash that contains the Object::Remote
+specific information. The keys are
+
+=over 4
+
+=item connection_id
+
+If the log message was generated on a remote Perl interpreter then the
+Object::Remote::Connection id of that interpreter will be available here.
+
+=back
+
+=back
+
+=head1 ATTRIBUTES
+
+=over 4
+
+=item level_names
+
+This is a required attribute. Must be an array ref with the list of log level names
+in it. The list must be ordered with the lowest level as element 0 and the highest
+level as the last element. There is no default value.
+
+=item min_level
+
+The lowest log level that will be output by the logger. There is no default value.
+
+=item max_level
+
+The highest log level that will be output by the logger. The default value is the
+highest level present in level_names.
+
+=item format
+
+The printf style format string to use when rendering the log message. The following
+sequences are significant:
+
+=over 4
+
+=item %l
+
+Level name that the log message was generated at.
+
+=item %s
+
+Log message rendered into a string with a leading space before any additional lines in a
+multiple line message.
+
+=item %t
+
+Time the log message was generated rendered into a string. The time value is taken from
+the Perl interpreter that generated the log message; it is not the time that the logger
+received the log message on the local interpreter if the log message was forwarded.
+
+=item %r
+
+Log::Remote connection information rendered into a string.
+
+=item %c
+
+Name of the sub-class of Object::Remote::Logging that was used by the class
+that generated the log message. Can also be Object::Remote::Logging itself.
+
+=item %p
+
+Package name of the class that generated the log message.
+
+=item %m
+
+Method name that generated the log message.
+
+=item %f
+
+Filename that the log message was generated in.
+
+=item %i
+
+Line number the log message was generated at.
+
+=item %h
+
+Hostname the log message was generated on.
+
+=item %P
+
+Process id of the Perl interpreter that generated the log message.
+
+=item %%
+
+A literal %.
+
+=back
+
+=back
+
extends 'Object::Remote::Logging::Logger';
has format => ( is => 'ro', required => 1, default => sub { '%s at %f line %i, log level: %l' } );
-has max_level => ( is => 'ro', required => 1, default => sub { 'error' } );
has min_level => ( is => 'ro', required => 1, default => sub { 'warn' } );
sub output { warn $_[1] };