File Coverage

blib/lib/Log/Log4perl/Appender.pm
Criterion Covered Total %
statement 107 111 96.4
branch 48 54 88.8
condition 5 6 83.3
subroutine 20 20 100.0
pod 2 10 20.0
total 182 201 90.5


line stmt bran cond sub pod time code
1             ##################################################
2             ##################################################
3              
4             use 5.006;
5 70     70   1373 use strict;
  70         264  
6 70     70   398 use warnings;
  70         156  
  70         1667  
7 70     70   391  
  70         136  
  70         2274  
8             use Log::Log4perl::Level;
9 70     70   445 use Carp;
  70         192  
  70         546  
10 70     70   455  
  70         185  
  70         4646  
11             use constant _INTERNAL_DEBUG => 0;
12 70     70   473  
  70         176  
  70         67744  
13             our $unique_counter = 0;
14              
15             ##################################################
16             ##################################################
17             $unique_counter = 0;
18             }
19 295     295 0 738  
20             ##################################################
21             ##################################################
22             # THREADS: Need to lock here to make it thread safe
23             $unique_counter++;
24             my $unique_name = sprintf("app%03d", $unique_counter);
25             # THREADS: Need to unlock here to make it thread safe
26 20     20 0 41 return $unique_name;
27 20         99 }
28              
29 20         60 ##################################################
30             ##################################################
31             my($class, $appenderclass, %params) = @_;
32              
33             # Pull in the specified Log::Log4perl::Appender object
34             eval {
35 291     291 1 5853  
36             # Eval erroneously succeeds on unknown appender classes if
37             # the eval string just consists of valid perl code (e.g. an
38 291         586 # appended ';' in $appenderclass variable). Fail if we see
39             # anything in there that can't be class name.
40             die "'$appenderclass' not a valid class name " if
41             $appenderclass =~ /[^:\w]/;
42              
43             # Check if the class/package is already available because
44 291 100       1577 # something like Class::Prototyped injected it previously.
45              
46             # Use UNIVERSAL::can to check the appender's new() method
47             # [RT 28987]
48             if( ! $appenderclass->can('new') ) {
49             # Not available yet, try to pull it in.
50             # see 'perldoc -f require' for why two evals
51             eval "require $appenderclass";
52 290 100       3713 #unless ${$appenderclass.'::IS_LOADED'}; #for unit tests,
53             #see 004Config
54             die $@ if $@;
55 37         2801 }
56             };
57              
58 37 100       71652 $@ and die "ERROR: can't load appenderclass '$appenderclass'\n$@";
59             print "Appender class $appenderclass loaded OK ($@)\n" if _INTERNAL_DEBUG;
60              
61             $params{name} = unique_name() unless exists $params{name};
62 291 100       937  
63 289         456 # If it's a Log::Dispatch::File appender, default to append
64             # mode (Log::Dispatch::File defaults to 'clobber') -- consensus 9/2002
65 289 100       883 # (Log::Log4perl::Appender::File already defaults to 'append')
66             if ($appenderclass eq 'Log::Dispatch::File' &&
67             ! exists $params{mode}) {
68             $params{mode} = 'append';
69             }
70 289 50 66     1035  
71             print "Calling $appenderclass new\n" if _INTERNAL_DEBUG;
72 0         0  
73             my $appender = $appenderclass->new(
74             # Set min_level to the lowest setting. *we* are
75 289         432 # controlling this now, the appender should just
76             # log it with no questions asked.
77             min_level => 'debug',
78             # Set 'name' and other parameters
79             map { $_ => $params{$_} } keys %params,
80             );
81              
82             print "Calling $appenderclass new returned OK\n" if _INTERNAL_DEBUG;
83 289         919  
  902         2660  
