1 package Object::Remote::Logging;
5 use Object::Remote::LogRouter;
6 use Object::Remote::LogDestination;
7 use Log::Contextual::SimpleLogger;
10 use base qw(Log::Contextual);
13 return $_[1] if defined $_[1];
16 return $Router_Instance if defined $Router_Instance;
18 $Router_Instance = Object::Remote::LogRouter->new(
30 if ($ENV{OBJECT_REMOTE_LOG_LEVEL}) {
31 $class->init_logging_stderr($ENV{OBJECT_REMOTE_LOG_LEVEL});
35 sub init_logging_stderr {
36 my ($class, $level) = @_;
37 our $Log_Level = $level;
38 chomp(my $hostname = `hostname`);
40 our $Log_Output = Object::Remote::LogDestination->new(
41 logger => Log::Contextual::SimpleLogger->new({
42 levels_upto => $Log_Level,
45 my $time = sprintf("%0.2i:%0.2i:%0.2i", $t[2], $t[1], $t[0]);
46 print STDERR "[$hostname $$] $time ", @_
51 $Log_Output->connect($class->arg_router);
54 sub init_logging_forwarding {
55 # my ($class, $remote_parent) = @_;
56 # chomp(my $host = `hostname`);
57 # $class->arg_router->description("$$ $host");
58 # $class->arg_router->parent_router($remote_parent);
59 # $remote_parent->add_child_router($class->arg_router);
66 Hierarchical routed logging concept
70 Object::Remote and systems built on it would benefit from a standard model
71 for logging that enables simple and transparent log generation and consumption
72 that can cross the Perl interpreter instance boundaries. More
73 generally CPAN would benefit from a common logging framework that allows all
74 log message generators to play nicely with all log message consumers with out
75 making the generators or consumers jump through hoops to do what they want to do.
76 If these two solutions are the same then all modules built using the
77 logging framework will transparently operate properly when run under Object::Remote.
79 Such a solution needs to be flexible and have a low performance impact when it is not
80 actively logging. The hiearchy of log message routers is the way to achieve all of these
81 goals. The abstracted message router interface introduced to Log::Contextual allows
82 the hierarchical routing system to be built and tested inside Object::Remote with possible
83 larger scale deployment in the future.
85 Hierarchy of log routers
87 * Each Perl module ideally would use at least a router dedicated
88 to that module and may have child routers if the module is complex.
90 * Log messages inserted at low levels in the hierarchy
91 are available at routers at higher levels in the hierarchy.
93 * Each running Perl instance has a root router which receives
94 all log messages generated in the Perl instance.
96 * The routing hierarchy is available for introspection and connections
97 from child routers to parent routers have human readable descriptions
99 * The entire routing system is dynamic
100 * Add and remove routers while the system is in operation
101 * Add and remove subscriptions into routers while the system is in operation
103 * Auto-solves Object::Remote logging by setting the parent router of the
104 root router in the remote instance to a router in the local instance. The
105 log messages will flow into the local router via a proxy object.
107 * There needs to be two modes of operation for routed logging
108 * forwarding across Perl instances using Object::Remote proxies
109 for ease of use during normal operation
111 * STDERR output by default because not all logs can be forwarded
112 such as log messages for parts of Object::Remote that relate to
113 Object::Remote delivering the log.
120 * System::Introspector
126 * System::Introspector
131 * System::Introspector
135 [1] This router has all logs generated anywhere
137 [2] Everything related to Object::Remote including
138 log messages from remote nodes for things other
140 [3] Log messages generated by Object::Remote on the local
142 [4] All log messages from all remote nodes
143 [5] This is the connection from a remote instance to the
144 local instance using a proxy object - the name contains
145 the Object::Remote::Connection id for the remote node
147 As a demonstration of the flexibility of the this system consider a CPAN testers GUI
148 tool. This hypothetical tool would allow a tester to select a module by name and perform
149 the automated tests for that package and all dependent packages. Inside the tool is a pane for
150 the output of the process (STDOUT and STDERR), a pane for log messages, and a pane displaying
151 the modules that are participating in routed logging. The tester could then click on individual
152 packages and enable logging for that package dynamically. If neccassary more than one package
153 could be monitored if neccassary. If the GUI is wrapping a program that runs for long periods of
154 time or if the application is a daemon then being able to dynamically add and remove logging
157 Log message selection and output
160 * Modules and packages know how they want to format log messages.
161 * Consumers of log messages want to know
162 * Which Perl module/package generated that message.
163 * When running with Object::Remote if the log message is from
164 a remote connection and if so which connection.
165 * Consumers of a log message know how they want to output them. The logger
166 should not be enforcing a specific type of log output.
167 * Most log messages most of the time will be completely ignored and unused.
168 * Router subscriptions
169 * A consumer of log messages will subscribe to a router at any arbitrary point
170 in the router hierarchy even across machines if Object::Remote is involved
171 * The subscription is used to access a stream of log data and is not used to select
172 which packages/modules should be logged
173 * For instance the Object::Remote log router has log messages flowing through
174 it that include logs generated on remote nodes even if those logs were generated
175 by a module other than Object::Remote
178 * The module has defined what the log message format is
179 * The subscription has defined the scope of messages that will be
180 available for selection, ie: all log messages everywhere,
181 all logs generated on Object::Remote nodes, etc
182 * Selection defines what log messages are going to be delivered
183 to a logger object instance
184 * Selectors act as a gate between a subscription and the logger object
185 * Selectors are closures that perform introspection on the log
186 message and metadata; if the selector returns true the logger
187 will be invoked to log this message
188 * The logger still has a log level assigned to it and still will have
189 the is_$level method invoked to only log at that specific level
192 * A log destination is an instance of a logger object and the associated
194 * Consuming logging data from this system is a matter of
195 * Constructing an instance of a logging destination object which has
196 the following attributes:
197 * logger - the logger object
198 * selectors - a list of closures; the first one that returns true
199 causes the logger to be checked for this log_level and
201 * Register selectors with the destination by invoking a method and specifying
202 sub refs as an argument
204 Technical considerations
205 * The routing hierarchy has cycles where parent routers hold a reference to the child
206 and the child holds a reference to the parent. The cycles are not a problem if weak
207 references are used however proxy objects don't seem to currently work with weak
209 * Once a logger hits a proxy object the caller information is totally blown; this
210 crossing isn't transparent yet
211 * If Object::Remote is logging its actions and those logs are being forwarded then
212 logs can be generated from the forwarding itself creating an infinite loop. Only
213 a portion of Object::Remote can be forwarded.