perltidy code and add .perltidyrc to repo
[p5sagit/Log-Contextual.git] / lib / Log / Contextual.pm
index 1d0a1dc..9e8ca08 100644 (file)
@@ -12,10 +12,6 @@ use Exporter::Declare::Export::Generator;
 use Data::Dumper::Concise;
 use Scalar::Util 'blessed';
 
-my @dlog = ((map "Dlog_$_", @levels), (map "DlogS_$_", @levels));
-
-my @log = ((map "log_$_", @levels), (map "logS_$_", @levels));
-
 eval {
    require Log::Log4perl;
    die if $Log::Log4perl::VERSION < 1.29;
@@ -24,151 +20,144 @@ eval {
 
 # ____ is because tags must have at least one export and we don't want to
 # export anything but the levels selected
-sub ____ {}
+sub ____ { }
 
-exports ('____',
-   @dlog, @log,
-   qw( set_logger with_logger )
-);
+exports(qw(____ set_logger with_logger ));
 
 export_tag dlog => ('____');
 export_tag log  => ('____');
 import_arguments qw(logger package_logger default_logger);
 
-sub before_import {
-   my ($class, $importer, $spec) = @_;
-
-   die 'Log::Contextual does not have a default import list'
-      if $spec->config->{default};
-
-   my @levels = @{$class->arg_levels($spec->config->{levels})};
-   for my $level (@levels) {
-      if ($spec->config->{log}) {
-         $spec->add_export("&log_$level", sub (&@) {
-            _do_log( $level => _get_logger( caller ), shift @_, @_)
-         });
-         $spec->add_export("&logS_$level", sub (&@) {
-            _do_logS( $level => _get_logger( caller ), $_[0], $_[1])
-         });
-      }
-      if ($spec->config->{dlog}) {
-         $spec->add_export("&Dlog_$level", sub (&@) {
-           my ($code, @args) = @_;
-           return _do_log( $level => _get_logger( caller ), sub {
-              local $_ = (@args?Data::Dumper::Concise::Dumper @args:'()');
-              $code->(@_)
-           }, @args );
-         });
-         $spec->add_export("&DlogS_$level", sub (&$) {
-           my ($code, $ref) = @_;
-           _do_logS( $level => _get_logger( caller ), sub {
-              local $_ = Data::Dumper::Concise::Dumper $ref;
-              $code->($ref)
-           }, $ref )
-         });
-      }
-   }
+sub router {
+   our $Router_Instance ||= do {
+      require Log::Contextual::Router;
+      Log::Contextual::Router->new
+     }
 }
 
-sub arg_logger { $_[1] }
-sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] }
+sub arg_logger         { $_[1] }
+sub arg_levels         { $_[1] || [qw(debug trace warn info error fatal)] }
 sub arg_package_logger { $_[1] }
 sub arg_default_logger { $_[1] }
 
-sub after_import {
-   my ($class, $importer, $specs) = @_;
+sub before_import {
+   my ($class, $importer, $spec) = @_;
+   my $router      = $class->router;
+   my $exports     = $spec->exports;
+   my %router_args = (
+      exporter  => $class,
+      target    => $importer,
+      arguments => $spec->argument_info
+   );
 
-   if (my $l = $class->arg_logger($specs->config->{logger})) {
-      set_logger($l)
-   }
+   die 'Log::Contextual does not have a default import list'
+     if $spec->config->{default};
 
-   if (my $l = $class->arg_package_logger($specs->config->{package_logger})) {
-      _set_package_logger_for($importer, $l)
-   }
+   $router->before_import(%router_args);
 
-   if (my $l = $class->arg_default_logger($specs->config->{default_logger})) {
-      _set_default_logger_for($importer, $l)
-   }
-}
+   $spec->add_export(
+      '&set_logger',
+      sub {
+         my $router = $class->router;
 
-our $Get_Logger;
-our %Default_Logger;
-our %Package_Logger;
+         die ref($router) . " does not support set_logger()"
+           unless $router->does('Log::Contextual::Role::Router::SetLogger');
 
-sub _set_default_logger_for {
-   my $logger = $_[1];
-   if(ref $logger ne 'CODE') {
-      die 'logger was not a CodeRef or a logger object.  Please try again.'
-         unless blessed($logger);
-      $logger = do { my $l = $logger; sub { $l } }
-   }
-   $Default_Logger{$_[0]} = $logger
-}
+         return $router->set_logger(@_);
+      }) if $exports->{'&set_logger'};
 
-sub _set_package_logger_for {
-   my $logger = $_[1];
-   if(ref $logger ne 'CODE') {
-      die 'logger was not a CodeRef or a logger object.  Please try again.'
-         unless blessed($logger);
-      $logger = do { my $l = $logger; sub { $l } }
-   }
-   $Package_Logger{$_[0]} = $logger
-}
-
-sub _get_logger($) {
-   my $package = shift;
-   (
-      $Package_Logger{$package} ||
-      $Get_Logger ||
-      $Default_Logger{$package} ||
-      die q( no logger set!  you can't try to log something without a logger! )
-   )->($package, { caller_level => 2 });
-}
+   $spec->add_export(
+      '&with_logger',
+      sub {
+         my $router = $class->router;
 
-sub set_logger {
-   my $logger = $_[0];
-   if(ref $logger ne 'CODE') {
-      die 'logger was not a CodeRef or a logger object.  Please try again.'
-         unless blessed($logger);
-      $logger = do { my $l = $logger; sub { $l } }
-   }
+         die ref($router) . " does not support with_logger()"
+           unless $router->does('Log::Contextual::Role::Router::WithLogger');
 
-   warn 'set_logger (or -logger) called more than once!  This is a bad idea!'
-      if $Get_Logger;
-   $Get_Logger = $logger;
-}
+         return $router->with_logger(@_);
+      }) if $exports->{'&with_logger'};
 
-sub with_logger {
-   my $logger = $_[0];
-   if(ref $logger ne 'CODE') {
-      die 'logger was not a CodeRef or a logger object.  Please try again.'
-         unless blessed($logger);
-      $logger = do { my $l = $logger; sub { $l } }
+   my @levels = @{$class->arg_levels($spec->config->{levels})};
+   for my $level (@levels) {
+      if ($spec->config->{log}) {
+         $spec->add_export(
+            "&log_$level",
+            sub (&@) {
+               my ($code, @args) = @_;
+               $router->handle_log_request(
+                  exporter       => $class,
+                  caller_package => scalar(caller),
+                  caller_level   => 1,
+                  message_level  => $level,
+                  message_sub    => $code,
+                  message_args   => \@args,
+               );
+               return @args;
+            });
+         $spec->add_export(
+            "&logS_$level",
+            sub (&@) {
+               my ($code, @args) = @_;
+               $router->handle_log_request(
+                  exporter       => $class,
+                  caller_package => scalar(caller),
+                  caller_level   => 1,
+                  message_level  => $level,
+                  message_sub    => $code,
+                  message_args   => \@args,
+               );
+               return $args[0];
+            });
+      }
+      if ($spec->config->{dlog}) {
+         $spec->add_export(
+            "&Dlog_$level",
+            sub (&@) {
+               my ($code, @args) = @_;
+               my $wrapped = sub {
+                  local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()');
+                  &$code;
+               };
+               $router->handle_log_request(
+                  exporter       => $class,
+                  caller_package => scalar(caller),
+                  caller_level   => 1,
+                  message_level  => $level,
+                  message_sub    => $wrapped,
+                  message_args   => \@args,
+               );
+               return @args;
+            });
+         $spec->add_export(
+            "&DlogS_$level",
+            sub (&$) {
+               my ($code, $ref) = @_;
+               my $wrapped = sub {
+                  local $_ = Data::Dumper::Concise::Dumper($_[0]);
+                  &$code;
+               };
+               $router->handle_log_request(
+                  exporter       => $class,
+                  caller_package => scalar(caller),
+                  caller_level   => 1,
+                  message_level  => $level,
+                  message_sub    => $wrapped,
+                  message_args   => [$ref],
+               );
+               return $ref;
+            });
+      }
    }
-   local $Get_Logger = $logger;
-   $_[1]->();
 }
 
-sub _do_log {
-   my $level  = shift;
-   my $logger = shift;
-   my $code   = shift;
-   my @values = @_;
-
-   $logger->$level($code->(@_))
-      if $logger->${\"is_$level"};
-   @values
-}
-
-sub _do_logS {
-   my $level  = shift;
-   my $logger = shift;
-   my $code   = shift;
-   my $value  = shift;
-
-   $logger->$level($code->($value))
-      if $logger->${\"is_$level"};
-   $value
+sub after_import {
+   my ($class, $importer, $spec) = @_;
+   my %router_args = (
+      exporter  => $class,
+      target    => $importer,
+      arguments => $spec->argument_info
+   );
+   $class->router->after_import(%router_args);
 }
 
 1;
@@ -626,10 +615,27 @@ The first six merely need to return true if that level is enabled.  The latter
 six take the results of whatever the user returned from their coderef and log
 them.  For a basic example see L<Log::Contextual::SimpleLogger>.
 
+=head1 LOG ROUTING
+
+In between the loggers and the log functions is a log router that is responsible for
+finding a logger to handle the log event and passing the log information to the
+logger. This relationship is described in the documentation for C<Log::Contextual::Role::Router>.
+
+C<Log::Contextual> and packages that extend it will by default share a router singleton that
+implements the with_logger() and set_logger() functions and also respects the -logger,
+-package_logger, and -default_logger import options with their associated default value
+functions. The router singleton is available as the return value of the router() function. Users
+of Log::Contextual may overload router() to return instances of custom log routers that
+could for example work with loggers that use a different interface.
+
 =head1 AUTHOR
 
 frew - Arthur Axel "fREW" Schmidt <frioux@gmail.com>
 
+=head1 CONTRIBUTORS
+
+triddle - Tyler Riddle <t.riddle@shadowcat.co.uk>
+
 =head1 DESIGNER
 
 mst - Matt S. Trout <mst@shadowcat.co.uk>