84             my $self = {
85             appender => $appender,
86 289         4240 name => $params{name},
87             layout => undef,
88             level => $ALL,
89             composite => 0,
90             };
91 289         1420  
92             #whether to collapse arrays, etc.
93             $self->{warp_message} = $params{warp_message};
94              
95             if (!$INC{'Log/Log4perl/Config.pm'}) {
96             require Log::Log4perl::Config;
97 289         792 }
98              
99 289 50       898 if($self->{warp_message} and
100 0         0 my $cref =
101             Log::Log4perl::Config::compile_if_perl($self->{warp_message})) {
102             $self->{warp_message} = $cref;
103 289 100 100     1056 }
104            
105             bless $self, $class;
106 1         2  
107             return $self;
108             }
109 289         684  
110             ##################################################
111 289         1000 ##################################################
112             my ($self, $flag) = @_;
113              
114             $self->{composite} = $flag if defined $flag;
115             return $self->{composite};
116             }
117 759     759 0 1631  
118             ##################################################
119 759 100       1818 ##################################################
120 759         2640 my ($self, $level) = @_;
121              
122             print "Setting threshold to $level\n" if _INTERNAL_DEBUG;
123              
124             if(defined $level) {
125             # Checking for \d makes for a faster regex(p)
126 29     29 0 82 $self->{level} = ($level =~ /^(\d+)$/) ? $level :
127             # Take advantage of &to_priority's error reporting
128 29         41 Log::Log4perl::Level::to_priority($level);
129             }
130 29 100       62  
131             return $self->{level};
132 24 100       128 }
133              
134             ##################################################
135             ##################################################
136             # Relay this call to Log::Log4perl::Appender:* or
137 29         72 # Log::Dispatch::*
138             ##################################################
139             my ($self, $p, $category, $level, $cache) = @_;
140              
141             # Check if the appender has a last-minute veto in form
142             # of an "appender threshold"
143             if($self->{level} > $
144             Log::Log4perl::Level::PRIORITY{$level}) {
145             print "$self->{level} > $level, aborting\n" if _INTERNAL_DEBUG;
146 583     583 0 1973 return undef;
147             }
148              
149             # Run against the (yes only one) customized filter (which in turn
150 583 100       1540 # might call other filters via the Boolean filter) and check if its
151             # ok() method approves the message or blocks it.
152 22         36 if($self->{filter}) {
153 22         86 if($self->{filter}->ok(%$p,
154             log4p_category => $category,
155             log4p_level => $level )) {
156             print "Filter $self->{filter}->{name} passes\n" if _INTERNAL_DEBUG;
157             } else {
158             print "Filter $self->{filter}->{name} blocks\n" if _INTERNAL_DEBUG;
159 561 100       1343 return undef;
160 30 100       153 }
161             }
162              
163 15         58 unless($self->composite()) {
164              
165 15         56 #not defined, the normal case
166 15         77 if (! defined $self->{warp_message} ){
167             #join any message elements
168             if (ref $p->{message} eq "ARRAY") {
169             for my $i (0..$#{$p->{message}}) {
170 546 100       1238 if( !defined $p->{message}->[ $i ] ) {
171             local $Carp::CarpLevel =
172             $Carp::CarpLevel + $Log::Log4perl::caller_depth + 1;
173 502 100       1229 carp "Warning: Log message argument #" .
    100          
    100          
174             ($i+1) . " undefined";
175 489 100       1421 }
176 483         802 }
  483         1543  
177 511 100       1553 $p->{message} =
178 1         4 join($Log::Log4perl::JOIN_MSG_ARRAY_CHAR,
179             @{$p->{message}}
180 1         345 );
181             }
182            
183             #defined but false, e.g. Appender::DBI
184             } elsif (! $self->{warp_message}) {
185             ; #leave the message alone
186 483         847
  483         1482  
187             } elsif (ref($self->{warp_message}) eq "CODE") {
188             #defined and a subref
189             $p->{message} =
190             [$self->{warp_message}->(@{$p->{message}})];
191             } else {
192             #defined and a function name?
193             no strict qw(refs);
194             $p->{message} =
195             [$self->{warp_message}->(@{$p->{message}})];
196             }
197 1         3  
  1         29  
198             $p->{message} = $self->{layout}->render($p->{message},
199             $category,
200 70     70   642 $level,
  70         202  
  70         34187  
201             3 + $Log::Log4perl::caller_depth,
202 1         2 ) if $self->layout();
  1         6  
203             }
204              
205             my $args = [%$p, log4p_category => $category, log4p_level => $level];
206 502 50       1207  
207             if(defined $cache) {
208             $$cache = $args;
209             } else {
210             $self->{appender}->log(@$args);
211             }
212 546         2632  
213             return 1;
214 546 100       1317 }
215 14         26  
216             ###########################################
217 532         1860 ###########################################
218             my ($self, $cache) = @_;
219              
220 546         13539 $self->{appender}->log(@$cache);
221             }
222              
223             ##################################################
224             ##################################################
225             my($self, $name) = @_;
226 14     14 0 29  
227             # Somebody wants to *set* the name?
228 14         57 if($name) {
229             $self->{name} = $name;
230             }
231              
232             return $self->{name};
233             }
234 215     215 0 600  
235             ###########################################
236             # associated with this appender
237 215 50       628 ###########################################
238 0         0 my($self, $layout) = @_;
239              
240             # Somebody wants to *set* the layout?
241 215         764 if($layout) {
242             $self->{layout} = $layout;
243              
244             # somebody wants a layout, but not set yet, so give 'em default
245             }elsif (! $self->{layout}) {
246             $self->{layout} = Log::Log4perl::Layout::SimpleLayout
247             ->new($self->{name});
248 800     800 1 1839  
249             }
250              
251 800 100       2431 return $self->{layout};
    100          
