more log lines - found deadlock where controller blocks on read seemingly outside...
[scpubgit/Object-Remote.git] / lib / Object / Remote / Logging.pm
CommitLineData
5e2b2229 1package Object::Remote::Logging;
2
3use strictures 1;
4
f7ea4120 5use Log::Contextual qw( :log );
6use Object::Remote::LogRouter;
4a9fa1a5 7use Object::Remote::LogDestination;
8use Log::Contextual::SimpleLogger;
9use Carp qw(cluck);
5e2b2229 10
f7ea4120 11use base qw(Log::Contextual);
5e2b2229 12
4a9fa1a5 13sub arg_router {
5d59cb98 14 return $_[1] if defined $_[1];
15 our $Router_Instance;
4a9fa1a5 16
5d59cb98 17 return $Router_Instance if defined $Router_Instance;
4a9fa1a5 18
5d59cb98 19 $Router_Instance = Object::Remote::LogRouter->new(
20 description => $_[0],
21 );
4a9fa1a5 22}
5e2b2229 23
4a9fa1a5 24sub init_logging {
5d59cb98 25 my ($class) = @_;
26 our $Did_Init;
4a9fa1a5 27
5d59cb98 28 return if $Did_Init;
29 $Did_Init = 1;
4a9fa1a5 30
5d59cb98 31 if ($ENV{OBJECT_REMOTE_LOG_LEVEL}) {
32 $class->init_logging_stderr($ENV{OBJECT_REMOTE_LOG_LEVEL});
33 }
4a9fa1a5 34}
35
36sub init_logging_stderr {
5d59cb98 37 my ($class, $level) = @_;
38 our $Log_Level = $level;
39 chomp(my $hostname = `hostname`);
40 our $Log_Output = Object::Remote::LogDestination->new(
41 logger => Log::Contextual::SimpleLogger->new({
42 levels_upto => $Log_Level,
43 coderef => sub {
44 my @t = localtime();
45 my $time = sprintf("%0.2i:%0.2i:%0.2i", $t[2], $t[1], $t[0]);
46 warn "[$hostname $$] $time ", @_
47 },
48 })
49 );
50 $Log_Output->connect($class->arg_router);
4a9fa1a5 51}
52
53sub init_logging_forwarding {
5d59cb98 54# my ($class, $remote_parent) = @_;
55# chomp(my $host = `hostname`);
56# $class->arg_router->description("$$ $host");
57# $class->arg_router->parent_router($remote_parent);
58# $remote_parent->add_child_router($class->arg_router);
4a9fa1a5 59}
5e2b2229 60
611;
62
4a9fa1a5 63#__END__
64#
65#Hierarchical routed logging concept
66#
67# Why?
68#
69# Object::Remote and systems built on it would benefit from a standard model
70# for logging that enables simple and transparent log generation and consumption
71# that can cross the Perl interpreter instance boundaries transparently. More
72# generally CPAN would benefit from a common logging framework that allows all
73# log message generators to play nicely with all log message consumers with out
74# making the generators or consumers jump through hoops to do what they want to do.
75# If these two solutions are the same then all modules built using the
76# logging framework will transparently operate properly when run under Object::Remote.
77#
78# Such a solution needs to be flexible and have a low performance impact when it is not
79# actively logging. The hiearchy of log message routers is the way to achieve all of these
80# goals. The abstracted message router interface introduced to Log::Contextual allows
81# the hierarchical routing system to be built and tested inside Object::Remote with possible
82# larger scale deployment in the future.
83#
84# Hierarchy of log routers
85#
86# * Each Perl module ideally would use at least a router dedicated
87# to that module and may have child routers if the module is complex.
88# * Log messages inserted at low levels in the hierarchy
89# are available at routers at higher levels in the hierarchy.
90# * Each running Perl instance has a root router which receives
91# all log messages generated in the Perl instance.
92# * The routing hierarchy is available for introspection and connections
93# from child routers to parent routers have human readable strings
94# * The entire routing system is dynamic
95# * Add and remove routers while the system is in operation
96# * Add and remove taps into routers while the system is in operation
97# * Auto-solves Object::Remote logging by setting the parent router of the
98# root router in the remote instance to a router in the local instance the
99# log messages will flow into the local router via a proxy object
100# * Should probably be two modes of operation for Object::Remote logging
101# * forwarding across instances for ease of use during normal operation
102# * stderr output by default for debugging cases to limit the usage of
103# object::remote
104#
105#
106# Example hiearchy
107#
108# Root [1]
109# * System::Introspector
110# * Object::Remote [2]
111# * local [3]
112# * remote [4]
113# * hostname-1.example.com [5]
114# * Root
115# * System::Introspector
116# * Object::Remote
117# * local
118# * hostname-2.example.com
119# * Root
120# * System::Introspector
121# * Object::Remote
122# * local
123#
124# [1] This router has all logs generated anywhere
125# even on remote hosts
126# [2] Everything related to Object::Remote including
127# log messages from remote nodes for things other
128# than Object::Remote
129# [3] Log messages generated by Object::Remote on the local
130# node only
131# [4] All log messages from all remote nodes
132# [5] This is the connection from a remote instance to the
133# local instance using a proxy object
134#
135# As a demonstration of the flexibility of the this system consider a CPAN testers GUI
136# tool. This hypothetical tool would allow a tester to select a module by name and perform
137# the automated tests for that package and all dependent packages. Inside the tool is a pane for
138# the output of the process (STDOUT and STDERR), a pane for log messages, and a pane displaying
139# the modules that are participating in routed logging. The tester could then click on individual
140# packages and enable logging for that package dynamically. If neccassary more than one package
141# could be monitored if neccassary. If the GUI is wrapping a program that runs for long periods of
142# time or if the application is a daemon then being able to dynamically add and remove logging
143# becomes very useful.
144#
145# Log message selection and output
146#
147# * Assumptions
148# * Modules and packages know how they want to format log messages
149# * Consumers of log messages want to know
150# * Which Perl module/package generated that message
151# * When running with Object::Remote if the log message is from
152# a remote node and if so which node
153# * Consuming a log message is something the consumer knows how it wants
154# to be done; the module/package should not be dictating how to receive
155# the log messages
156# * Most log messages most of the time will be completely ignored and unused
157# * Router taps
158# * A consumer of log messages will tap into a router at any arbitrary point
159# in the router hierarchy even across machines if Object::Remote is involved
160# * The tap is used to access a stream of log data and is not used to select
161# which packages/modules should be logged
162# * For instance Object::Remote has log messages flowing through it that
163# include logs generated on remote nodes even if those logs were generated
164# by a module other than Object::Remote
165# * Selection
166# * The module has defined what the log message format is
167# * The tap has defined the scope of messages that will be
168# available for selection, ie: all log messages everywhere,
169# all logs generated on Object::Remote nodes, etc
170# * Selection defines what log messages are going to be delivered
171# to a logger object instance
172# * Selectors act as a gate between a tap and the logger object
173# * Selectors are closures that perform introspection on the log
174# message; if the selector returns true the logger will be invoked
175# to log this message
176# * The logger still has a log level assigned to it and still will have
177# the is_$level method invoked to only log at that specific level
178# * Destinations
179# * A log destination is an instance of a logger object and the associated
180# selectors.
181# * Consuming logging data from this system is a matter of
182# * Constructing an instance of a logging destination object which has
183# the following attributes:
184# * logger - the logger object, like warnlogger or log4perl instance
185# * selectors - a list of closures; the first one that returns true
186# causes the logger to be checked for this log_level and
187# invoked if neccassary
188# * Register selectors with the destination by invoking a method and specifying
189# sub refs as an argument
190#
191# Technical considerations
192# * Log contextual likes to have the logger invoked directly inside the exported log
193# specific methods because it removes a need to muck with logger caller depths to
194# report back the proper caller information for the logger.
195# * Because of this the best strategy identified is to return a list of loggers
196# to those exported methods which then invoke the loggers inside the method
197# * This means that log message forwarding is a process of querying each parent
198# router for a list of logger objects that should be invoked. Each router along
199# the hierarchy adds to this list and the log_* method will invoke all loggers
200# directly.
201# * The routing hierarchy has cycles where parent routers hold a reference to the child
202# and the child holds a reference to the parent. The cycles are not a problem if weak
203# references are used however proxy objects don't seem to currently work with weak
204# references.
205# * Once a logger hits a proxy object the caller information is totally blown; this
206# crossing isn't transparent yet
207#
208#
209#
210
211
212
213