add self to contributor list; document new env variables in Object::Remote POD; add...
[scpubgit/Object-Remote.git] / lib / Object / Remote / Logging.pm
CommitLineData
5e2b2229 1package Object::Remote::Logging;
2
4e446335 3use Moo;
4use Scalar::Util qw(blessed);
5use Object::Remote::Logging::Logger;
f4a85080 6use Exporter::Declare;
663fb34f 7use Carp qw(carp croak);
5e2b2229 8
4e446335 9extends 'Log::Contextual';
5e2b2229 10
663fb34f 11exports(qw( ____ router arg_levels ));
12#exception log - log a message then die with that message
13export_tag elog => ('____');
14#fatal log - log a message then call exit(1)
15export_tag flog => ('____');
f4a85080 16
4e446335 17sub router {
c0b2df05 18 our $Router_Instance ||= do {
19 require Object::Remote::Logging::Router;
20 Object::Remote::Logging::Router->new;
21 }
4e446335 22}
5e2b2229 23
9de32e1d 24#log level descriptions
25#info - standard log level - normal program output for the end user
26#warn - output for program that is executing quietly
27#error - output for program that is running more quietly
28#fatal - it is not possible to continue execution; this level is as quiet as is possible
29#verbose - output for program executing verbosely (-v)
30#debug - output for program running more verbosely (-v -v)
31#trace - output for program running extremely verbosely (-v -v -v)
4e446335 32sub arg_levels {
9de32e1d 33 #the order of the log levels is significant with the
34 #most verbose level being first in the list and the
35 #most quiet as the last item
36 return [qw( trace debug verbose info warn error fatal )];
4a9fa1a5 37}
5e2b2229 38
663fb34f 39sub before_import {
40 my ($class, $importer, $spec) = @_;
41 my $router = $class->router;
42
43 $class->SUPER::before_import($importer, $spec);
44
45 my @levels = @{$class->arg_levels($spec->config->{levels})};
46 for my $level (@levels) {
47 if ($spec->config->{elog}) {
48 $spec->add_export("&Elog_$level", sub (&) {
49 my ($code, @args) = @_;
50 $router->handle_log_request({
51 controller => $class,
52 package => scalar(caller),
53 caller_level => 1,
54 level => $level,
55 }, $code);
56 #TODO this should get fed into a logger so it can be formatted
57 croak $code->();
58 });
59 }
60 if ($spec->config->{flog}) {
61 #TODO that prototype isn't right
62 $spec->add_export("&Flog_$level", sub (&@) {
63 my ($code, $exit_value) = @_;
64 $exit_value = 1 unless defined $exit_value;
65 $router->handle_log_request({
66 controller => $class,
67 package => scalar(caller),
68 caller_level => 1,
69 level => $level,
70 }, $code);
71 #TODO this should get fed into a logger so it can be formatted
d672a9bf 72 #don't let it going wrong stop us from calling exit()
73 eval { carp $code->() };
663fb34f 74 exit($exit_value);
75 });
76 }
77 }
78}
79
4e446335 80#this is invoked on all nodes
4a9fa1a5 81sub init_logging {
c0b2df05 82 my $level = $ENV{OBJECT_REMOTE_LOG_LEVEL};
0fe333eb 83 my $format = $ENV{OBJECT_REMOTE_LOG_FORMAT};
eb49c7df 84 #TODO allow the selections value to be * so it selects everything
85 my $selections = $ENV{OBJECT_REMOTE_LOG_SELECTIONS};
86 my %controller_should_log;
87
c0b2df05 88 return unless defined $level;
0fe333eb 89 $format = "[%l %r] %s" unless defined $format;
eb49c7df 90 $selections = __PACKAGE__ unless defined $selections;
91 %controller_should_log = map { $_ => 1 } split(' ', $selections);
92
c0b2df05 93 my $logger = Object::Remote::Logging::Logger->new(
0fe333eb 94 min_level => lc($level), format => $format,
c0b2df05 95 level_names => Object::Remote::Logging::arg_levels(),
96 );
97
c0b2df05 98 router()->connect(sub {
eb49c7df 99 my $controller = $_[1]->{controller};
466ee2c4 100 return unless $controller_should_log{'*'} || $controller_should_log{$controller};
c0b2df05 101 #skip things from remote hosts because they log to STDERR
102 #when OBJECT_REMOTE_LOG_LEVEL is in effect
103 return if $_[1]->{remote}->{connection_id};
104 $logger
105 });
4a9fa1a5 106}
107
4e446335 108#this is invoked by the controlling node
109#on the remote nodes
4a9fa1a5 110sub init_logging_forwarding {
4e446335 111 my ($self, %controller_info) = @_;
112
113 router()->_remote_metadata({ connection_id => $controller_info{connection_id} });
466ee2c4 114 router()->_forward_destination($controller_info{router}) if $ENV{OBJECT_REMOTE_LOG_FORWARDING};
4a9fa1a5 115}
5e2b2229 116
1171;
d672a9bf 118__END__
119
120=head1 NAME
121
122Object::Remote::Logging - Logging subsystem for Object::Remote
123
124=head1 SYNOPSIS
125
126 use Object::Remote::Logging qw( :log :dlog :elog :flog arg_levels router );
127
128 @levels = qw( trace debug verbose info warn error fatal );
129 @levels = arg_levels(); #same result
130
131 $ENV{OBJECT_REMOTE_LOG_LEVEL} = 'trace'; #or other level name
132 $ENV{OBJECT_REMOTE_LOG_FORMAT} = '%l %t: %p::%m %s'; #and more
133 $ENV{OBJECT_REMOTE_LOG_FORWARDING} = 0 || 1; #default 0
134 $ENV{OBJECT_REMOTE_LOG_SELECTIONS} = 'Object::Remote::Logging Some::Other::Subclass';
135
136 log_info { 'Trace log event' };
137 Dlog_verbose { "Debug event with Data::Dumper::Concise: $_" } { foo => 'bar' };
138 Elog_error { 'Error event that calls die() with this string' };
139 Flog_fatal { 'Fatal event calls warn() then exit()' } 1;
140
141=head1 DESCRIPTION
142
143This is the logging framework for Object::Remote implemented as a subclass of
144L<Log::Contextual> with a slightly incompatible API. This system allows
145developers using Object::Remote and end users of that software to control
146Object::Remote logging so operation can be tracked if needed. This is also
147the API used to generate log messages inside the Object::Remote source code.
148
149The rest of the logging system comes from L<Object::Remote::Logging::Logger>
150which implements log rendering and output and L<Object::Remote::Logging::Router>
151which delivers log events to the loggers.
152
153=head1 EXPORTABLE SUBROUTINES
154
155=over 4
156
157=item arg_levels
158
159Returns an array reference that contains the ordered list of level names
160with the lowest log level first and the highest log level last.
161
162=item router
163
164Returns the instance of L<Object::Remote::Logging::Router> that is in use. The router
165instance is used in combination with L<Object::Remote::Logging::Logger> objects to
166select then render and output log messages.
167
168=item log_<level> and Dlog_<level>
169
170These methods come direct from L<Log::Contextual>; see that documentation for a
171complete reference. For each of the log level names there are subroutines with the log_
172and Dlog_ prefix that will generate the log message. The first argument is a code block
173that returns the log message contents and the optional further arguments are both passed
174to the block as the argument list and returned from the log method as a list.
175
176 log_trace { "A fine log message $_[0] " } 'if I do say so myself';
177 $hashref = Dlog_trace { "Very handy: $_" } { foo => 'bar' };
178
179=item logS_<level> and DlogS_<level>
180
181Works just like log_ and Dlog_ except returns only the first argument as a scalar value.
182
183 my $beverage = log_info { "Customer ordered $_[0]" } 'Coffee';
184
185=item Elog_<level>
186
187Log an event and then generate an exception by calling die() with the log message.
188
189 Elog_error { "Could not open file: $!" };
190
191=item Flog_<level>
192
193Log the event, generate a warning with the log message, then call exit(). The exit
194value will default to 1 or can be specified as an argument.
195
196 Flog_fatal { 'Could not lock resource' } 3;
197
198=back
199
200=head1 LEVEL NAMES
201
202Object::Remote uses an ordered list of log level names with the minimum level
203first and the maximum level last. The list of level names can be accessed via
204the arg_levels method which is exportable to the consumer of this class. The log
205level names are:
206
207=over 4
208
209=item trace
210
211As much information about operation as possible including multiple line dumps of
212large content. Tripple verbose operation (-v -v -v).
213
214=item debug
215
216Messages about operations that could hang as well as internal state changes,
217results from method invocations, and information useful when looking for faults.
218Double verbose operation (-v -v).
219
220=item verbose
221
222Additional optional messages to the user that can be enabled at their will. Single
223verbose operation (-v).
224
225=item info
226
227Messages from normal operation that are intended to be displayed to the end
228user if quiet operation is not indicated and more verbose operation is not
229in effect.
230
231=item warn
232
233Something wasn't supposed to happen but did. Operation was not impacted but
234otherwise the event is noteworthy. Single quiet operation (-q).
235
236=item error
237
238Something went wrong. Operation of the system may continue but some operation
239has most definitely failed. Double quiet operation (-q -q).
240
241=item fatal
242
243Something went wrong and recovery is not possible. The system should stop operating
244as soon as possible. Tripple quiet operation (-q -q -q).
245
246=back
247
248=head1 ENVIRONMENT
249
250=over 4
251
252=item OBJECT_REMOTE_LOG_LEVEL
253
254By default Object::Remote will generate log events but messages will not be
255output to STDERR. If there is a defined value for this variable then logs will
256be sent to STDERR if they are at this level or higher.
257
258=item OBJECT_REMOTE_LOG_FORMAT
259
260If logging output is enabled and this value is defined then the logger will
261use this format string instead of the default '[%l %r] %s'; See
262L<Object::Remote::Logging::Logger> for documentation on the format string.
263
264=item OBJECT_REMOTE_LOG_SELECTIONS
265
266By default Object::Remote log output will only be enabled for messages generated inside
267Object::Remote packages. If logs should be generated for other log messages instead of just
268Object::Remote messages set this variable to the names of any Object::Remote::Logging subclass or
269Object::Remote::Logging itself seperated by a space. To output all logs generated set the value
270to *.
271
272=item OBJECT_REMOTE_LOG_FORWARDING
273
274Object::Remote can forward log events from the remote Perl interpreter to the local Perl
275interpreter in a transparent way. Currently this feature is disabled by default but
276that will change Really Soon Now(TM); to enable it set the variable to '1'.
277
278=back
5e2b2229 279