252 298         1097 }
253              
254             ##################################################
255             ##################################################
256             my ($self, $filter) = @_;
257 7         52  
258             if($filter) {
259             print "Setting filter to $filter->{name}\n" if _INTERNAL_DEBUG;
260             $self->{filter} = $filter;
261 800         3414 }
262              
263             return $self->{filter};
264             }
265              
266             ##################################################
267 12     12 0 25 ##################################################
268             # Relay everything else to the underlying
269 12 50       26 # Log::Log4perl::Appender::* or Log::Dispatch::*
270 12         14 # object
271 12         24 ##################################################
272             my $self = shift;
273              
274 12         27 no strict qw(vars);
275              
276             $AUTOLOAD =~ s/.*:://;
277              
278             if(! defined $self->{appender}) {
279             die "Can't locate object method $AUTOLOAD() in ", __PACKAGE__;
280             }
281              
282             return $self->{appender}->$AUTOLOAD(@_);
283             }
284 271     271   26425  
285             ##################################################
286 70     70   583 ##################################################
  70         156  
  70         12330  
287             foreach my $key (keys %{$_[0]}) {
288 271         1550 # print "deleting $key\n";
289             delete $_[0]->{$key};
290 271 50       826 }
291 0         0 }
292              
293             1;
294 271         935  
295              
296             =encoding utf8
297              
298             =head1 NAME
299              
300 205     205   5448 Log::Log4perl::Appender - Log appender class
  205         881  
