File Coverage

lib/Log/Shiras/Switchboard.pm
Criterion Covered Total %
statement 312 325 96.0
branch 76 106 71.7
condition 13 28 46.4
subroutine 51 51 100.0
pod 9 9 100.0
total 461 519 88.8


line stmt bran cond sub pod time code
1             package Log::Shiras::Switchboard;
2             our $AUTHORITY = 'cpan:JANDREW';
3 5     5   1005153 use version; our $VERSION = version->declare("v0.48.0");
  5         1189  
  5         33  
4 5     5   400 use strict;
  5         7  
  5         85  
5 5     5   16 use warnings;
  5         5  
  5         117  
6 5     5   143 use 5.010;
  5         14  
7 5     5   18 use utf8;
  5         7  
  5         32  
8 5     5   106 use lib '../../';
  5         6  
  5         29  
9             #~ use Log::Shiras::Unhide qw( :InternalSwitchboarD );
10             ###InternalSwitchboarD warn "You uncovered internal logging statements for Log::Shiras::Switchboard-$VERSION" if !$ENV{hide_warn};
11 5     5   2016 use MooseX::Singleton;
  5         283906  
  5         17  
12 5     5   106532 use MooseX::StrictConstructor;
  5         25132  
  5         25  
13 5     5   29449 use MooseX::HasDefaults::RO;
  5         23282  
  5         17  
14 5     5   33680 use DateTime;
  5         1089598  
  5         242  
15 5     5   36 use Carp qw( cluck confess longmess );
  5         7  
  5         394  
16             $Carp::CarpInternal{'Log::Shiras::Switchboard'}++;
17 5         50 use MooseX::Types::Moose qw(
18             HashRef ArrayRef Bool RegexpRef Str
19             Int Maybe Undef
20 5     5   1527 );
  5         115274  
21 5     5   20842 use Clone 'clone';
  5         7232  
  5         267  
22 5     5   25 use Data::Dumper;
  5         8  
  5         198  
23             use lib
24 5         36 'lib',
25             '../lib',
26 5     5   20 ;
  5         5  
27 5     5   1920 use MooseX::ShortCut::BuildInstance v1.44 qw( build_instance should_re_use_classes );
  5         1156764  
  5         71  
28             should_re_use_classes( 1 );
29 5     5   4989 use Data::Walk::Extracted v0.28;
  5         1884029  
  5         214  
30 5     5   2525 use Data::Walk::Prune v0.028;
  5         113237  
  5         191  
31 5     5   2299 use Data::Walk::Graft v0.028;
  5         62265  
  5         162  
32 5     5   2139 use Data::Walk::Print v0.028;
  5         46965  
  5         169  
33 5     5   1921 use Data::Walk::Clone v0.024;
  5         39530  
  5         164  
34 5         35 use Log::Shiras::Types qw(
35             ElevenArray ElevenInt ReportObject YamlFile
36             JsonFile FileHash ArgsHash
37 5     5   2051 );#
  5         12  
38              
39             #########1 Package Variables 3#########4#########5#########6#########7#########8#########9
40              
41             my @default_levels = (
42             'trace', 'debug', 'info', 'warn', 'error', 'fatal',
43             undef, undef, undef, undef, undef, 'eleven',# This one goes to eleven :^|
44             );
45             my $time_zone = DateTime::TimeZone->new( name => 'local' );
46 5     5   19030 use constant TALK_DEBUG => 0; # Author testing only
  5         7  
  5         290  
47 5     5   17 use constant IMPORT_DEBUG => 0; # Author testing only
  5         9  
  5         175  
48 5     5   16 use constant GET_OPERATOR_DEBUG => 0; # Author testing only
  5         7  
  5         1859  
