1 package Object::Remote::Logging::Logger;
4 use Scalar::Util qw(weaken);
7 #TODO sigh invoking a logger with a log level name the same
8 #as an attribute could happen - restrict attributes to _ prefix
9 #and restrict log levels to not start with out that prefix?
10 has format => ( is => 'ro', required => 1, default => sub { '%l: %s' } );
11 has level_names => ( is => 'ro', required => 1 );
12 has min_level => ( is => 'ro', required => 1, default => sub { 'info' } );
13 has max_level => ( is => 'lazy', required => 1 );
14 has _level_active => ( is => 'lazy' );
16 #just a stub so it doesn't get to AUTOLOAD
22 (my $method) = (our $AUTOLOAD =~ /([^:]+)$/);
26 if ($method =~ m/^_/) {
27 croak "invalid method name $method for " . ref($self);
30 if ($method =~ m/^is_(.+)/) {
32 my $is_method = "is_$level_name";
33 *{$is_method} = sub { shift(@_)->_level_active->{$level_name} };
34 return $self->$is_method;
37 my $level_name = $method;
38 *{$level_name} = sub {
40 unless(exists($self->_level_active->{$level_name})) {
41 croak "$level_name is not a valid log level name";
44 $self->_log($level_name, @_);
47 return $self->$level_name(@_);
50 sub _build_max_level {
52 return $self->level_names->[-1];
55 sub _build__level_active {
58 my $min_level = $self->min_level;
59 my $max_level = $self->max_level;
62 foreach my $level (@{$self->level_names}) {
63 if($level eq $min_level) {
67 $active{$level} = $should_log;
69 if (defined $max_level && $level eq $max_level) {
78 my ($self, $level, $content, $metadata_in) = @_;
79 my %metadata = %$metadata_in;
80 my $rendered = $self->_render($level, \%metadata, @$content);
81 $self->_output($rendered);
84 sub _create_format_lookup {
85 my ($self, $level, $metadata, $content) = @_;
86 my $method = $metadata->{method};
88 $method = '(none)' unless defined $method;
91 '%' => '%', t => $self->_render_time($metadata->{timestamp}),
92 r => $self->_render_remote($metadata->{object_remote}),
93 s => $self->_render_log(@$content), l => $level,
94 c => $metadata->{controller}, p => $metadata->{package}, m => $method,
95 f => $metadata->{filename}, i => $metadata->{line},
96 h => $metadata->{hostname}, P => $metadata->{pid},
100 sub _get_format_var_value {
101 my ($self, $name, $data) = @_;
102 my $val = $data->{$name};
103 return $val if defined $val;
104 return '(undefined)';
108 my ($self, $time) = @_;
109 return scalar(localtime($time));
113 my ($self, $remote) = @_;
114 return 'local' if ! defined $remote || ! defined $remote->{connection_id};
115 return 'remote #' . $remote->{connection_id};
119 my ($self, @content) = @_;
120 return join('', @content);
123 my ($self, $level, $metadata, @content) = @_;
124 my $var_table = $self->_create_format_lookup($level, $metadata, [@content]);
125 my $template = $self->format;
127 $template =~ s/%([\w%])/$self->_get_format_var_value($1, $var_table)/ge;
130 $template =~ s/\n/\n /g;
136 my ($self, $content) = @_;
137 print STDERR $content;
146 Object::Remote::Logging::Logger - Format and output a log message
150 use Object::Remote::Logging::Logger;
151 use Object::Remote::Logging qw( router arg_levels );
153 my $app_output = Object::Remote::Logging::Logger->new(
154 level_names => arg_levels, format => '%t %s',
155 min_level => 'verbose', max_level => 'info',
158 #Selector method can return 0 or more logger
159 #objects that will receive the messages
161 my ($generating_package, $metadata) = @_;
162 return unless $metadata->{controller} eq 'App::Logging::Subclass';
166 #true value as second argument causes the selector
167 #to be stored with a weak reference
168 router->connect($selector, 1);
170 #disconnect the selector from the router
173 #router will hold this logger forever
174 #and send it all log messages
175 router->connect(Object::Remote::Logging::WarnLogger->new(
176 level_names => arg_levels, format => '%s at %f line %i, log level: %l'
177 min_level => 'warn', max_level => 'error',
182 This class receives log messages from an instance of L<Object::Remote::Log::Router>,
183 formats them according to configuration, and then outputs them to STDERR. In between
184 the router and the logger is a selector method which inspects the log message metadata
185 and can return 0 or more loggers that should receive the log message.
189 A logger object receives the log messages that are generated and converts them to
190 formatted log entries then displays them to the end user. Each logger has a set
191 of active log levels and will only output a log entry if the log message is at
194 To gain access to the stream of log messages a connection is made to the log router.
195 A logger can directly connect to the router and receive an unfiltered stream of
196 log messages or a selector closure can be used instead. The selector will be executed
197 for each log message with the message metadata and returns a list of 0 or more loggers
198 that should receive the log message. When the selector is executed the first argument
199 is the class name of the package that generated the log message and the second argument
200 is a hash reference containing the message metadata.
204 The message metadata is a hash reference with the following keys:
210 Name of the log level of the message.
214 Name of the sub-class of Object::Remote::Logging in use by
215 the generating package.
219 Name of the package that generated the log message.
223 Name of the method the message was generated inside of.
227 Unix time of the message generation.
231 Process id of the Perl interpreter the message was generated in.
235 Hostname of the system where the message was generated.
239 Name of the file the message was generated in.
243 Line of the source file the message was generated at.
247 This is a reference to another hash that contains the Object::Remote
248 specific information. The keys are
254 If the log message was generated on a remote Perl interpreter then the
255 Object::Remote::Connection id of that interpreter will be available here.
267 This is a required attribute. Must be an array ref with the list of log level names
268 in it. The list must be ordered with the lowest level as element 0 and the highest
269 level as the last element. There is no default value.
273 The lowest log level that will be output by the logger. There is no default value.
277 The highest log level that will be output by the logger. The default value is the
278 highest level present in level_names.
282 The printf style format string to use when rendering the log message. The following
283 sequences are significant:
289 Level name that the log message was generated at.
293 Log message rendered into a string with a leading space before any additional lines in a
294 multiple line message.
298 Time the log message was generated rendered into a string. The time value is taken from
299 the Perl interpreter that generated the log message; it is not the time that the logger
300 received the log message on the local interpreter if the log message was forwarded.
304 Log::Remote connection information rendered into a string.
308 Name of the sub-class of Object::Remote::Logging that was used by the class
309 that generated the log message. Can also be Object::Remote::Logging itself.
313 Package name of the class that generated the log message.
317 Method name that generated the log message.
321 Filename that the log message was generated in.
325 Line number the log message was generated at.
329 Hostname the log message was generated on.
333 Process id of the Perl interpreter that generated the log message.