revise log router api to match log::contextual router api change
Tyler Riddle [Tue, 16 Oct 2012 01:27:19 +0000 (18:27 -0700)]
lib/Object/Remote/LogDestination.pm
lib/Object/Remote/LogRouter.pm
lib/Object/Remote/Logging.pm
lib/Object/Remote/Role/LogForwarder.pm

index 67f436a..7cdbbd1 100644 (file)
@@ -10,7 +10,7 @@ sub select {
   my ($self, $router, $selector) = @_; 
   my $subscription = $router->subscribe($self->logger, $selector); 
   push(@{ $self->subscriptions }, $subscription);
-  return $subscription; 
+  return $self;
 }
 
 sub connect {
index 671856a..3b1f655 100644 (file)
@@ -12,53 +12,32 @@ sub before_import { }
 sub after_import { }
 
 sub subscribe {
-  my ($self, $logger, $selector, $is_temp) = @_; 
+  my ($self, $logger, $selector) = @_;
   my $subscription_list = $self->subscriptions;
-   
-  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 $subscription = [ $logger, $selector ];
+     
+  my $subscription = [ $logger, $selector ];
   
-   $is_temp = 0 unless defined $is_temp; 
-   push(@$subscription_list, $subscription);
-   if ($is_temp) {
-     #weaken($subscription->[-1]);
-   }
-   return $subscription; 
+  push(@$subscription_list, $subscription);
+   
+  return $self; 
 }
 
 #TODO turn this logic into a role
-sub handle_log_message {
-  my ($self, $caller, $level, $log_meth, @values) = @_; 
+sub get_loggers {
+  my ($self, $caller, $level) = @_; 
   my $should_clean = 0; 
+  my @logger_list; 
       
   foreach(@{ $self->subscriptions }) {
-    unless(defined($_)) {
+    unless(defined) {
       $should_clean = 1;
         next; 
      }
+     
      my ($logger, $selector) = @$_;
-     #TODO this is not a firm part of the api but providing
-     #this info to the selector is a good feature
-     local($_) = { level => $level, package => $caller };
-     if ($selector->(@values)) {
-        #TODO issues with caller_level have not been resolved yet
-        #when a logger crosses an object::remote::connection so
-        $logger = $logger->($caller, { caller_level => -1 });
-        
-        #TODO there is a known issue with the interaction of this 
-        #routed logging scheme and objects proxied with Object::Remote.
-        #Specifically the loggers must be invoked with a calling
-        #depth of 0 which isn't possible using a logger that has
-        #been proxied which is what happens with routed logging
-        #if the logger is created in one Perl interpreter and the
-        #logging happens in another
-        $logger->$level($log_meth->(@values))
-          if $logger->${\"is_$level"};
+     
+     if ($selector->({ log_level => $level, package => $caller, caller_level => 2 })) {
+       push(@logger_list, $logger);     
      }
    }
    
@@ -66,7 +45,7 @@ sub handle_log_message {
      $self->_remove_dead_subscriptions; 
    }
    
-   return; 
+   return @logger_list; 
 }
 
 sub _remove_dead_subscriptions {
index b9276e9..f2fec49 100644 (file)
@@ -36,16 +36,18 @@ sub init_logging_stderr {
   my ($class, $level) = @_;
   our $Log_Level = $level;
   chomp(my $hostname = `hostname`);
+  
   our $Log_Output = Object::Remote::LogDestination->new(
     logger => Log::Contextual::SimpleLogger->new({ 
       levels_upto => $Log_Level,
       coderef => sub { 
         my @t = localtime();
         my $time = sprintf("%0.2i:%0.2i:%0.2i", $t[2], $t[1], $t[0]);
-        warn "[$hostname $$] $time ", @_ 
+        print STDERR "[$hostname $$] $time ", @_ 
       },
     })
   );
+  
   $Log_Output->connect($class->arg_router);
 }
 
@@ -59,153 +61,159 @@ sub init_logging_forwarding {
 
 1;
 
-#__END__
-#
-#Hierarchical routed logging concept
-#
-#  Why?
-#  
-#  Object::Remote and systems built on it would benefit from a standard model
-#  for logging that enables simple and transparent log generation and consumption
-#  that can cross the Perl interpreter instance boundaries transparently. More 
-#  generally CPAN would benefit from a common logging framework that allows all
-#  log message generators to play nicely with all log message consumers with out
-#  making the generators or consumers jump through hoops to do what they want to do. 
-#  If these two solutions are the same then all modules built using the
-#  logging framework will transparently operate properly when run under Object::Remote.
-#  
-#  Such a solution needs to be flexible and have a low performance impact when it is not
-#  actively logging. The hiearchy of log message routers is the way to achieve all of these
-#  goals. The abstracted message router interface introduced to Log::Contextual allows 
-#  the hierarchical routing system to be built and tested inside Object::Remote with possible
-#  larger scale deployment in the future.
-#  
-#  Hierarchy of log routers
-#  
-#    * Each Perl module ideally would use at least a router dedicated
-#      to that module and may have child routers if the module is complex.
-#    * Log messages inserted at low levels in the hierarchy
-#      are available at routers at higher levels in the hierarchy.
-#    * Each running Perl instance has a root router which receives
-#      all log messages generated in the Perl instance.
-#    * The routing hierarchy is available for introspection and connections
-#      from child routers to parent routers have human readable strings
-#    * The entire routing system is dynamic
-#       * Add and remove routers while the system is in operation
-#       * Add and remove taps into routers while the system is in operation
-#    * Auto-solves Object::Remote logging by setting the parent router of the
-#      root router in the remote instance to a router in the local instance the
-#      log messages will flow into the local router via a proxy object
-#       * Should probably be two modes of operation for Object::Remote logging
-#          * forwarding across instances for ease of use during normal operation
-#          * stderr output by default for debugging cases to limit the usage of
-#            object::remote   
-#
-#
-#  Example hiearchy
-#  
-#     Root                [1]
-#       * System::Introspector
-#       * Object::Remote  [2]
-#          * local        [3]
-#          * remote       [4]
-#             * hostname-1.example.com [5]
-#                * Root
-#                   * System::Introspector
-#                   * Object::Remote
-#                      * local
-#             * hostname-2.example.com
-#                 * Root
-#                   * System::Introspector
-#                   * Object::Remote
-#                      * local
-#    
-#      [1] This router has all logs generated anywhere
-#          even on remote hosts        
-#      [2] Everything related to Object::Remote including
-#          log messages from remote nodes for things other
-#          than Object::Remote     
-#      [3] Log messages generated by Object::Remote on the local
-#          node only        
-#      [4] All log messages from all remote nodes    
-#      [5] This is the connection from a remote instance to the
-#          local instance using a proxy object
-#
-#      As a demonstration of the flexibility of the this system consider a CPAN testers GUI 
-#      tool. This hypothetical tool would allow a tester to select a module by name and perform
-#      the automated tests for that package and all dependent packages. Inside the tool is a pane for
-#      the output of the process (STDOUT and STDERR), a pane for log messages, and a pane displaying
-#      the modules that are participating in routed logging. The tester could then click on individual
-#      packages and enable logging for that package dynamically. If neccassary more than one package
-#      could be monitored if neccassary. If the GUI is wrapping a program that runs for long periods of
-#      time or if the application is a daemon then being able to dynamically add and remove logging
-#      becomes very useful.
-#   
-#   Log message selection and output
-#   
-#      * Assumptions
-#         * Modules and packages know how they want to format log messages
-#         * Consumers of log messages want to know
-#            * Which Perl module/package generated that message
-#            * When running with Object::Remote if the log message is from
-#              a remote node and if so which node
-#         * Consuming a log message is something the consumer knows how it wants
-#           to be done; the module/package should not be dictating how to receive
-#           the log messages
-#         * Most log messages most of the time will be completely ignored and unused
-#       * Router taps
-#          * A consumer of log messages will tap into a router at any arbitrary point
-#            in the router hierarchy even across machines if Object::Remote is involved
-#          * The tap is used to access a stream of log data and is not used to select
-#            which packages/modules should be logged
-#             * For instance Object::Remote has log messages flowing through it that 
-#               include logs generated on remote nodes even if those logs were generated
-#               by a module other than Object::Remote
-#       * Selection
-#          * The module has defined what the log message format is
-#          * The tap has defined the scope of messages that will be 
-#            available for selection, ie: all log messages everywhere,
-#            all logs generated on Object::Remote nodes, etc
-#          * Selection defines what log messages are going to be delivered
-#            to a logger object instance
-#             * Selectors act as a gate between a tap and the logger object
-#             * Selectors are closures that perform introspection on the log
-#               message; if the selector returns true the logger will be invoked
-#               to log this message
-#             * The logger still has a log level assigned to it and still will have
-#               the is_$level method invoked to only log at that specific level
-#       * Destinations
-#          * A log destination is an instance of a logger object and the associated
-#            selectors.
-#          * Consuming logging data from this system is a matter of
-#             * Constructing an instance of a logging destination object which has
-#               the following attributes:
-#                * logger - the logger object, like warnlogger or log4perl instance
-#                * selectors - a list of closures; the first one that returns true
-#                              causes the logger to be checked for this log_level and
-#                              invoked if neccassary 
-#          * Register selectors with the destination by invoking a method and specifying
-#            sub refs as an argument 
-#      
-#   Technical considerations
-#      * Log contextual likes to have the logger invoked directly inside the exported log
-#        specific methods because it removes a need to muck with logger caller depths to
-#        report back the proper caller information for the logger.
-#         * Because of this the best strategy identified is to return a list of loggers
-#           to those exported methods which then invoke the loggers inside the method
-#         * This means that log message forwarding is a process of querying each parent
-#           router for a list of logger objects that should be invoked. Each router along
-#           the hierarchy adds to this list and the log_* method will invoke all loggers
-#           directly. 
-#      * The routing hierarchy has cycles where parent routers hold a reference to the child
-#        and the child holds a reference to the parent. The cycles are not a problem if weak
-#        references are used however proxy objects don't seem to currently work with weak
-#        references. 
-#      * Once a logger hits a proxy object the caller information is totally blown; this
-#        crossing isn't transparent yet
-#       
-#       
-#       
+__END__
+
+Hierarchical routed logging concept
+
+  Why?
+  
+  Object::Remote and systems built on it would benefit from a standard model
+  for logging that enables simple and transparent log generation and consumption
+  that can cross the Perl interpreter instance boundaries. More 
+  generally CPAN would benefit from a common logging framework that allows all
+  log message generators to play nicely with all log message consumers with out
+  making the generators or consumers jump through hoops to do what they want to do. 
+  If these two solutions are the same then all modules built using the
+  logging framework will transparently operate properly when run under Object::Remote.
+  
+  Such a solution needs to be flexible and have a low performance impact when it is not
+  actively logging. The hiearchy of log message routers is the way to achieve all of these
+  goals. The abstracted message router interface introduced to Log::Contextual allows 
+  the hierarchical routing system to be built and tested inside Object::Remote with possible
+  larger scale deployment in the future.
+  
+  Hierarchy of log routers
+  
+    * Each Perl module ideally would use at least a router dedicated
+      to that module and may have child routers if the module is complex.
+      
+    * Log messages inserted at low levels in the hierarchy
+      are available at routers at higher levels in the hierarchy.
+      
+    * Each running Perl instance has a root router which receives
+      all log messages generated in the Perl instance.
+      
+    * The routing hierarchy is available for introspection and connections
+      from child routers to parent routers have human readable descriptions
+      
+    * The entire routing system is dynamic
+       * Add and remove routers while the system is in operation
+       * Add and remove subscriptions into routers while the system is in operation
+       
+    * Auto-solves Object::Remote logging by setting the parent router of the
+      root router in the remote instance to a router in the local instance. The
+      log messages will flow into the local router via a proxy object.
+      
+       * There needs to be two modes of operation for routed logging
+          * forwarding across Perl instances using Object::Remote proxies
+              for ease of use during normal operation
+              
+          * STDERR output by default because not all logs can be forwarded
+            such as log messages for parts of Object::Remote that relate to 
+            Object::Remote delivering the log. 
+            
+
+
+  Example hiearchy
+  
+   * Root                [1]
+       * System::Introspector
+       * Object::Remote  [2]
+          * local        [3]
+          * remote       [4]
+             * connection #1 [5]
+                * Root
+                   * System::Introspector
+                   * Object::Remote
+                      * local
+             * connection #2
+                 * Root
+                   * System::Introspector
+                   * Object::Remote
+                      * local
+    
+      [1] This router has all logs generated anywhere
+          even on remote hosts        
+      [2] Everything related to Object::Remote including
+          log messages from remote nodes for things other
+          than Object::Remote     
+      [3] Log messages generated by Object::Remote on the local
+          node only        
+      [4] All log messages from all remote nodes    
+      [5] This is the connection from a remote instance to the
+          local instance using a proxy object - the name contains
+          the Object::Remote::Connection id for the remote node
+
+      As a demonstration of the flexibility of the this system consider a CPAN testers GUI 
+      tool. This hypothetical tool would allow a tester to select a module by name and perform
+      the automated tests for that package and all dependent packages. Inside the tool is a pane for
+      the output of the process (STDOUT and STDERR), a pane for log messages, and a pane displaying
+      the modules that are participating in routed logging. The tester could then click on individual
+      packages and enable logging for that package dynamically. If neccassary more than one package
+      could be monitored if neccassary. If the GUI is wrapping a program that runs for long periods of
+      time or if the application is a daemon then being able to dynamically add and remove logging
+      becomes very useful.
+   
+   Log message selection and output
+   
+      * Assumptions
+         * Modules and packages know how they want to format log messages.
+         * Consumers of log messages want to know
+            * Which Perl module/package generated that message.
+            * When running with Object::Remote if the log message is from
+              a remote connection and if so which connection.
+         * Consumers of a log message know how they want to output them. The logger
+           should not be enforcing a specific type of log output. 
+         * Most log messages most of the time will be completely ignored and unused.
+       * Router subscriptions
+          * A consumer of log messages will subscribe to a router at any arbitrary point
+            in the router hierarchy even across machines if Object::Remote is involved
+          * The subscription is used to access a stream of log data and is not used to select
+            which packages/modules should be logged
+             * For instance the Object::Remote log router has log messages flowing through 
+               it that include logs generated on remote nodes even if those logs were generated
+               by a module other than Object::Remote
+               
+       * Selection
+          * The module has defined what the log message format is
+          * The subscription has defined the scope of messages that will be 
+            available for selection, ie: all log messages everywhere,
+            all logs generated on Object::Remote nodes, etc
+          * Selection defines what log messages are going to be delivered
+            to a logger object instance
+             * Selectors act as a gate between a subscription and the logger object
+             * Selectors are closures that perform introspection on the log
+               message and metadata; if the selector returns true the logger 
+               will be invoked to log this message
+             * The logger still has a log level assigned to it and still will have
+               the is_$level method invoked to only log at that specific level
+               
+       * Destinations
+          * A log destination is an instance of a logger object and the associated
+            subscriptions.
+          * Consuming logging data from this system is a matter of
+             * Constructing an instance of a logging destination object which has
+               the following attributes:
+                * logger - the logger object
+                * selectors - a list of closures; the first one that returns true
+                              causes the logger to be checked for this log_level and
+                              invoked if needed 
+          * Register selectors with the destination by invoking a method and specifying
+            sub refs as an argument 
+      
+   Technical considerations
+      * The routing hierarchy has cycles where parent routers hold a reference to the child
+        and the child holds a reference to the parent. The cycles are not a problem if weak
+        references are used however proxy objects don't seem to currently work with weak
+        references. 
+      * Once a logger hits a proxy object the caller information is totally blown; this
+        crossing isn't transparent yet
+      * If Object::Remote is logging its actions and those logs are being forwarded then
+        logs can be generated from the forwarding itself creating an infinite loop. Only
+        a portion of Object::Remote can be forwarded.  
+       
+       
+       
 
 
 
index d57a7b8..5be6851 100644 (file)
@@ -52,7 +52,7 @@ sub add_child_router {
 #  return delete $self->child_routers->{$description};
 #}
 
-after handle_log_message => sub {
+after get_loggers => sub {
   my ($self, @args) = @_;
   my $parent = $self->parent_router;