49              
50             #########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
51              
52             has name_space_bounds =>(
53             isa => HashRef[HashRef],
54             reader => 'get_name_space',
55             clearer => '_clear_all_name_space',
56             writer => '_set_whole_name_space',
57             default => sub{ {} },
58             trigger => \&_clear_can_communicate_cash,
59             );
60              
61             has reports =>(
62             traits => ['Hash'],
63             isa => HashRef[ArrayRef],
64             reader => 'get_reports',
65             writer => '_set_all_reports',
66             handles =>{
67             has_no_reports => 'is_empty',
68             _set_report => 'set',
69             get_report => 'get',
70             remove_reports => 'delete',
71             },
72             default => sub{ {} },
73             );
74              
75             has logging_levels =>(
76             traits => ['Hash'],
77             isa => HashRef[ElevenArray],
78             handles =>{
79             has_log_levels => 'exists',
80             add_log_levels => 'set',
81             _get_log_levels => 'get',
82             remove_log_levels => 'delete',
83             },
84             writer => 'set_all_log_levels',
85             reader => 'get_all_log_levels',
86             default => sub{ {} },
87             );
88              
89             has all_buffering =>(
90             isa => HashRef[ArrayRef],
91             traits => ['Hash'],
92             writer => 'set_all_buffering',
93             reader => '_get_all_buffering',
94             handles =>{
95             has_buffer => 'exists',
96             stop_buffering => 'delete',
97             _set_buffer => 'set',
98             _get_buffer => 'get',
99             _get_buffer_list => 'keys',
100             },
101             default => sub{ {} },
102             );
103              
104             #########1 Public Methods 3#########4#########5#########6#########7#########8#########9
105              
106             sub import {
107 15     15   63 my( $class, @args ) = @_;
108 15         94 my $instance = $class->instance;#Returns a pre-existing instance if it exists
109 15 100       407 return 1 if $instance->_has_import_recursion_block; # Only accept the first build!
110 5         208 $instance->_set_import_recursion_block( 1 );
111 5 50 50     85 warn "Received args:" . join( '~|~', @args ) if @args and IMPORT_DEBUG;
112              
113             # Handle versions (and other nonsense)
114 5 50 33     21 if( $args[0] and $args[0] =~ /^v?\d+\.?\d*/ ){# Version check since import highjacks the built in
115 0         0 warn "Running version check on version: $args[0]" if IMPORT_DEBUG;
116 0         0 my $result = $VERSION <=> version->parse( $args[0]);
117 0         0 warn "Tested against version -$VERSION- gives result: $result" if IMPORT_DEBUG;
118 0 0       0 if( $result < 0 ){
119 0         0 confess "Version -$args[0]- requested for Log::Shiras::Switchboard " .
120             "- the installed version is: $VERSION";
121             }
122 0         0 shift @args;
123             }
124 5 50       14 if( @args ){
125 0         0 confess "Unknown flags passed to Log::Shiras::Switchboard: " . join( ' ', @args );
126             }
127              
128             # Still not sure why this is needed but maybe because of the singlton?
129 5     5   25 no warnings 'once';
  5         6  
  5         295  
130 5 100       15 if($Log::Shiras::Unhide::strip_match) {
131 1     1   54 eval 'use Log::Shiras::Unhide';
  22         72  
  1         2  
  1         9  
132             }
133 5     5   18 use warnings 'once';
  5         5  
  5         3983  
134 5         5022 warn "Finished the switchboard import" if IMPORT_DEBUG;
135             }
136              
137             #Special MooseX::Singleton instantiation that pulls multiple instances into the same master case
138             # This method won't report until the caller name_space and report destination are set up
139             # use the constant GET_OPERATOR_DEBUG to see unreported messages
140             sub get_operator{
141 13     13 1 3206 my( $maybe_class, @args ) = @_;
142 13 50       43 if( $maybe_class ne __PACKAGE__ ){
143 0         0 unshift @args, $maybe_class;
144 0         0 $maybe_class = __PACKAGE__;
145             }
146 13         118 my $instance = $maybe_class->instance;#Returns a pre-existing instance if it exists
147 13 0 33     88 my $arguments =
    50 0        
    100          
148             ( !@args) ? undef :
149             ( ( @args > 1 ) and ( scalar( @args ) % 2 == 0 ) ) ? { @args } :
150             ( is_YamlFile( $args[0] ) or is_JsonFile( $args[0] ) ) ? to_FileHash( $args[0] ) :
151             to_ArgsHash( $args[0] );
152             ###InternalSwitchboarD my $talk_result = 1;
153             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 2,
154             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
155             ###InternalSwitchboarD message =>[ "Initial parsing of arguments yeilds:", $arguments ], } );
156             ###InternalSwitchboarD warn "Initial parsing of arguments yeilds:" . Dumper( $arguments ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
157 13 50 66     42 if( $arguments and exists $arguments->{conf_file} ){
158 2         16 my $file_hash = to_FileHash( $arguments->{conf_file} );
159 2         8 delete $arguments->{conf_file};
160 2         10 $arguments = $instance->graft_data( tree_ref => $file_hash, scion_ref => $arguments );
161             }
162             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 0,
163             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
164             ###InternalSwitchboarD message =>[ "Updated arguments with conf_file key parsed:", $arguments ], } );
165             ###InternalSwitchboarD warn "Updated arguments with conf_file key parsed:" . Dumper( $arguments ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
166 11         13 my $level = 1;
167 11         21 my $message = [ "Starting get operator" ];
168 11 100       31 if( keys %$arguments ){
169 8         23 $level = 2;
170 8         26 push @$message, 'With updates to:' , keys %$arguments;
171             }
172             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => $level,
173             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
174             ###InternalSwitchboarD message =>[ $message, $arguments ], } );
175             ###InternalSwitchboarD warn Dumper( $message, $arguments ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
176 13         16 my @action_list;
177 13         23 for my $key ( keys %$arguments ){
178 14         37 push @action_list, $key;
179 13         22 my $method_1 = "add_$key";
180 13         22 my $method_2 = "set_$key";
181 14 50       56 my $input = is_HashRef( $arguments->{$key} ) ? $arguments->{$key} : {$arguments->{$key}};
182             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 0,
183             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
184             ###InternalSwitchboarD message =>[ "Processed key -$key- to the methods -$method_1- and -$method_2-",
185             ###InternalSwitchboarD "used to implement arguments:", $arguments->{$key} ], } );
186             ###InternalSwitchboarD warn "Processed key -$key- to the methods -$method_1- and -$method_2-" if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
187             ###InternalSwitchboarD warn "used to implement arguments:" . Dumper( $arguments->{$key} ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
188 14 100       1875 if( $instance->can( $method_1 ) ){
189             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 1,
190             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
191             ###InternalSwitchboarD message =>[ "Using method: $method_1" ], } );
192             ###InternalSwitchboarD warn "Using method: $method_1" if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
193 12         27 $instance->$method_1( $input );
194             }else{
195             ###InternalSwitchboarD $instance->master_talk( { report => 'log_file', level => 1,
196             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
197             ###InternalSwitchboarD message =>[ "Using method: $method_2" ], } );
198             ###InternalSwitchboarD warn "Using method: $method_2" if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
199 4         12 $instance->$method_2( $input );
200             }
201             }
202             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 2,
203             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
204             ###InternalSwitchboarD message =>[ "Switchboard finished updating the following arguments: ", @action_list ], } );
205             ###InternalSwitchboarD warn "Switchboard finished updating the following arguments: " . Dumper( @action_list ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
206             ###InternalSwitchboarD $talk_result = $instance->master_talk( { report => 'log_file', level => 0,
207             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::get_operator',
208             ###InternalSwitchboarD message =>[ 'The switchboard instance is:', $instance ], } );
209             ###InternalSwitchboarD warn 'The switchboard instance is:' . Dumper( $instance ) if GET_OPERATOR_DEBUG and ($talk_result == 0 or $talk_result == -3);
210 13         121 return $instance;
211             }
212              
213             # This is the only method that can't self report - use the constant TALK_DEBUG instead
214             # (Any self reporting from here is by definition a trigger for deep recursion fails)
215             sub master_talk{
216 3319     3317 1 6092 my ( $self, $data_ref ) = @_;
217 3319         99193 my $recursion = $self->_has_message_recursion_block;
218             ###InternalSwitchboarD warn "Arrived at master_talk with recursion level -$recursion- from line: " . (caller(0))[2] if TALK_DEBUG;
219 3319 100       41927 if( $recursion == 0 ){
    100          
220             ###InternalSwitchboarD warn '---->Recursion level 0 acceptable!' if TALK_DEBUG;
221             }elsif( $recursion == 1 ){# Allow for one level so internal junk can report
222             ###InternalSwitchboarD warn '------------------->Recursion level 1 acceptable!' if TALK_DEBUG;
223             }else{
224             ###InternalSwitchboarD warn "Allowed recursion level exceeded!" if TALK_DEBUG;
225 3294         5428 return -1; # Special return state for recursion-fail
226             }
227 54         670 $self->_set_message_recursion_block( 1 + $recursion );
228             ###InternalSwitchboarD warn "Arrived at master_talk with the instructions:" . Dumper( $data_ref ) if TALK_DEBUG;
229              
230             # Check the NameSpace
231             ###InternalSwitchboarD warn "Checking if report -$data_ref->{report}- level -$data_ref->{level}- and NameSpace -$data_ref->{name_space}- are allowed to communicate" if TALK_DEBUG;
232 464 100       688 if( $self->_can_communicate(
233             $data_ref->{report}, $data_ref->{level}, $data_ref->{name_space} ) ){
234             ###InternalSwitchboarD warn "The message passed the name_space test" if TALK_DEBUG;
235             }else{
236             ###InternalSwitchboarD if( TALK_DEBUG ){
237             ###InternalSwitchboarD my $message = '<----';
238             ###InternalSwitchboarD $message .= $recursion == 1 ? '---------------' : '' ;
239             ###InternalSwitchboarD $message .= 'Reducing recursion level!';
240             ###InternalSwitchboarD warn $message;
241             ###InternalSwitchboarD warn "The message did NOT pass the name_space test";
242             ###InternalSwitchboarD }
243 2836         1863 $self->_set_message_recursion_block( $recursion );# Early return so cleanup needed
244 2836         2788 return -3;
245             }
246              
247             ### Add some meta_data
248             # Add message time
249 485         13708 $data_ref->{date_time} = DateTime->now( time_zone => $time_zone )->format_cldr( 'yyyy-MM-dd hh:mm:ss' );
250              
251             # Add carp_stack as needed
252 485         16640 $data_ref = $self->_add_carp_stack( $data_ref );
253              
254             # Add source keys
255 483         299 $data_ref = $self->_add_caller( $data_ref );
256             ###InternalSwitchboarD warn "The message metadata load is complete" if TALK_DEBUG;
257              
258             # Check if the message is buffered
259 483         1040 my $y = $self->_buffer_decision( $data_ref );
260             ###InternalSwitchboarD warn "Buffer decision result: $y" if TALK_DEBUG;
261              
262             # Send message to report as needed
263 79 100       119 my $x = ( $y eq 'report' ) ? $self->_really_report( $data_ref ) : -2;
264             ###InternalSwitchboarD warn "Returned from _really_report-ing with: $x" if TALK_DEBUG;
265              
266             ###InternalSwitchboarD if( TALK_DEBUG ){
267             ###InternalSwitchboarD my $message = '<----';
268             ###InternalSwitchboarD $message .= $recursion == 1 ? '---------------' : '' ;
269             ###InternalSwitchboarD $message .= 'Reducing recursion level!';
270             ###InternalSwitchboarD warn $message;
271             ###InternalSwitchboarD }
272 424         730 $self->_set_message_recursion_block( $recursion );
273 424         12230 return $x;
274             }
275              
276             sub add_name_space_bounds{
277 414     8 1 6023 my ( $self, $name_space_ref ) = @_;
278             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
279             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_name_space_bounds',
280             ###InternalSwitchboarD message =>[ 'Arrived at add_name_space_bounds with:', $name_space_ref,
281             ###InternalSwitchboarD '...against current master name_space_bounds:', $self->get_name_space ], } );
282 70         496 my $new_sources = $self->graft_data(
283             tree_ref => $self->get_name_space,
284             scion_ref => $name_space_ref,
285             );
286 70         104931 my $result = $self->_set_whole_name_space( $new_sources );
287             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
288             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_name_space_bounds',
289             ###InternalSwitchboarD message =>[ 'Updated master name_space_bounds:', $new_sources ], } );
290 68         22674 return 1;
291             }
292              
293             sub remove_name_space_bounds{
294 62     1 1 1132 my ( $self, $removal_ref ) = @_;
295             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
296             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::remove_name_space_bounds',
297             ###InternalSwitchboarD message =>[ 'Arrived at remove_name_space_bounds with:', $removal_ref,
298             ###InternalSwitchboarD '...against current master name_space_bounds:', $self->get_name_space ], } );
299 62         131 my $result;
300 61         84 $self->_set_whole_name_space(
301             $result = $self->prune_data( tree_ref => $self->get_name_space, slice_ref => $removal_ref, )
302             );
303             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
304             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::remove_name_space_bounds',
305             ###InternalSwitchboarD message =>[ 'Updated master name_space_bounds:', $result ], } );
306 61         216 return $result;
307             }
308              
309             sub add_reports{
310 68     9 1 3347 my( $self, @args ) = @_;
311 68 100       85 my %report_hash = ( scalar( @args ) == 1 ) ? %{$args[0]} : @args ;
  66         1799  
312             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
313             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
314             ###InternalSwitchboarD message =>[ 'Arrived at add_reports with:', {%report_hash},
315             ###InternalSwitchboarD 'Current master reports:', $self->get_reports ], } );
316 68         802 for my $name ( keys %report_hash ){
317 12         75 my $report_list = [];
318             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
319             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
320             ###InternalSwitchboarD message =>[ "Adding output to the report named: $name" ], } );
321 13         30 for my $report ( @{$report_hash{$name}} ){
  13         35  
322             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
323             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
324             ###InternalSwitchboarD message =>[ 'processing:', $report ], } );
325 8 100       27 if( is_ReportObject( $report ) ){
326             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
327             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
328             ###InternalSwitchboarD message =>[ 'no object creation needed for this output' ], } );
329             }else{
330 4         268 $report = to_ReportObject( $report );
331             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
332             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
333             ###InternalSwitchboarD message =>[ 'after building the instance:', $report ], } );
334             }
335 7         48 push @{$report_list} , $report;
  7         21  
336             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
337             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
338             ###InternalSwitchboarD message =>[ 'updated report list:', $report_list ], } );
339             }
340 12         294 $self->_set_report( $name => $report_list );
341             }
342              
343             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
344             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
345             ###InternalSwitchboarD message =>[ 'Final report space:', $self->get_reports ], } );
346 8         114 return 1;
347             }
348              
349             sub get_log_levels{
350 2     2 1 519 my ( $self, $report ) = @_;
351 3   50     8 $report //= 'log_file';
352 3         6 my $output;
353             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
354             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
355             ###InternalSwitchboarD message =>[ "Reached get_log_levels for report: $report" ], } );
356 3         8 my $x = 0;
357 4 100       125 if( $self->has_log_levels( $report ) ){
358             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
359             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
360             ###InternalSwitchboarD message =>[ "Custom log level for -$report- found" ], } );
361 2         89 $output = $self->_get_log_levels( $report );
362             }else{
363             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
364             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
365             ###InternalSwitchboarD message =>[ "No custome log levels in force for -$report- sending the defaults" ], } );
366 2         31 $output = [ @default_levels ];
367             }
368 5     5   23 no warnings 'uninitialized';#OK to have undef at some levels
  5         7  
  5         177  
369             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
370             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::add_reports',
371             ###InternalSwitchboarD message =>[ "Returning the log levels for -$report-" . join( ', ', @$output ) ], } );
372 5     5   54 use warnings 'uninitialized';
  5         8  
  5         8022  
373 2         23 return $output;
374             }
375              
376             sub send_buffer_to_output{
377 6     6 1 20 my ( $self, $report ) = @_;
378 6   50     11 $report //= 'log_file';
379             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
380             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::send_buffer_to_output',
381             ###InternalSwitchboarD message =>[ "Reached send_buffer_to_output for report: $report" ], } );
382 6         6 my $x = 0;
383 6 50       156 if( $self->has_buffer( $report ) ){
384             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
385             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::send_buffer_to_output',
386             ###InternalSwitchboarD message =>[ "Flushing the buffer ..." ], } );
387 6         93 for my $message_ref ( @{$self->_get_buffer( $report )} ) {
  6         138  
388             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
389             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::send_buffer_to_output',
390             ###InternalSwitchboarD message =>[ "Sending:", $message_ref->{message} ], } );
391 3         42 $x += $self->_really_report( $message_ref );
392             }
393 6         179 $self->_set_buffer( $report => [] );
394             }else{
395             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 3,
396             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::send_buffer_to_output',
397             ###InternalSwitchboarD message =>[ "Attempting to send buffer to output when no buffering is in force!" ], } );
398             }
399             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
400             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::send_buffer_to_output',
401             ###InternalSwitchboarD message =>[ "Returning from attempt to flush buffer with: $x" ], } );
402 6         86 return $x;
403             }
404              
405             sub clear_buffer{
406 1     1 1 9 my ( $self, $report ) = @_;
407 1   50     4 $report //= 'log_file';
408             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
409             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::clear_buffer',
410             ###InternalSwitchboarD message =>[ "Reached clear_buffer for report: $report" ], } );
411 1         1 my $x = 0;
412 1 50       29 if( $self->has_buffer( $report ) ){
413             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
414             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::clear_buffer',
415             ###InternalSwitchboarD message =>[ "clearing the buffer ..." ], } );
416 1         44 $self->_set_buffer( $report => [] );
417 1         13 $x = 1;
418             }else{
419             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
420             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::clear_buffer',
421             ###InternalSwitchboarD message =>[ "Attempting to clear a buffer to output when no buffering is in force!" ], } );
422             }
423             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
424             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::clear_buffer',
425             ###InternalSwitchboarD message =>[ "Returning from attempt to clear the buffer with: $x" ], } );
426 1         4 return $x;
427             }
428              
429             sub start_buffering{
430 2     2 1 9 my ( $self, $report ) = @_;
431 2   50     5 $report //= 'log_file';
432             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
433             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::start_buffering',
434             ###InternalSwitchboarD message =>[ "Reached set_buffering for report: $report" ], } );
435 2         2 my $x = 0;
436 2 50       59 if( $self->has_buffer( $report ) ){
437             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 3,
438             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::start_buffering',
439             ###InternalSwitchboarD message =>[ "Attempting to turn on a buffer to when it already exists!" ], } );
440             }else{
441 2         86 $self->_set_buffer( $report => [] );
442 2         27 $x = 1;
443             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
444             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::start_buffering',
445             ###InternalSwitchboarD message =>[ "Buffering turned on ..." ], } );
446             }
447             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
448             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::start_buffering',
449             ###InternalSwitchboarD message =>[ "Returning from attempt to set the buffer with: $x" ], } );
450 2         8 return $x;
451             }
452              
453             #########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
454              
455             has _import_recursion_block =>(
456             isa => Bool,
457             reader => '_has_import_recursion_block',
458             writer => '_set_import_recursion_block',
459             init_arg => undef,
460             default => 0,
461             );
462              
463             has _message_recursion_block =>(
464             isa => Int,
465             reader => '_has_message_recursion_block',
466             writer => '_set_message_recursion_block',
467             init_arg => undef,
468             default => 0,
469             );
470              
471             has _data_walker =>(
472             isa => 'Walker',
473             handles =>[ qw( graft_data prune_data print_data ) ],
474             writer => '_set_data_walker',
475             predicate => '_has_data_walker',
476             init_arg => undef,
477             builder => '_build_data_walker',
478             #~ lazy => 1,
479             );
480              
481             has _can_communicate_cash =>(
482             isa => HashRef,
483             traits => ['Hash'],
484             clearer => '_clear_can_communicate_cash',
485             handles =>{
486             _has_can_com_cash => 'exists',
487             _set_can_com_cash => 'set',
488             _get_can_com_cash => 'get',
489             },
490             init_arg => undef,
491             default => sub{ {} },
492             );
493              
494             has _test_buffer =>(
495             isa => HashRef[ArrayRef],
496             clearer => '_clear_all_test_buffers',
497             traits => ['Hash'],
498             handles =>{
499             _has_test_buffer => 'exists',
500             _set_test_buffer => 'set',
501             _get_test_buffer => 'get',
502             },
503             default => sub{ {} },
504             );
505              
506             #########1 Private Methods 3#########4#########5#########6#########7#########8#########9
507              
508             sub _can_communicate{
509 489     489   466 my ( $self, $report, $level, $name_string ) = @_;
510             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
511             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
512             ###InternalSwitchboarD message =>[ "Arrived at _can_communicate to see if report: $report",
513             ###InternalSwitchboarD "- will accept a call at the urgency of: $level",
514             ###InternalSwitchboarD "- from the name_space: $name_string" ], } );
515 489         1927 my $cash_string = $name_string . $report . $level;
516 489         1037 my $pass = 0;
517 489         421 my $x = "Report -$report- is NOT UNBLOCKed for the name-space: $name_string";
518 489 100       1261 if( $self->_has_can_com_cash( $cash_string ) ){
519 473         14810 ( $pass, $x ) = @{$self->_get_can_com_cash( $cash_string )};
  430         5703  
520             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
521             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
522             ###InternalSwitchboarD message =>[ "Found the permissions cached: $pass" ], } );
523             }else{
524 437         13451 my $source_space = $self->get_name_space;
525 437 100       6956 return $pass if !keys %$source_space;
526 59         1776 my @telephone_name_space = ( split /::/, $name_string );
527             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
528             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
529             ###InternalSwitchboarD message =>[ 'Consolidating permissions for the name space:', @telephone_name_space ,
530             ###InternalSwitchboarD 'against the source space:', $source_space ], } );
531 59         616 my $level_ref = {};
532 47         183 $level_ref = $self->_get_block_unblock_levels( $level_ref, $source_space );
533             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
534             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
535             ###InternalSwitchboarD message =>[ '_get_block_unblock_levels returned returned the level ref:', $level_ref ], } );
536 47         197 SPACETEST: for my $next_level ( @telephone_name_space ){
537             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
538             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
539             ###InternalSwitchboarD message =>[ "Checking for additional adjustments at: $next_level" ], } );
540 60 100       121 if( exists $source_space->{$next_level} ){
541 50         365 $source_space = clone( $source_space->{$next_level} );
542             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
543             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
544             ###InternalSwitchboarD message =>[ "The next level -$next_level- exists", $source_space ], } );
545 50         175 $level_ref = $self->_get_block_unblock_levels( $level_ref, $source_space );
546             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
547             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
548             ###InternalSwitchboarD message =>[ '_get_block_unblock_levels returned the level ref:', $level_ref ], } );
549             }else{
550             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
551             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
552             ###InternalSwitchboarD message =>[ "Didn't find the next level -$next_level-" ], } );
553 41         101 last SPACETEST;
554             }
555             }
556             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
557             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
558             ###InternalSwitchboarD message =>[ 'Final level collection is:', $level_ref,
559             ###InternalSwitchboarD "Checking for the report name in the consolidated level ref"], } );
560 148         489 REPORTTEST: for my $key ( keys %$level_ref ){
561             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
562             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
563             ###InternalSwitchboarD message =>[ "Testing: $key" ], } );
564 160 100       431 if( $key =~ /$report/i ){
565             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
566             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
567             ###InternalSwitchboarD message =>[ "Matched key to the target report: $report" ], } );
568 131         2651 my $allowed = $self->_convert_level_name_to_number( $level_ref->{$key}, $report );
569             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
570             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
571             ###InternalSwitchboarD message =>[ "The allowed level for -$report- is: $allowed" ], } );
572 131         652 my $attempted = $self->_convert_level_name_to_number( $level, $report );
573             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
574             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
575             ###InternalSwitchboarD message =>[ "The attempted level for -$level- is: $attempted" ], } );
576 131 100       308 if( $attempted >= $allowed ){
577 126         368 $x = "The message clears for report -$report- at level: $level";
578 26         82 $pass = 1 ;
579             }else{
580 21         64 $x = "The destination -$report- is UNBLOCKed but not to the -$level- level at the name space: $name_string";
581             }
582 46         146 last REPORTTEST;
583             }
584             }
585 47         569 $self->_set_can_com_cash( $cash_string => [ $pass, $x ] );
586             }
587             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
588             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate',
589             ###InternalSwitchboarD message =>[ $x ], } );
590 56         577 return $pass;
591             }
592              
593             sub _add_caller{
594 110     79   285 my ( $self, $data_ref ) = @_;
595 96         153 my $level = 2;
596 96 100       214 if( !exists $data_ref->{source_sub} ){
597 82         214 $data_ref->{source_sub} = 'Log::Shiras::Switchboard::master_talk';
598 82         126 $level = 1;
599             }
600             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
601             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_caller',
602             ###InternalSwitchboarD message =>[ "Arrived at _get_caller for start level (up): $level",
603             ###InternalSwitchboarD "and source sub: $data_ref->{source_sub}", ], } );
604 96         378 my( $caller_ref, $complete, $last_ref,);
605 96         189 while( !$complete ){
606 92         279 @$caller_ref{qw( package filename line subroutine )} = (caller($level))[0..3];
607             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
608             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_caller',
609             ###InternalSwitchboarD message =>[ "Retrieved caller data from up level: $level", $caller_ref ], } );
610 92 100       693 if( $caller_ref->{subroutine} eq $data_ref->{source_sub} ){
611             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
612             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_caller',
613             ###InternalSwitchboarD message =>[ "Matched: $data_ref->{source_sub}" ], } );
614 89         325 $complete = 1;
615             }
616 102         252 $level++;
617 116 50       1367 last if $level > 6;# safety valve
618             }
619             #~ my $caller_ref = $data_ref->{source_sub} eq 'IO::Callback::print' ?
620             #~ $self->_alt_caller( $data_ref, $level ) :
621             #~ $self->_main_caller( $data_ref, $level );
622             #~ ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
623             #~ ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_caller',
624             #~ ###InternalSwitchboarD message =>[ "Returned from caller search with:", $caller_ref ], } );
625 531         2284 delete $caller_ref->{subroutine};
626 531         1150 $caller_ref->{filename} =~ s/\\/\//g;
627             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => '2',
628             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_caller',
629             ###InternalSwitchboarD message =>[ "Caller ref - ending at level: $level", $caller_ref], } );
630 79         278 return { %$caller_ref, %$data_ref };
631             }
632              
633             sub _add_carp_stack{
634 139     79   190 my ( $self, $data_ref ) = @_;
635             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
636             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_carp_stack',
637             ###InternalSwitchboarD message =>[ "Arrived at _add_carp_stack for action: " . exists $data_ref->{carp_stack} ], } );
638              
639 139 100       467 if( $data_ref->{carp_stack} ){
640 120         385 my @carp_list = split( /\n\s*/, longmess() );
641 61         566 push @{$data_ref->{message}}, @carp_list;
  1         270  
642             }
643 20         23 delete $data_ref->{carp_stack};
644             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => '0',
645             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_add_carp_stack',
646             ###InternalSwitchboarD message =>[ "Longmess test complete with message: ", $data_ref->{message} ], } );
647 79         93 return $data_ref;
648             }
649              
650             sub _buffer_decision{
651 139     79   317 my ( $self, $report_ref ) = @_;
652             #~ warn Dumper( $report_ref );
653             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
654             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_buffer_decision',
655             ###InternalSwitchboarD message =>[ "Arrived at _buffer_decision for report: $report_ref->{report}",
656             ###InternalSwitchboarD "..with buffer setting: " . $self->has_buffer( $report_ref->{report} ), ], } );
657              
658             # Check if the regular buffer is active (and load buffer or report)
659 139         2131 my $x = 'report';
660 79 100       662 if( $self->has_buffer( $report_ref->{report} ) ){
661             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
662             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_buffer_decision',
663             ###InternalSwitchboarD message =>[ "The buffer is active - sending the message to the buffer (not the report)." ], } );
664 64         1856 push @{$self->_get_buffer( $report_ref->{report} )}, $report_ref;# Load the buffer
  4         97  
665 4         53 $x = 'buffer';
666             }
667             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
668             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_buffer_decision',
669             ###InternalSwitchboarD message =>[ "Current action for report -$report_ref->{report}- is: $x" ], } );
670 19         319 return $x;
671             }
672              
673             sub _load_test_buffer{
674 78     78   74 my ( $self, $report_ref ) = @_;
675             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
676             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_load_test_buffer',
677             ###InternalSwitchboarD message =>[ "Arrived at _test_buffer for report: $report_ref->{report}",
678             ###InternalSwitchboarD "..with test buffer setting: " . $self->_has_test_buffer( $report_ref->{report} ), ], } );
679              
680             # Start a test buffer for the report if it doesn't exist
681 138 100       3387 if( !$self->_has_test_buffer( $report_ref->{report} ) ){
682             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
683             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_load_test_buffer',
684             ###InternalSwitchboarD message =>[ "This is a new TEST buffer request for report " .
685             ###InternalSwitchboarD "-$report_ref->{report}- turning the buffer on!" ], } );
686 126         2257 $self->_set_test_buffer( $report_ref->{report} =>[] );
687             }
688             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
689             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_load_test_buffer',
690             ###InternalSwitchboarD message =>[ "Loading the line to the test buffer" ], } );
691 21         348 unshift @{$self->_get_test_buffer( $report_ref->{report} )}, $report_ref;
  21         549  
692              
693             # Reduce the buffer size as needed
694 78         1221 while( $#{$self->_get_test_buffer( $report_ref->{report} )} > $Log::Shiras::Test2::last_buffer_position ){
  78         1211  
695             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
696             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_load_test_buffer',
697             ###InternalSwitchboarD message =>[ "The TEST buffer has outgrown it's allowed size. Reducing it from: " .
698             ###InternalSwitchboarD $#{$self->_get_test_buffer( $report_ref->{report} )} ], } );
699 60         82 pop @{$self->_get_test_buffer( $report_ref->{report} )};
  60         1798  
700             }
701              
702 53         738 return 1;
703             }
704              
705             sub _really_report{
706 113     78   1140 my ( $self, $report_ref ) = @_;
707             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
708             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_really_report',
709             ###InternalSwitchboarD message =>[ "Arrived at _really_report to report -$report_ref->{report}- with message:", $report_ref->{message} ], } );
710              
711             # Load the test buffer as called
712 113 50       393 if( $Log::Shiras::Test2::last_buffer_position ){
713             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
714             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_really_report',
715             ###InternalSwitchboarD message =>[ "Sending the message to the test buffer too!" ], } );
716 113         1261 $self->_load_test_buffer( $report_ref );
717             }
718              
719             # Send the data to the reports
720 173         3516 my $x = 0;
721 138         1386 my $report_array_ref = $self->get_report( $report_ref->{report} );
722 78 100       299 if( $report_array_ref ){
723 73         1789 for my $report ( @{$report_array_ref} ){
  73         821  
724 45 50       72 next if !$report;
725             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
726             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_really_report',
727             ###InternalSwitchboarD message =>[ 'sending message to: ' . $report_ref->{report}, ], } );
728 45         88 $report->add_line( $report_ref );
729 44         97 $x++;
730             }
731             ###InternalSwitchboarD warn 'Checking if this is a fatal message' if TALK_DEBUG;
732 55         209 $self->_is_fatal( $report_ref );
733             ###InternalSwitchboarD warn 'The message was not fatal!' if TALK_DEBUG;
734             }else{
735             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
736             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_really_report',
737             ###InternalSwitchboarD message =>[ "The report name -$report_ref->{report}- does not have any destination instances to use!" ], } );
738             }
739             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
740             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_really_report',
741             ###InternalSwitchboarD message =>[ "Message was reported -$x- times" ], } );
742 59         192 return $x;
743             }
744              
745             sub _is_fatal{
746 98     56   3517 my ( $self, $data_ref ) = @_;#, $recursion
747             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
748             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_is_fatal',
749             ###InternalSwitchboarD message =>[ "Arrived at _is_fatal to see if urgency -$data_ref->{level}- equals fatal", ], } );
750 99 100       313 if( $data_ref->{level} =~ /fatal/i ){
751             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 3,
752             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_is_fatal',
753             ###InternalSwitchboarD message =>[ "Checking which message to send based on the message content:", $data_ref->{message} ], } );
754             #~ $self->_set_message_recursion_block( $recursion );# Early return so cleanup needed (for the case of an eval'd fatal)
755 87         270 my $fatality = '';
756 44         47 my $empty = "Fatal call sent to the switchboard";
757 19 100       93 if(!$data_ref->{message} ){
758 61         258 $fatality = $empty;
759             }else{
760 60         145 my $i = 0;
761 0         0 for my $element ( @{$data_ref->{message}} ){
  1         2  
762 1 50 33     1 if( !$element or length( $element ) == 0 ){
    0          
763             }elsif( $i ){
764 1 0       3 $fatality .= "\n" . ( ref $element ? Dumper( $element ) : $element );
765 1         6 $i++;
766             }else{
767 0 0       0 $fatality = "\n" . ( ref $element ? Dumper( $element ) : $element );
768 0         0 $i++;
769             }
770             }
771 0 50       0 $fatality .= length( $fatality ) > 0 ? "<- sent at a 'fatal' level" : $empty ;
772             }
773 1         131 confess( $fatality );
774             }
775 13         20 return 1;
776             }
777              
778             sub _get_block_unblock_levels{
779 183     182   346 my ( $self, $level_ref, $space_ref ) = @_;
780             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
781             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
782             ###InternalSwitchboarD message =>[ 'Arrived at _get_block_unblock_levels for:', $space_ref,
783             ###InternalSwitchboarD 'Received the level ref:', $level_ref ], } );
784 224 100       593 if( exists $space_ref->{UNBLOCK} ){
785             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
786             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
787             ###InternalSwitchboarD message =>[ 'Found an UNBLOCK at this level:', $space_ref->{UNBLOCK} ], } );
788 177         388 for my $report ( keys %{$space_ref->{UNBLOCK}} ){
  48         162  
789 64         118 $level_ref->{$report} = $space_ref->{UNBLOCK}->{$report};
790             }
791             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
792             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
793             ###InternalSwitchboarD message =>[ 'level ref with UNBLOCK changes:', $level_ref ], } );
794             }
795 53 50       118 if( exists $space_ref->{BLOCK} ){
796             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
797             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
798             ###InternalSwitchboarD message =>[ 'Found an BLOCK at this level:', $space_ref->{BLOCK} ], } );
799 38         69 for my $report ( keys %{$space_ref->{BLOCK}} ){
  18         69  
800 147         256 delete $level_ref->{$report};
801             }
802             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
803             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
804             ###InternalSwitchboarD message =>[ 'level ref with BLOCK changes:', $level_ref ], } );
805             }
806             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
807             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_can_communicate::_get_block_unblock_levels',
808             ###InternalSwitchboarD message =>[ 'Returning the level ref:', $level_ref ], } );
809 35         43 return $level_ref;
810             }
811              
812             sub _convert_level_name_to_number{
813 64     64   85 my ( $self, $level, $report ) = @_;
814             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
815             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
816             ###InternalSwitchboarD message =>[ "Arrived at _convert_level_name_to_number with level -$level" ], } );
817 64         163 my $x = 0;
818 64 100       116 if( is_ElevenInt( $level ) ){
819             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 0,
820             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
821             ###InternalSwitchboarD message =>[ "-$level- is already an integer in the correct range." ], } );
822 45         159 $x = $level;
823             }else{
824 180 50       3537 my $level_ref = ( !$report ) ? [ @default_levels ] :
    50          
825             ( $self->has_log_levels( $report ) ) ? $self->get_log_levels( $report ) :
826             [ @default_levels ] ;
827 180 50       714 if( !$level_ref ){
828             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 4,
829             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
830             ###InternalSwitchboarD message =>[ "After trying several options no level list could be isolated for report -" .
831             ###InternalSwitchboarD $report . "-. Level -" . ( $level // 'UNDEFINED' ) .
832             ###InternalSwitchboarD "- will be set to 0 (These go to eleven)" ], } );
833             }else{
834             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
835             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
836             ###InternalSwitchboarD message =>[ 'Checking for a match for -$level- in the level ref:', $level_ref ], } );
837 39         3770 my $found = 0;
838 39         470 for my $word ( @$level_ref ){
839 92 100 100     623 if( $word and $level =~ /^$word$/i ){
840             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 2,
841             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
842             ###InternalSwitchboarD message =>[ "Level word -$word- matches passed level: $level" ], } );
843 39         138 $found = 1;
844 39         93 last;
845             }
846 93         122 $x++;
847             }
848 103 50       766 if( !$found ){
849             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 3,
850             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
851             ###InternalSwitchboarD message =>[ "No match was found for the level -$level-" .
852             ###InternalSwitchboarD " assigned to the report -$report-", ], } );
853 20         120 $x = 0;
854             }
855             }
856             }
857             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
858             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::master_talk::_convert_level_name_to_number',
859             ###InternalSwitchboarD message =>[ "Returning -$level- as the integer: $x" ], } );
860 50         86 return $x;
861             }
862              
863             before stop_buffering => sub{
864             my ( $self, @buffer_list ) = @_;
865             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
866             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::stop_buffering',
867             ###InternalSwitchboarD message =>[ "Action 'before' clearing the buffers:", @buffer_list ], } );
868             for my $report ( @buffer_list ){
869             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
870             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::stop_buffering',
871             ###InternalSwitchboarD message =>[ "Checking the buffers for report: $report" ], } );
872             if( $self->has_buffer( $report) ){
873             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
874             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::stop_buffering',
875             ###InternalSwitchboarD message =>[ "Flushing the buffer for: $report" ], } );
876             $self->send_buffer_to_output( $report );
877             }
878             }
879             return @buffer_list;
880             };
881              
882             before set_all_buffering => sub{
883             my ( $self, $buffer_ref ) = @_;
884             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
885             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::set_all_buffering',
886             ###InternalSwitchboarD message =>[ "Setting up new buffers:", $buffer_ref, $self->_get_buffer_list ], } );
887             for my $report ( $self->_get_buffer_list ){
888             ###InternalSwitchboarD $self->master_talk( { report => 'log_file', level => 1,
889             ###InternalSwitchboarD name_space => 'Log::Shiras::Switchboard::set_all_buffering',
890             ###InternalSwitchboarD message =>[ "Flushing the buffer for: $report" ], } );
891             $self->send_buffer_to_output( $report );
892             }
893             return $buffer_ref;
894             };
895              
896             after '_set_whole_name_space' => sub{ __PACKAGE__->_clear_can_communicate_cash };
897              
898             sub _build_data_walker{
899 25     5   49 my ( $self, ) = @_;
900             ###InternalSwitchboarD warn "Arrived at _build_data_walker" if IMPORT_DEBUG;
901 69         118 return build_instance(
902             package => 'Walker',
903             superclasses => ['Data::Walk::Extracted',],
904             roles =>[
905             'Data::Walk::Graft',
906             'Data::Walk::Clone',
907             'Data::Walk::Prune',
908             'Data::Walk::Print',
909             ],
910             skipped_nodes =>{
911             OBJECT => 1,
912             CODEREF => 1,
913             },
914             to_string => 1,
915             );
916             }
917              
918             #~ sub DEMOLISH{
919             #~ my ( $self ) = @_;
920             #~ }
921              
922             #########1 Phinish 3#########4#########5#########6#########7#########8#########9
923              
924 5     5   26 no MooseX::Singleton;
  5         7  
  5         50  