301              
302 1243         5487 =head1 SYNOPSIS
303              
304             use Log::Log4perl;
305              
306             # Define a logger
307             my $logger = Log::Log4perl->get_logger("abc.def.ghi");
308              
309             # Define a layout
310             my $layout = Log::Log4perl::Layout::PatternLayout->new(
311             "%d (%F:%L)> %m");
312              
313             # Define an appender
314             my $appender = Log::Log4perl::Appender->new(
315             "Log::Log4perl::Appender::Screen",
316             name => 'dumpy');
317              
318             # Set the appender's layout
319             $appender->layout($layout);
320             $logger->add_appender($appender);
321              
322             =head1 DESCRIPTION
323              
324             This class is a wrapper around the C<Log::Log4perl::Appender>
325             appender set.
326              
327             It also supports the <Log::Dispatch::*> collections of appenders. The
328             module hides the idiosyncrasies of C<Log::Dispatch> (e.g. every
329             dispatcher gotta have a name, but there's no accessor to retrieve it)
330             from C<Log::Log4perl> and yet re-uses the extremely useful variety of
331             dispatchers already created and tested in C<Log::Dispatch>.
332              
333             =head1 FUNCTIONS
334              
335             =head2 Log::Log4perl::Appender->new($dispatcher_class_name, ...);
336              
337             The constructor C<new()> takes the name of the appender
338             class to be created as a I<string> (!) argument, optionally followed by
339             a number of appender-specific parameters,
340             for example:
341              
342             # Define an appender
343             my $appender = Log::Log4perl::Appender->new(
344             "Log::Log4perl::Appender::File"
345             filename => 'out.log');
346              
347             In case of C<Log::Dispatch> appenders,
348             if no C<name> parameter is specified, the appender object will create
349             a unique one (format C<appNNN>), which can be retrieved later via
350             the C<name()> method:
351              
352             print "The appender's name is ", $appender->name(), "\n";
353              
354             Other parameters are specific to the appender class being used.
355             In the case above, the C<filename> parameter specifies the name of
356             the C<Log::Log4perl::Appender::File> dispatcher used.
357              
358             However, if, for instance,
359             you're using a C<Log::Dispatch::Email> dispatcher to send you
360             email, you'll have to specify C<from> and C<to> email addresses.
361             Every dispatcher is different.
362             Please check the C<Log::Dispatch::*> documentation for the appender used
363             for details on specific requirements.
364              
365             The C<new()> method will just pass these parameters on to a newly created
366             C<Log::Dispatch::*> object of the specified type.
367              
368             When it comes to logging, the C<Log::Log4perl::Appender> will transparently
369             relay all messages to the C<Log::Dispatch::*> object it carries
370             in its womb.
371              
372             =head2 $appender->layout($layout);
373              
374             The C<layout()> method sets the log layout
375             used by the appender to the format specified by the
376             C<Log::Log4perl::Layout::*> object which is passed to it as a reference.
377             Currently there's two layouts available:
378              
379             Log::Log4perl::Layout::SimpleLayout
380             Log::Log4perl::Layout::PatternLayout
381              
382             Please check the L<Log::Log4perl::Layout::SimpleLayout> and
383             L<Log::Log4perl::Layout::PatternLayout> manual pages for details.
384              
385             =head1 Supported Appenders
386              
387             Here's the list of appender modules currently available via C<Log::Dispatch>,
388             if not noted otherwise, written by Dave Rolsky:
389              
390             Log::Dispatch::ApacheLog
391             Log::Dispatch::DBI (by Tatsuhiko Miyagawa)
392             Log::Dispatch::Email,
393             Log::Dispatch::Email::MailSend,
394             Log::Dispatch::Email::MailSendmail,
395             Log::Dispatch::Email::MIMELite
396             Log::Dispatch::File
397             Log::Dispatch::FileRotate (by Mark Pfeiffer)
398             Log::Dispatch::Handle
399             Log::Dispatch::Screen
400             Log::Dispatch::Syslog
401             Log::Dispatch::Tk (by Dominique Dumont)
402              
403             C<Log4perl> doesn't care which ones you use, they're all handled in
404             the same way via the C<Log::Log4perl::Appender> interface.
405             Please check the well-written manual pages of the
406             C<Log::Dispatch> hierarchy on how to use each one of them.
407              
408             =head1 Parameters passed on to the appender's log() method
409              
410             When calling the appender's log()-Funktion, Log::Log4perl will
411             submit a list of key/value pairs. Entries to the following keys are
412             guaranteed to be present:
413              
414             =over 4
415              
416             =item message
417              
418             Text of the rendered message
419              
420             =item log4p_category
421              
422             Name of the category of the logger that triggered the event.
423              
424             =item log4p_level
425              
426             Log::Log4perl level of the event
427              
428             =back
429              
430             =head1 Pitfalls
431              
432             Since the C<Log::Dispatch::File> appender truncates log files by default,
433             and most of the time this is I<not> what you want, we've instructed
434             C<Log::Log4perl> to change this behavior by slipping it the
435             C<mode =E<gt> append> parameter behind the scenes. So, effectively
436             with C<Log::Log4perl> 0.23, a configuration like
437              
438             log4perl.category = INFO, FileAppndr
439             log4perl.appender.FileAppndr = Log::Dispatch::File
440             log4perl.appender.FileAppndr.filename = test.log
441             log4perl.appender.FileAppndr.layout = Log::Log4perl::Layout::SimpleLayout
442              
443             will always I<append> to an existing logfile C<test.log> while if you
444             specifically request clobbering like in
445              
446             log4perl.category = INFO, FileAppndr
447             log4perl.appender.FileAppndr = Log::Dispatch::File
448             log4perl.appender.FileAppndr.filename = test.log
449             log4perl.appender.FileAppndr.mode = write
450             log4perl.appender.FileAppndr.layout = Log::Log4perl::Layout::SimpleLayout
451              
452             it will overwrite an existing log file C<test.log> and start from scratch.
453              
454             =head1 Appenders Expecting Message Chunks
455              
456             Instead of simple strings, certain appenders are expecting multiple fields
457             as log messages. If a statement like
458              
459             $logger->debug($ip, $user, "signed in");
460              
461             causes an off-the-shelf C<Log::Log4perl::Appender::Screen>
462             appender to fire, the appender will
463             just concatenate the three message chunks passed to it
464             in order to form a single string.
465             The chunks will be separated by a string defined in
466             C<$Log::Log4perl::JOIN_MSG_ARRAY_CHAR> (defaults to the empty string
467             "").
468              
469             However, different appenders might choose to
470             interpret the message above differently: An
471             appender like C<Log::Log4perl::Appender::DBI> might take the
472             three arguments passed to the logger and put them in three separate
473             rows into the DB.
474              
475             The C<warp_message> appender option is used to specify the desired
476             behavior.
477             If no setting for the appender property
478              
479             # *** Not defined ***
480             # log4perl.appender.SomeApp.warp_message
481              
482             is defined in the Log4perl configuration file, the
483             appender referenced by C<SomeApp> will fall back to the standard behavior
484             and join all message chunks together, separating them by
485             C<$Log::Log4perl::JOIN_MSG_ARRAY_CHAR>.
486              
487             If, on the other hand, it is set to a false value, like in
488              
489             log4perl.appender.SomeApp.layout=NoopLayout
490             log4perl.appender.SomeApp.warp_message = 0
491              
492             then the message chunks are passed unmodified to the appender as an
493             array reference. Please note that you need to set the appender's
494             layout to C<Log::Log4perl::Layout::NoopLayout> which just leaves
495             the messages chunks alone instead of formatting them or replacing
496             conversion specifiers.
497              
498             B<Please note that the standard appenders in the Log::Dispatch hierarchy
499             will choke on a bunch of messages passed to them as an array reference.
500             You can't use C<warp_message = 0> (or the function name syntax
501             defined below) on them.
502             Only special appenders like Log::Log4perl::Appender::DBI can deal with
503             this.>
504              
505             If (and now we're getting fancy)
506             an appender expects message chunks, but we would
507             like to pre-inspect and probably modify them before they're
508             actually passed to the appender's C<log>
509             method, an inspection subroutine can be defined with the
510             appender's C<warp_message> property:
511              
512             log4perl.appender.SomeApp.layout=NoopLayout
513             log4perl.appender.SomeApp.warp_message = sub { \
514             $#_ = 2 if @_ > 3; \
515             return @_; }
516              
517             The inspection subroutine defined by the C<warp_message>
518             property will receive the list of message chunks, like they were
519             passed to the logger and is expected to return a corrected list.
520             The example above simply limits the argument list to a maximum of
521             three by cutting off excess elements and returning the shortened list.
522              
523             Also, the warp function can be specified by name like in
524              
525             log4perl.appender.SomeApp.layout=NoopLayout
526             log4perl.appender.SomeApp.warp_message = main::filter_my_message
527              
528             In this example,
529             C<filter_my_message> is a function in the C<main> package,
530             defined like this:
531              
532             my $COUNTER = 0;
533              
534             sub filter_my_message {
535             my @chunks = @_;
536             unshift @chunks, ++$COUNTER;
537             return @chunks;
538             }
539              
540             The subroutine above will add an ever increasing counter
541             as an additional first field to
542             every message passed to the C<SomeApp> appender -- but not to
543             any other appender in the system.
544              
545             =head2 Composite Appenders
546              
547             Composite appenders relay their messages to sub-appenders after providing
548             some filtering or synchronizing functionality on incoming messages.
549             Examples are
550             Log::Log4perl::Appender::Synchronized,
551             Log::Log4perl::Appender::Limit, and
552             Log::Log4perl::Appender::Buffer. Check their manual pages for details.
553              
554             Composite appender objects are regular Log::Log4perl::Appender objects,
555             but they have the composite flag set:
556              
557             $app->composite(1);
558              
559             and they define a post_init() method, which sets the appender it relays
560             its messages to:
561              
562             ###########################################
563             sub post_init {
564             ############################################
565             my($self) = @_;
566            
567             if(! exists $self->{appender}) {
568             die "No appender defined for " . __PACKAGE__;
569             }
570            
571             my $appenders = Log::Log4perl->appenders();
572             my $appender = Log::Log4perl->appenders()->{$self->{appender}};
573            
574             if(! defined $appender) {
575             die "Appender $self->{appender} not defined (yet) when " .
576             __PACKAGE__ . " needed it";
577             }
578            
579             $self->{app} = $appender;
580             }
581              
582             The reason for this post-processing step is that the relay appender
583             might not be defined yet when the composite appender gets defined.
584             This can happen if Log4perl is initialized with a configuration file
585             (which is the most common way to initialize Log4perl), because
586             appenders spring into existence in unpredictable order.
587              
588             For example, if you define a Synchronized appender like
589              
590             log4perl.appender.Syncer = Log::Log4perl::Appender::Synchronized
591             log4perl.appender.Syncer.appender = Logfile
592              
593             then Log4perl will set the appender's C<appender> attribute to the
594             I<name> of the appender to finally relay messages to. After the
595             Log4perl configuration file has been processed, Log4perl will remember to
596             call the composite appender's post_init() method, which will grab
597             the relay appender instance referred to by the name (Logfile)
598             and set it in its C<app> attribute. This is exactly what the
599             code snippet above does.
600              
601             But if you initialize Log4perl by its API, you need to remember to
602             perform these steps. Here's the lineup:
603              
604             use Log::Log4perl qw(get_logger :levels);
605            
606             my $fileApp = Log::Log4perl::Appender->new(
607             'Log::Log4perl::Appender::File',
608             name => 'MyFileApp',
609             filename => 'mylog',
610             mode => 'append',
611             );
612             $fileApp->layout(
613             Log::Log4perl::Layout::PatternLayout::Multiline->new(
614             '%d{yyyy-MM-dd HH:mm:ss} %p [%c] #%P> %m%n')
615             );
616             # Make the appender known to the system (without assigning it to
617             # any logger
618             Log::Log4perl->add_appender( $fileApp );
619            
620             my $syncApp = Log::Log4perl::Appender->new(
621             'Log::Log4perl::Appender::Synchronized',
622             name => 'MySyncApp',
623             appender => 'MyFileApp',
624             key => 'nem',
625             );
626             $syncApp->post_init();
627             $syncApp->composite(1);
628              
629             # The Synchronized appender is now ready, assign it to a logger
630             # and start logging.
631             get_logger("")->add_appender($syncApp);
632              
633             get_logger("")->level($DEBUG);
634             get_logger("wonk")->debug("waah!");
635              
636             The composite appender's log() function will typically cache incoming
637             messages until a certain trigger condition is met and then forward a bulk
638             of messages to the relay appender.
639              
640             Caching messages is surprisingly tricky, because you want them to look
641             like they came from the code location they were originally issued from
642             and not from the location that triggers the flush. Luckily, Log4perl
643             offers a cache mechanism for messages, all you need to do is call the
644             base class' log() function with an additional reference to a scalar,
645             and then save its content to your composite appender's message buffer
646             afterwards:
647              
648             ###########################################
649             sub log {
650             ###########################################
651             my($self, %params) = @_;
652              
653             # ... some logic to decide whether to cache or flush
654              
655             # Adjust the caller stack
656             local $Log::Log4perl::caller_depth =
657             $Log::Log4perl::caller_depth + 2;
658              
659             # We need to cache.
660             # Ask the appender to save a cached message in $cache
661             $self->{relay_app}->SUPER::log(\%params,
662             $params{log4p_category},
663             $params{log4p_level}, \my $cache);
664              
665             # Save it in the appender's message buffer
666             push @{ $self->{buffer} }, $cache;
667             }
668              
669             Note that before calling the log() method of the relay appender's base class
670             (and thus introducing two additional levels on the call stack), we need to
671             adjust the call stack to allow Log4perl to render cspecs like the %M or %L
672             correctly. The cache will then contain a correctly rendered message, according
673             to the layout of the target appender.
674              
675             Later, when the time comes to flush the cached messages, a call to the relay
676             appender's base class' log_cached() method with the cached message as
677             an argument will forward the correctly rendered message:
678              
679             ###########################################
680             sub log {
681             ###########################################
682             my($self, %params) = @_;
683              
684             # ... some logic to decide whether to cache or flush
685              
686             # Flush pending messages if we have any
687             for my $cache (@{$self->{buffer}}) {
688             $self->{relay_app}->SUPER::log_cached($cache);
689             }
690             }
691              
692              
693             =head1 SEE ALSO
694              
695             Log::Dispatch
696              
697             =head1 LICENSE
698              
699             Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt>
700             and Kevin Goess E<lt>cpan@goess.orgE<gt>.
701              
702             This library is free software; you can redistribute it and/or modify
703             it under the same terms as Perl itself.
704              
705             =head1 AUTHOR
706              
707             Please contribute patches to the project on Github:
708              
709             http://github.com/mschilli/log4perl
710              
711             Send bug reports or requests for enhancements to the authors via our
712              
713             MAILING LIST (questions, bug reports, suggestions/patches):
714             log4perl-devel@lists.sourceforge.net
715              
716             Authors (please contact them via the list above, not directly):
717             Mike Schilli <m@perlmeister.com>,
718             Kevin Goess <cpan@goess.org>
719              
720             Contributors (in alphabetical order):
721             Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
722             Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
723             Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
724             Grundman, Paul Harrington, Alexander Hartmaier David Hull,
725             Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter,
726             Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope,
727             Lars Thegler, David Viner, Mac Yang.
728