convert to unobtrusive Dist::Zilla
[p5sagit/Log-Contextual.git] / lib / Log / Contextual / Role / Router.pm
1 package Log::Contextual::Role::Router;
2
3 # ABSTRACT: Abstract interface between loggers and logging code blocks
4
5 use Moo::Role;
6
7 requires 'before_import';
8 requires 'after_import';
9 requires 'handle_log_request';
10
11 1;
12
13 __END__
14
15 =head1 SYNOPSIS
16
17   package MyApp::Log::Router;
18
19   use Moo;
20   use Log::Contextual::SimpleLogger;
21
22   with 'Log::Contextual::Role::Router';
23
24   has logger => (is => 'lazy');
25
26   sub _build_logger {
27      return Log::Contextual::SimpleLogger->new({ levels_upto => 'debug' });
28   }
29
30   sub before_import {
31      my ($self, %export_info) = @_;
32      my $exporter = $export_info{exporter};
33      my $target = $export_info{target};
34      print STDERR "Package '$target' will import from '$exporter'\n";
35   }
36
37   sub after_import {
38      my ($self, %export_info) = @_;
39      my $exporter = $export_info{exporter};
40      my $target = $export_info{target};
41      print STDERR "Package '$target' has imported from '$exporter'\n";
42   }
43
44   sub handle_log_request {
45      my ($self, %message_info) = @_;
46      my $log_code_block = $message_info{message_sub};
47      my $args = $message_info{message_args};
48      my $log_level_name = $message_info{message_level};
49      my $logger = $self->logger;
50      my $is_active = $logger->can("is_${log_level_name}");
51
52      return unless defined $is_active && $logger->$is_active;
53      my $log_message = $log_code_block->(@$args);
54      $logger->$log_level_name($log_message);
55   }
56
57   package MyApp::Log::Contextual;
58
59   use Moo;
60   use MyApp::Log::Router;
61
62   extends 'Log::Contextual';
63
64   #This example router is a singleton
65   sub router {
66      our $Router ||= MyApp::Log::Router->new
67   }
68
69   package main;
70
71   use strict;
72   use warnings;
73   use MyApp::Log::Contextual qw(:log);
74
75   log_info { "Hello there" };
76
77 =head1 DESCRIPTION
78
79 Log::Contextual has three parts
80
81 =over 4
82
83 =item Export manager and logging method generator
84
85 These tasks are handled by the C<Log::Contextual> package.
86
87 =item Logger selection and invocation
88
89 The logging functions generated and exported by Log::Contextual call a method
90 on an instance of a log router object which is responsible for invoking any loggers
91 that should get an opportunity to receive the log message. The C<Log::Contextual::Router>
92 class implements the set_logger() and with_logger() functions as well as uses the
93 arg_ prefixed functions to configure itself and provide the standard C<Log::Contextual>
94 logger selection API.
95
96 =item Log message formatting and output
97
98 The logger objects themselves accept or reject a log message at a certain log
99 level with a guard method per level. If the logger is going to accept the
100 log message the router is then responsible for executing the log message code
101 block and passing the generated message to the logging object's log method.
102
103 =back
104
105 =head1 METHODS
106
107 =over 4
108
109 =item before_import($self, %import_info)
110
111 =item after_import($self,  %import_info)
112
113 These two required methods are called with identical arguments at two different places
114 during the import process. The before_import() method is invoked prior to the logging
115 subroutines being exported into the target package and after_import() is called when the
116 export is completed but before control returns to the package that imported the API.
117
118 The arguments are passed as a hash with the following keys:
119
120 =over 4
121
122 =item exporter
123
124 This is the name of the package that has been imported. It can also be 'Log::Contextual' itself. In
125 the case of the synopsis the value for exporter would be 'MyApp::Log::Contextual'.
126
127 =item target
128
129 This is the package name that is importing the logging API. In the case of the synopsis the
130 value would be 'main'.
131
132 =item arguments
133
134 This is a hash reference containing the configuration values that were provided for the import.
135 The key is the name of the configuration item that was specified without the leading hyphen ('-').
136 For instance if the logging API is imported as follows
137
138   use Log::Contextual qw( :log ), -logger => Custom::Logger->new({ levels => [qw( debug )] });
139
140 then $import_info{arguments}->{logger} would contain that instance of Custom::Logger.
141
142 =back
143
144 =item handle_log_request($self, %message_info)
145
146 This method is called by C<Log::Contextual> when a log event happens. The arguments are passed
147 as a hash with the following keys
148
149 =over 4
150
151 =item exporter
152
153 This is the name of the package that created the logging methods used to generate the log event.
154
155 =item caller_package
156
157 This is the name of the package that the log event has happened inside of.
158
159 =item caller_level
160
161 This is an integer that contains the value to pass to caller() that will provide
162 information about the location the log event was created at.
163
164 =item log_level
165
166 This is the name of the log level associated with the log event.
167
168 =item message_sub
169
170 This is the message generating code block associated with the log event passed as a subref. If
171 the logger accepts the log request the router should execute the subref to create
172 the log message and then pass the message as a string to the logger.
173
174 =item message_args
175
176 This is an array reference that contains the arguments given to the message generating code block.
177 When invoking the message generator it will almost certainly be expecting these argument values
178 as well.
179
180 =back
181
182 =back