925             __PACKAGE__->meta->make_immutable;
926              
927             1;
928             # The preceding line will help the module return a true value
929              
930             #########1 main pod docs 3#########4#########5#########6#########7#########8#########9
931              
932             __END__
933              
934             =head1 NAME
935              
936             Log::Shiras::Switchboard - Log::Shiras message screening and delivery
937              
938             =head1 DESCRIPTION
939              
940             L<Shiras|http://en.wikipedia.org/wiki/Moose#Subspecies> - A small subspecies of
941             Moose found in the western United States (of America).
942              
943             This is the class for message traffic control in the 'Log::Shiras' package. For a
944             general overview of the whole package see L<the top level documentation
945             |Log::Shiras>. Traffic is managed using name spaces. For the purposes of logging this
946             package uses three types of name space with an additional wrapper. The first name space
947             is the source code name space. This name space is managed by putting labeled comment
948             tags in the code and then exposing them with a source code filter. This is mostly used
949             when you want to have debug code available that does not impact your regular runs of the
950             code. This space is managed by L<Log::Shiras::Unhide>. The source code name space is a
951             flat list. The next name space is the caller name space. The caller name space is
952             assigned in the code with targeted embedded statements to the L<master_talk
953             |/master_talk( $args_ref )> method. Boilerplate for managing these calls can be found
954             in L<Log::Shiras::Telephone>. If you wish to inject name_space modifications from the
955             calling script you can use the role L<Log::Shiras::LogSpace>. The caller namespace can
956             be heirarchical and represented by a Hash of hashrefs. The final name space is the
957             destination or L<report|/reports> namespace. This namespace is flat but each position can contain
958             more than one actual report. Any message to a specific report name is sent to all reports
959             assigned to that name. Managing the traffic between the caller name space and the report
960             name space is done by setting allowed L<urgency|/logging_levels> levels in the
961             L<name space bounds|/name_space_bounds>., urgency levels, and report names.
962              
963             In order to stich all this together at run time this is a singleton class and so
964             'new' is the wrong way to get a new instance of this class. The right way is to use the
965             method L<get_operator|/get_operator( %args )>. The upside of using a singleton is you
966             can write a caller (message source) with an intended urgency and destination name and not
967             build the actual destination till run time.
968              
969             =head2 Initialization
970              
971             This class does not use ->new. Use 'get_operator' instead.
972              
973             =head3 get_operator( %args )
974              
975             =over
976              
977             B<Definition:> This method replaces the call to -E<gt>new or other instantiation
978             methods. The Log::Shiras::Switchboard class is a L<MooseX::Singleton
979             |https://metacpan.org/module/MooseX::Singleton> and as such needs to be called in a
980             slightly different fashion. This method can be used to either connect to the existing
981             switchboard or start the switchboard with new settings. Each call to this method will
982             implement the settings passed in %args merging them with any pre-existing settings.
983             Where pre-existing settings disagree with new settings the new settings take
984             precedence. So be careful!
985              
986             B<Accepts:> [%args|$args_ref|full/file/path.(json|yml)] %args are treated the same
987             as attributes passed to other class style calls to new. The data can either be
988             passed as a fat comma list or a hashref. If this method receives a string it will
989             try to treat it like a full file path to a JSON or YAML file with the equivalent
990             $args_ref stored. See L<conf_file|/conf_file> to pass a file path and arguments.
991              
992             B<Returns:> an instance of the Log::Shiras::Switchboard class called an 'operator'.
993             This operator can act on the switchboard to perform any of the methods including
994             any attribute access methods.
995              
996             =back
997              
998             =head2 Attributes
999              
1000             Data passed to L<get_operator|/get_operator( %args )> when creating an instance. For
1001             modification of these attributes see the remaining L<Methods|/Methods>
1002             used to act on the operator. B<DO NOT USE 'Log::Shiras::Switchboard-E<gt>new' to get
1003             a new class instance>
1004              
1005             =head3 name_space_bounds
1006              
1007             =over
1008              
1009             B<Definition:> This attribute stores the boundaries set for the name-space management of
1010             communications (generally from L<Log::Shiras::Telephone>) message data sources. This
1011             value ref defines where in the name-space, to which L<reports|/reports>, and at L<what
1012             urgency level|/logging_levels> messages are allows to pass. Name spaces are stored as
1013             a L<hash of hashes|http://perldoc.perl.org/perldsc.html#HASHES-OF-HASHES> that goes as
1014             deep as needed. To send a message between a specific caller name-space and a named
1015             'report' destination this hash ref tree must have the key 'UNBLOCK' at or below the
1016             target name space in the hashref tree. The UNBLOCK key must have as a value a hashref
1017             with report names as keys and the minimum allowed L<pass level|/logging_levels> as the
1018             value. That(ose) report(s) then remain(s) open to communication farther out on the
1019             caller name space branch until a new UNBLOCK key sets different permission level or
1020             a 'BLOCK' key is implemented. The difference between a BLOCK and UNBLOCK key is that
1021             a BLOCK key value only needs to contain report keys (the key values are unimportant).
1022             Any level assigned to the report name by a BLOCK key is ignored and all communication
1023             at that point and further in the branch is cut off all for all deeper levels of the
1024             name space branch for that report. There are a couple of significant points for review;
1025              
1026             =over
1027              
1028             B<*> UNBLOCK and BLOCK should not be used as branch of the telephone name-space tree
1029              
1030             B<*> If a caller name-space is not listed here or a report name is not explicitly
1031             UNBLOCKed then the message is blocked by default.
1032              
1033             B<*> Even though 'log_file' is the default report it is not 'UNBLOCK'ed by default.
1034             It must be explicitly UNBLOCKed to be used.
1035              
1036             B<*> UNBLOCKing or BLOCKing of a report can occur independant of it's existance.
1037             This allows the addition of a report later and have it work upon its creation.
1038              
1039             B<*> If an UNBLOCK and BLOCK key exist at the same point in a name space then
1040             the hashref associated with the UNBLOCK key is evaluated first and the hashref
1041             associated with the BLOCK key is evaluated second. This means that the BLOCK
1042             command can negate a report UNBLOCKing level.
1043              
1044             B<*> Any name space on the same branch (but deeper) than an UNBLOCK command remains
1045             UNBLOCKed for the listed report urgency levels until a deeper UNBLOCK or BLOCK is
1046             registered for that report.
1047              
1048             B<*> When UNBLOCKing a report at a deeper level than an initial UNBLOCK setting
1049             the new level can be set higher or lower than the initial setting.
1050              
1051             B<*> BLOCK commands are only valuable deeper than an initial UNBLOCK command. The
1052             Tree trunk starts out 'BLOCK'ed by default.
1053              
1054             B<*> All BLOCK commands completly block the report(s) named for that point and
1055             deeper independant of the urgency value associated with report name key in
1056             the BLOCK hashref.
1057              
1058             B<*> The hash key whos hashref value contains an UNBLOCK hash key is the point in
1059             the NameSpace where the report is UNBLOCKed to the defined level.
1060              
1061             =back
1062              
1063             B<Default> all caller name-spaces are blocked (no reporting)
1064              
1065             B<Range> The caller name-space is stored and searched as a hash of hashes. No
1066             array refs will be correctly read as any part of the name-space definition. At each
1067             level of the name-space the switchboard will also recognize the special keys 'UNBLOCK'
1068             and 'BLOCK' I<in that order>. As a consequence UNBLOCK and BLOCK are not supported as
1069             name-space elements. Each UNBLOCK (or BLOCK) key should have a hash ref of L<report
1070             |/reports> name keys as it's value. The hash ref of report name keys should contain
1071             the minimum allowed urgency level down to which the report is UNBLOCKed. The value
1072             associated with any report key in a BLOCK hash ref is not tested since BLOCK closes
1073             all reporting from that point and deeper.
1074              
1075             B<Example>
1076              
1077             name_space_bounds =>{
1078             Name =>{#<-- name-space
1079             Space =>{#<-- name-space
1080             UNBLOCK =>{#<-- Telephone name-space 'Name::Space' is unblocked
1081             log_file => 'warn'#<-- but only for calls to the 'log_file' report
1082             }, # with an urgency of 'warn' or greater
1083             Boundary =>{#<-- name-space
1084             UNBLOCK =>{#<-- The deeper space 'Name::Space::Boundary' receives a new setting
1085             log_file => 'trace',#<-- messages are allowed at 'trace' urgency now
1086             special_report => 'eleven',<-- a new report and level are added
1087             },
1088             Place =>{},<-- deeper name-space - log_file permissions still 'trace'
1089             },
1090             },
1091             },
1092             }
1093              
1094             B<Warning> All active name-space boundaries must coexist in the singleton. There
1095             is only one master name-space for the singleton. New calls for object intances can
1096             overwrite existing object instances name-space boundaries. No cross instance name-space
1097             protection is done. This requires conscious managment! I<It is entirely possible to call
1098             for another operator in the same program space with overlapping name-space boundaries that
1099             changes reporting for a callers originally used in the context of the original operator.>
1100              
1101             B<attribute methods> Methods provided to adjust this attribute
1102              
1103             =over
1104              
1105             B<get_name_space>
1106              
1107             =over
1108              
1109             B<Definition:> Returns the full program namespace
1110              
1111             =back
1112              
1113             =back
1114              
1115             =back
1116              
1117             =head3 reports
1118              
1119             =over
1120              
1121             B<Definition:> This attribute stores report names and associated composed class
1122             instances for that name. The attribute expects a L<hash of arrays
1123             |http://perldoc.perl.org/perldsc.html#HASHES-OF-ARRAYS>. Each hash key is the
1124             report name and the array contains the report instances associated with that name. Each
1125             passed array object will be tested to see if it is an object that can( 'add_line' ).
1126             If not this code will try to coerce the passed reference at the array position into an
1127             object using L<MooseX::ShortCut::BuildInstance>.
1128              
1129             B<Default> no reports are active. If a message is sent to a non-existant report
1130             name then nothing happens unless L<self reporting|Log::Shiras::Unhide> is fully enabled.
1131             Then it is possible to collect various warning messages related to the failure of a
1132             message.
1133              
1134             B<Example>
1135              
1136             reports =>{
1137             log_file =>[<-- report name
1138             Print::Wisper->new,#<-- a reporting instance of a class ( see Synopsis )
1139             {#<-- MooseX::ShortCut::BuildInstance definition for a different report
1140             package => 'Print::Excited',#<-- name this (new) class
1141             add_methods =>{
1142             add_line => sub{#<-- ensure it has an 'add_line' method
1143             shift;
1144             my @input = ( ref $_[0]->{message} eq 'ARRAY' ) ?
1145             @{$_[0]->{message}} : $_[0]->{message};
1146             my @new_list;
1147             map{ push @new_list, $_ if $_ } @input;
1148             chomp @new_list;
1149             print '!!!' . uc(join( ' ', @new_list)) . "!!!\n";
1150             }
1151             },
1152             }
1153             ],
1154             other_name =>[],#<-- name created but no report instances added (maybe later?)
1155             },
1156              
1157             B<warning:> any re-definition of the outputs for a report name will only push the new
1158             report instance onto the existing report array ref. To remove an existing report output
1159             instance you must L<delete|/remove_reports( @report_list )> all report instances and the
1160             report name and then re-implement the report name and it's outputs.
1161              
1162             B<attribute methods> Methods provided to adjust this attribute
1163              
1164             =over
1165              
1166             B<get_reports>
1167              
1168             =over
1169              
1170             B<Definition:> Returns the full report hashref of arrays
1171              
1172             =back
1173              
1174             B<has_no_reports( $report )>
1175              
1176             =over
1177              
1178             B<Definition:> Checks if the $report requested has a key in the hashref
1179              
1180             =back
1181              
1182             B<get_report( $report )>
1183              
1184             =over
1185              
1186             B<Definition:> Returns the array ref of stored report objects for that $report
1187              
1188             =back
1189              
1190             B<remove_reports( $report1 [, $report2] )>
1191              
1192             =over
1193              
1194             B<Definition:> Deletes all storeage (and use of) $report1 etc.
1195              
1196             =back
1197              
1198             =back
1199              
1200             =back
1201              
1202             =head3 logging_levels
1203              
1204             =over
1205              
1206             B<Definition:> Each report name recognizes 12 different logging levels [0..11]
1207             (L<They go to 11!
1208             |http://en.wikipedia.org/wiki/Up_to_eleven#Original_scene_from_This_Is_Spinal_Tap> :). Each
1209             position within the logging levels can be assigned a name that is not case sensitive.
1210             Either the position integer or the name assigned to that position can be used to describe
1211             the urgency 'level'. Each message can be sent with name. The urgency level of a message
1212             L<can be defined|master_talk( $args_ref )> for each sent message. If you do not wish to
1213             use the default name for each logging position or you wish to name the logging positions
1214             that are not named then use this attribute. Not all of the elements need to be defined.
1215             There can be gaps between defined levels but counting undefined positions there can never
1216             be more than 12 total positions in the level array. The priority or urgency is lowest
1217             first to highest last on the list. Where requests sent with an urgency at or above the
1218             permissions barrier will pass. Since there are default priority names already in place
1219             this attribute is a window dressing setting and not much more.
1220              
1221             B<Default> The default array of priority / urgency levels is;
1222              
1223             'trace', 'debug', 'info', 'warn', 'error', 'fatal',
1224             undef, undef, undef, undef, undef, 'eleven',
1225              
1226             Any report name without a custom priority array will use the default array.
1227              
1228             B<Example>
1229              
1230             logging_levels =>{
1231             log_file =>[ qw(<-- report name (others use the default list)
1232             foo
1233             bar
1234             baz
1235             fatal
1236             ) ],
1237             }
1238              
1239             B<fatal> The Switchboard will L<confess|Carp/confess> for all messages sent with a
1240             priority or urgency level that matches qr/fatal/i. The switchboard will fully dispatch
1241             the message to it's intended report(s) prior to confessing the message. At this point
1242             the script will die. If the message is not approved (even at the fatal level) then
1243             nothing happens. 'fatal' can be set anywhere in the custom priority list from lowest
1244             to highest but fatal is the only string that will die. (priorities higher than fatal
1245             will not die) B<But>, if the message is blocked for the message I<name-space, report,
1246             and level> then the code will NOT die.> If 'fatal' is the requested level from the
1247             caller but it is not on the (custom) list for the report desination then the priority
1248             of the message drops to 0 (trace equivalent) and that level of urgencie must be accepted
1249             for the report to die. (even if the listed level at the 0 position is not 'fatal').
1250              
1251             =back
1252              
1253             B<attribute methods> Methods provided to adjust this attribute
1254              
1255             =over
1256              
1257             B<has_log_levels( $report )>
1258              
1259             =over
1260              
1261             B<Definition:> Indicates if a custom log level list is stored for $report.
1262              
1263             =back
1264              
1265             B<add_log_levels( $report )>
1266              
1267             =over
1268              
1269             B<Definition:> Sets the log level name strings for $report
1270              
1271             B<Accepts:> the value must be an array ref of no more than 12 total positions
1272              
1273             =back
1274              
1275             B<remove_log_levels( $report1 [, $report2] )>
1276              
1277             =over
1278              
1279             B<Definition:> Removes the custom log_level list for the $report[s]
1280              
1281             =back
1282              
1283             B<set_all_log_levels( $full_hashref_of_arrayrefs )>
1284              
1285             =over
1286              
1287             B<Definition:> Completely resets all custom log levels to $full_hashref_of_arrayrefs
1288              
1289             =back
1290              
1291             B<get_all_log_levels>
1292              
1293             =over
1294              
1295             B<Definition:> Returns the full hashref of arrayrefs for all custom log levels
1296              
1297             =back
1298              
1299             =back
1300              
1301             =head3 all_buffering
1302              
1303             =over
1304              
1305             B<Definition:> Buffering in this package is only valuable if you want to eliminate some
1306             of the sent messages after they were created. Buffering allows for clearing of sent
1307             messages from between two save points. For this to occur buffering must be on and
1308             L<flushing the buffer|/send_buffer_to_output( $report_name )> to the report need to
1309             occur at all known good points. When some section of prior messages are to be discarded
1310             then a L<clear_buffer|/clear_buffer( $report_name )> command can be sent and all buffered
1311             messages after the last flush will be discarded. If buffering is turned off the
1312             messages are sent directly to the report for processing with no holding period. This
1313             attribute accepts a hash ref where the keys are report names and the values empty arrayrefs
1314             You could theoretically pre-load your buffer here but it is not reccomended. If a new
1315             instance of this class is called with an 'all_buffering' arg sent then it will flush any
1316             pre-existing buffers (even if they are duplicated in the new call) then delete them and
1317             set the new passed list fresh.
1318              
1319             B<Default> All buffering is off
1320              
1321             B<Example>
1322              
1323             buffering =>{
1324             log_file => [],
1325             }
1326              
1327             B<attribute methods> Methods provided to adjust this attribute
1328              
1329             =over
1330              
1331             B<set_all_buffering( $hasref_of_arrayrefs )>
1332              
1333             =over
1334              
1335             B<Definition:> completely resets all buffers to $hasref_of_arrayrefs but flushes
1336             all the old buffers first
1337              
1338             =back
1339              
1340             B<has_buffer( $report )>
1341              
1342             =over
1343              
1344             B<Definition:> Checks if there is an active buffer for $report
1345              
1346             =back
1347              
1348             B<stop_buffering( $report1 [, $report2] )>
1349              
1350             =over
1351              
1352             B<Definition:> Removes the buffer for the $report[s] (flushing them first)
1353              
1354             =back
1355              
1356             =back
1357              
1358             =back
1359              
1360             =head3 conf_file
1361              
1362             =over
1363              
1364             B<Definition:> It is possible to pass all the Attribute settings to L<get_operator
1365             |/get_operator( %args )> as a config file. If you wish to mix your metaphores then
1366             one of the attribute keys can be 'conf_file' with the value being the full file path
1367             of a YAML or JSON file. If you pass other attributes and conf_file then where there
1368             is conflict the other attributes overwrite the file settings.
1369              
1370             B<Default> nothing
1371              
1372             B<Accepts:> a full file path to a config file with attribute settings
1373              
1374             =back
1375              
1376             =head2 Methods
1377              
1378             These are methods used to adjust outcomes for the activities in the switchboard or to
1379             leverage information held by the switchboard.
1380              
1381             =head3 master_talk( $args_ref )
1382              
1383             =over
1384              
1385             B<Definition:> This is a way to directly call a report using the switchboard operator. In a
1386             real telephone situation this would be that cool handset that the telephone repairman brought
1387             with him. Like the Telephone repairman's phone it plugs in directly to the switchboard (or
1388             in the repairmains case into a telephone line) and is a bit trickier to operate than absolutely
1389             necessary. For a nicer message sending interface see L<Log::Shiras::Telephone>. When the
1390             $args_ref message is received the switchboard will check the L<name_space_bounds
1391             |/name_space_bounds> permissions. If the message passes that test then it will attach metadata
1392             to to the $args_ref. The metadata attached to the message is a follows;
1393              
1394             date_time => The date and time the message was sent in CLDR format of 'yyyy-MM-dd hh:mm:ss'
1395              
1396             package => The package name of the message source
1397              
1398             filename => The (full) file name of the message source
1399              
1400             line => The line number of the message sourceIf and then test;
1401            
1402             Any L<message buffering|/all_buffering> is then handled or the message is sent to the report
1403             name and each report in that name-space receives the $args_ref as the arguments to a call
1404             $report->add_line( $args_ref ). When that is complete the message is checked to see if it
1405             is fatal;
1406              
1407             $args_ref->{level} =~ /fatal/i
1408              
1409             I<If the message was buffered first the script will not die until the message was flushed into
1410             the report from the buffer.>
1411              
1412             B<Returns:> The number of times the add_line call was made. There are some special cases.
1413              
1414             -3 = The call was not allowed by name_space permissions set in the switchboard
1415             -2 = The message was buffered rather than sent to a report
1416             -1 = The message was blocked as risking deep recursion
1417             0 = The call had permissions but found no report implementations to connect with
1418             1(and greater) = This indicates how many report instances received the message
1419              
1420             B<Accepts:> The passed args must be a HashRef and contain the following elements (any
1421             others will be ignored by the switchboard but not stripped).
1422              
1423             =over
1424              
1425             B<name_space> the value is the caller name_space as used by L<name_space_bounds|/name_space_bounds>
1426              
1427             B<level> value is the urgency level of the message sent. It can either be an integer in the
1428             set [0..11] or one of the L<defined logging level strings|/logging_levels>.
1429              
1430             B<report> the value is the L<report|/reports> name (destination) for the message ref
1431              
1432             B<message> the message key must have a value that is an array_ref. It is assumed that
1433             content can be parsed into somthing else at the report level including any ArrayRef
1434             sub-elements that may be Objects or hashrefs.
1435              
1436             B<carp_stack> if this key is passed and set to a true value then L<Carp> - longmess will
1437             be run on the message and the results will be split on the newline and pushed onto the end
1438             of the 'message' array_ref.
1439              
1440             B<source_sub> this key is generally handled in the background by Log::Shiras but if you
1441             write a new caller subroutine to lay over 'master_talk' then providing that name to this
1442             key will make the metada added to the message stop at the correct caller level.
1443              
1444             =over
1445              
1446             B<example>
1447              
1448             {
1449             name_space => 'MyCoolScript::my_subroutine',
1450             level => 'warn',
1451             report => 'log_file',
1452             message =>[ 'Dont ignore these words' ],
1453             }
1454              
1455             =back
1456              
1457             B<carp_stack> [optional] This is a simple passed boolean value that will trigger a traditional
1458             L<Carp> longmess stack to be split by /\n\s*/ and then pushed on the end of the message array ref.
1459             Before the message is stored this key will be deleted whether it was positive or negative.
1460              
1461             B<source_sub> [really optional] This is rarely used unless you are writing a replacement for
1462             L<Log::Shiras::Telephone>. If you are writing a replacement then a full method space string is
1463             passed here. This will be used to travel the L<caller|http://perldoc.perl.org/functions/caller.html>
1464             stack to find where the message line originated. The equivalent for Log::Shiras::Telephone is;
1465              
1466             =over
1467              
1468             B<example>
1469              
1470             { source_sub => 'Log::Shiras::Telephone::talk' }
1471              
1472             =back
1473              
1474             =back
1475              
1476             =back
1477              
1478             =head3 add_name_space_bounds( $ref )
1479              
1480             =over
1481              
1482             B<Definition:> This will L<graft|Data::Walk::Graft/graft_data( %argsE<verbar>$arg_ref )>
1483             more name-space boundaries onto the existing name-space. I<The passed ref will be treated
1484             as the 'scion_ref' using Data::Walk::Graft.>
1485              
1486             B<Accepts:> a data_ref (must start at the root of the main ref) of data to graft to the main
1487             name_space_bounds ref
1488              
1489             B<Returns:> The updated name-space data ref
1490              
1491             =back
1492              
1493             =head3 remove_name_space_bounds( $ref )
1494              
1495             =over
1496              
1497             B<Definition:> This will L<prune|Data::Walk::Prune/prune_data( %args )> the name-space
1498             L<boundaries|/name_space_bounds> using the passed name-space ref. I<The passed ref will
1499             be treated as the 'slice_ref' using Data::Walk::Prune.>
1500              
1501             B<Accepts:> a data_ref (must start at the root of the main ref) of data used to prune the
1502             main name_space_bounds ref
1503              
1504             B<Returns:> The updated name-space data ref
1505              
1506             =back
1507              
1508             =head3 add_reports( %args )
1509              
1510             =over
1511              
1512             B<Definition:> This will add more L<report|/reports> output instances to the existing
1513             named report registered instances. If the items in the passed report list are not already
1514             report object instances that -E<gt>can( 'add_line' ) there will be an attempt to build
1515             them using L<MooseX::ShortCut::BuildInstance/build_instance( %argsE<verbar>\%args )>.
1516             If (and only if) the report name does not exist then the report name will also be added to the
1517             report registry.
1518              
1519             B<Accepts:> a hash of arrays with the report objects as items in the array
1520              
1521             B<Returns:> 1
1522              
1523             =back
1524              
1525             =head3 get_log_levels( $report_name )
1526              
1527             =over
1528              
1529             B<Definition:> This will return the L<log level names|/logging_levels> names for a given
1530             report name in an array ref. If no custom levels are defined it will return the default
1531             level list.
1532              
1533             B<Accepts:> a report name
1534              
1535             B<Returns:> an array ref of the defined log levels for that report.
1536              
1537             =back
1538              
1539             =head3 send_buffer_to_output( $report_name )
1540              
1541             =over
1542              
1543             B<Definition:> This will flush the contents of the $report_name L<buffer|/buffering>
1544             to all the associated report objects.
1545              
1546             B<Accepts:> a $report_name
1547              
1548             B<Returns:> The number of times that $report_object->add_line( $message_ref ) was called to
1549             complete the buffer flush.
1550              
1551             =back
1552              
1553             =head3 start_buffering( $report_name )
1554              
1555             =over
1556              
1557             B<Definition:> This will start L<buffering|/buffering> for the $report_name. If the buffering is
1558             already implemented then nothing new happens. No equivalent report or name_space_bounds
1559             are required to turn buffering on!
1560              
1561             B<Accepts:> a $report_name string
1562              
1563             B<Returns:> 1
1564              
1565             =back
1566              
1567             =head3 clear_buffer( $report_name )
1568              
1569             =over
1570              
1571             B<Definition:> This will remove all messages currently in the L<buffer|/buffering>
1572             without sending them to the report.
1573              
1574             B<Accepts:> a $report_name string
1575              
1576             B<Returns:> 1
1577              
1578             =back
1579              
1580             =head1 SYNOPSIS
1581              
1582             This is pretty long so I put it at the end
1583              
1584             #!perl
1585             use Modern::Perl;
1586             use lib 'lib', '../lib',;
1587             use Log::Shiras::Unhide qw( :debug :InternalSwitchboarD );#
1588             use Log::Shiras::Switchboard;
1589             ###InternalSwitchboarD use Log::Shiras::Report::Stdout;
1590             $| = 1;
1591             ###LogSD warn "lets get ready to rumble...";
1592             my $operator = Log::Shiras::Switchboard->get_operator(
1593             name_space_bounds =>{
1594             main =>{
1595             UNBLOCK =>{
1596             # UNBLOCKing the quiet, loud, and run reports (destinations)
1597             # at the 'main' caller name_space and deeper
1598             quiet => 'warn',
1599             loud => 'info',
1600             run => 'trace',
1601             },
1602             },
1603             Log =>{
1604             Shiras =>{
1605             ###InternalSwitchboarD Switchboard =>{#<-- Internal reporting enabled here
1606             ###InternalSwitchboarD get_operator =>{
1607             ###InternalSwitchboarD UNBLOCK =>{
1608             ###InternalSwitchboarD # UNBLOCKing log_file
1609             ###InternalSwitchboarD # at Log::Shiras::Switchboard::get_operator
1610             ###InternalSwitchboarD # (self reporting)
1611             ###InternalSwitchboarD log_file => 'info',
1612             ###InternalSwitchboarD },
1613             ###InternalSwitchboarD },
1614             ###InternalSwitchboarD master_talk =>{
1615             ###InternalSwitchboarD _buffer_decision =>{
1616             ###InternalSwitchboarD UNBLOCK =>{
1617             ###InternalSwitchboarD # UNBLOCKing log_file
1618             ###InternalSwitchboarD # at Log::Shiras::Switchboard::master_talk::_buffer_decision
1619             ###InternalSwitchboarD # (self reporting)
1620             ###InternalSwitchboarD log_file => 'trace',
1621             ###InternalSwitchboarD },
1622             ###InternalSwitchboarD },
1623             ###InternalSwitchboarD },
1624             ###InternalSwitchboarD send_buffer_to_output =>{
1625             ###InternalSwitchboarD UNBLOCK =>{
1626             ###InternalSwitchboarD # UNBLOCKing log_file
1627             ###InternalSwitchboarD # at Log::Shiras::Switchboard::_flush_buffer
1628             ###InternalSwitchboarD # (self reporting)
1629             ###InternalSwitchboarD log_file => 'info',
1630             ###InternalSwitchboarD },
1631             ###InternalSwitchboarD },
1632             ###InternalSwitchboarD },#<-- Internal reporting enabled through here
1633             },
1634             },
1635             },
1636             reports =>{
1637             quiet =>[
1638             Print::Wisper->new,
1639             ],
1640             loud =>[
1641             {
1642             package => 'Print::Excited',
1643             add_methods =>{
1644             add_line => sub{
1645             shift;
1646             my @input = ( ref $_[0]->{message} eq 'ARRAY' ) ?
1647             @{$_[0]->{message}} : $_[0]->{message};
1648             my @new_list;
1649             map{ push @new_list, $_ if $_ } @input;
1650             chomp @new_list;
1651             print '!!!' . uc(join( ' ', @new_list)) . "!!!\n";
1652             }
1653             },
1654             }
1655             ],
1656             ###InternalSwitchboarD log_file =>[
1657             ###InternalSwitchboarD Log::Shiras::Report::Stdout->new,
1658             ###InternalSwitchboarD ],
1659             },
1660             all_buffering =>{
1661             quiet => [],
1662             },
1663             );
1664             ###LogSD warn "sending the message 'Hello World 1'";
1665             $operator->master_talk({
1666             report => 'log_file', level => 'warn', name_space => 'main',
1667             message =>[ 'Hello World 1' ] });
1668             ###LogSD warn "The name_space 'main' does not have destination 'log_file' permissions";
1669             ###LogSD warn "sending the message 'Hello World 2' to the report 'quiet'";
1670             $operator->master_talk({
1671             report => 'quiet', level => 'warn', name_space => 'main',
1672             message =>[ 'Hello World 2' ] });
1673             ###LogSD warn "message went to the buffer - turning off buffering for the 'quiet' destination ...";
1674             $operator->stop_buffering( 'quiet' );
1675             ###LogSD warn "should have printed what was in the 'quiet' buffer ...";
1676             $operator->master_talk({
1677             report => 'quiet', level => 'debug', name_space => 'main',
1678             message =>[ 'Hello World 3' ] });
1679             ###LogSD warn "sending the message 'Hello World 4' to the report 'loud'";
1680             $operator->master_talk({
1681             report => 'loud', level => 'info', name_space => 'main',
1682             message =>[ 'Hello World 4' ] });
1683             ###LogSD warn "sending the message 'Hello World 5' to the report 'run'";
1684             my $result = 1;
1685             $result = $operator->master_talk({
1686             report => 'run', level => 'warn', name_space => 'main',
1687             message =>[ 'Hello World 5' ] });
1688             ###LogSD warn "message to 'run' at 'warn' level was approved";
1689             ###LogSD warn "...but found -$result- reporting destinations (None were set up)";
1690              
1691             package Print::Wisper;
1692             sub new{
1693             bless {}, shift;
1694             }
1695             sub add_line{
1696             shift;
1697             my @input = ( ref $_[0]->{message} eq 'ARRAY' ) ?
1698             @{$_[0]->{message}} : $_[0]->{message};
1699             my @new_list;
1700             map{ push @new_list, $_ if $_ } @input;
1701             chomp @new_list;
1702             print '--->' . lc(join( ' ', @new_list )) . "<---\n";
1703             }
1704              
1705             1;
1706              
1707             #######################################################################################
1708             # Synopsis Screen Output for the following condition
1709             # use Log::Shiras::Unhide;
1710             # 01: --->hello world 2<---
1711             # 02: !!!HELLO WORLD 4!!!
1712             #######################################################################################
1713              
1714             #######################################################################################
1715             # Synopsis Screen Output for the following condition
1716             # use Log::Shiras::Unhide qw( :debug );
1717             # 01: Using Log::Shiras::Unhide-v0.29_1 strip_match string: (LogSD) at ../lib/Log/Shiras/Unhide.pm line 88.
1718             # 02: lets get ready to rumble... at log_shiras_switchboard.pl line 7.
1719             # 03: sending the message 'Hello World 1' at log_shiras_switchboard.pl line 80.
1720             # 04: The name_space 'main' does not have destination 'log_file' permissions at log_shiras_switchboard.pl line 84.
1721             # 05: sending the message 'Hello World 2' to the report 'quiet' at log_shiras_switchboard.pl line 85.
1722             # 06: message went to the buffer - turning off buffering for the 'quiet' destination ... at log_shiras_switchboard.pl line 89.
1723             # 07: --->hello world 2<---
1724             # 08: should have printed what was in the 'quiet' buffer ... at log_shiras_switchboard.pl line 91.
1725             # 09: sending the message 'Hello World 4' to the report 'loud' at log_shiras_switchboard.pl line 95.
1726             # 10: !!!HELLO WORLD 4!!!
1727             # 11: sending the message 'Hello World 5' to the report 'run' at log_shiras_switchboard.pl line 99.
1728             # 12: message to 'run' at 'warn' level was approved at log_shiras_switchboard.pl line 104.
1729             # 13: ...but found -0- reporting destinations (None were set up) at log_shiras_switchboard.pl line 105.
1730             #######################################################################################
1731              
1732             #######################################################################################
1733             # Synopsis Screen Output for the following conditions
1734             # use Log::Shiras::Unhide qw( :debug :InternalSwitchboarD );
1735             # 01: Using Log::Shiras::Unhide-v0.29_1 strip_match string: (LogSD|InternalSwitchboarD) at ../lib/Log/Shiras/Unhide.pm line 88.
1736             # 02: You uncovered internal logging statements for Log::Shiras::Types-v0.29_1 at ..\lib\Log\Shiras\Types.pm line 5.
1737             # 03: You uncovered internal logging statements for Log::Shiras::Switchboard-v0.29_1 at ..\lib\Log\Shiras\Switchboard.pm line 5.
1738             # 04: lets get ready to rumble... at log_shiras_switchboard.pl line 7.
1739             # 05: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1740             # 06: | line - 0704 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1741             # 07: :( Arrived at _buffer_decision for report: log_file
1742             # 08: ..with buffer setting: ):
1743             # 09: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1744             # 10: | line - 0715 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1745             # 11: :( Current action for report -log_file- is: report ):
1746             # 12: | level - 2 | name_space - Log::Shiras::Switchboard::get_operator
1747             # 13: | line - 0211 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1748             # 14: :( Switchboard finished updating the following arguments:
1749             # 15: reports
1750             # 16: name_space_bounds
1751             # 17: all_buffering ):
1752             # 18: sending the message 'Hello World 1' at log_shiras_switchboard.pl line 80.
1753             # 19: The name_space 'main' does not have destination 'log_file' permissions at log_shiras_switchboard.pl line 84.
1754             # 20: sending the message 'Hello World 2' to the report 'quiet' at log_shiras_switchboard.pl line 85.
1755             # 21: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1756             # 22: | line - 0704 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1757             # 23: :( Arrived at _buffer_decision for report: quiet
1758             # 24: ..with buffer setting: 1 ):
1759             # 25: | level - 1 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1760             # 26: | line - 0709 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1761             # 27: # 01: :( The buffer is active - sending the message to the buffer (not the report). ):
1762             # 28: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1763             # 29: | line - 0715 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1764             # 30: :( Current action for report -quiet- is: buffer ):
1765             # 31: message went to the buffer - turning off buffering for the 'quiet' destination ... at log_shiras_switchboard.pl line 89.
1766             # 32: --->hello world 2<---
1767             # 33: should have printed what was in the 'quiet' buffer ... at log_shiras_switchboard.pl line 91.
1768             # 34: sending the message 'Hello World 4' to the report 'loud' at log_shiras_switchboard.pl line 95.
1769             # 35: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1770             # 36: | line - 0704 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1771             # 37: :( Arrived at _buffer_decision for report: loud
1772             # 38: ..with buffer setting: ):
1773             # 39: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1774             # 40: | line - 0715 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1775             # 41: :( Current action for report -loud- is: report ):
1776             # 42: !!!HELLO WORLD 4!!!
1777             # 43: sending the message 'Hello World 5' to the report 'run' at log_shiras_switchboard.pl line 99.
1778             # 44: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1779             # 45: | line - 0704 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1780             # 46: :( Arrived at _buffer_decision for report: run
1781             # 47: ..with buffer setting: ):
1782             # 48: | level - 2 | name_space - Log::Shiras::Switchboard::master_talk::_buffer_decision
1783             # 49: | line - 0715 | file_name - ..\lib\Log\Shiras\Switchboard.pm
1784             # 50: :( Current action for report -run- is: report ):
1785             # 51: message to 'run' at 'warn' level was approved at log_shiras_switchboard.pl line 104.
1786             # 52: ...but found -0- reporting destinations (None were set up) at log_shiras_switchboard.pl line 105.
1787             #######################################################################################
1788              
1789             =head2 SYNOPSIS EXPLANATION
1790              
1791             =over
1792              
1793             use Log::Shiras::Unhide qw( :debug :InternalSwitchboarD );
1794             ..
1795             ###LogSD warn "lets get ready to rumble...";
1796              
1797             Log::Shiras::Unhide strips ###MyCoolTag tags - see L<Log::Shiras::Unhide> for more information.
1798             It represents the only driver between the three example outputs (All run from the same basic
1799             script). For instance when the :debug tag is passed to Unhide then ###LogSD is stripped.
1800             When :InternalSwitchboarD is passed it strips ###InternalSwitchboarD.
1801              
1802             Each of the remaining functions is documented above but the difference between the three
1803             outputs are based on what is unhid. In all cases 'Hello World [1..5]' is sent to master_talk
1804             in the switchboard. All of the calls are valid syntax but not all calls have the necessary
1805             target or urgency to be completed.
1806              
1807             In the first output it is obvious that only 'Hello World 2' and 'Hello World 4' have the
1808             necessary permissions to be completed. Each one is sent to a different report object so it
1809             will be obvious based on the output what path it took to be printed.
1810              
1811             In the second output only the ###LogSD tags are removed and so comments associated with the
1812             actions are exposed. In this case these comments only exist in the script space so
1813             warning messages are mostly the only thing exposed that is visible. Since ~::Unhide is a
1814             source filter it also provides a warning from the class showing that a source filter is
1815             turned on and what is being scrubbed. This includes scrubbing through the script and
1816             all used modules. (But not 'with' roles!).
1817              
1818             In the final output the ###InternalSwitchboarD tags are also stripped. Since there
1819             are a lot of these in L<Log::Shiras::Switchboard> there is a number of things available to
1820             see from that class. However the operator only has released log_file messages for the
1821             ~::get_operator and ~::_buffer_decision name spaces. A new class is also exposed that
1822             can take advantage of message metadata and uses it to show where the message came from
1823             as well has what urgency it was sent with.
1824              
1825             =back
1826              
1827             =head1 SUPPORT
1828              
1829             =over
1830              
1831             L<github Log-Shiras/issues|https://github.com/jandrew/Log-Shiras/issues>
1832              
1833             =back
1834              
1835             =head1 TODO
1836              
1837             =over
1838              
1839             B<1.> Add method to pull a full caller($x) stack and add it to message
1840             metadata. Probably should be triggered in the master_talk call args.
1841              
1842             B<2.> Investigate the possibility of an ONLY keyword in addition to
1843             of UNBLOCK - how would this be implemented? - Future uncertain
1844              
1845             =back
1846              
1847             =head1 AUTHOR
1848              
1849             =over
1850              
1851             =item Jed Lund
1852              
1853             =item jandrew@cpan.org
1854              
1855             =back
1856              
1857             =head1 COPYRIGHT
1858              
1859             This program is free software; you can redistribute
1860             it and/or modify it under the same terms as Perl itself.
1861              
1862             The full text of the license can be found in the
1863             LICENSE file included with this module.
1864              
1865             =head1 DEPENDENCIES
1866              
1867             =over
1868              
1869             L<version>
1870              
1871             L<5.010|http://perldoc.perl.org/perl5100delta.html>
1872              
1873             L<utf8>
1874              
1875             L<MooseX::Singleton>
1876              
1877             L<MooseX::StrictConstructor>
1878              
1879             L<MooseX::HasDefaults::RO>
1880              
1881             L<DateTime>
1882              
1883             L<Carp> - cluck confess
1884              
1885             L<MooseX::Types::Moose> - HashRef ArrayRef Bool RegexpRef Str Int
1886              
1887             L<Clone> - clone
1888              
1889             L<Data::Dumper>
1890              
1891             L<MooseX::ShortCut::BuildInstance> - v1.44 - build_instance should_re_use_classes
1892              
1893             L<Data::Walk::Extracted> - v0.28
1894              
1895             L<Data::Walk::Prune> - v0.028
1896              
1897             L<Data::Walk::Graft> - v0.028
1898              
1899             L<Data::Walk::Print> - v0.028
1900              
1901             L<Data::Walk::Clone> - v0.024
1902              
1903             L<Log::Shiras::Types>
1904              
1905             =back
1906              
1907             =head1 SEE ALSO
1908              
1909             =over
1910              
1911             L<Log::Shiras>
1912              
1913             =back
1914              
1915             =cut
1916              
1917             #########1 main pod documentation end 4#########5#########6#########7#########8#########9