File Coverage

blib/lib/Log/Dispatch/Config.pm
Criterion Covered Total %
statement 104 108 96.3
branch 26 34 76.4
condition 6 12 50.0
subroutine 20 20 100.0
pod 0 9 0.0
total 156 183 85.2


line stmt bran cond sub pod time code
1             package Log::Dispatch::Config;
2              
3 11     11   209189 use strict;
  11         22  
  11         520  
4 11     11   50 use vars qw($VERSION);
  11         13  
  11         623  
5             $VERSION = 0.11_02;
6              
7 11     11   6164 use Log::Dispatch;
  11         124713  
  11         367  
8 11     11   77 use base qw(Log::Dispatch);
  11         16  
  11         1014  
9 11     11   5623 use fields qw(config);
  11         14808  
  11         54  
10              
11             # caller depth: can be changed from outside
12             $Log::Dispatch::Config::CallerDepth = 0;
13              
14             # accessor for symblic reference
15             sub __instance {
16 66     66   120 my $class = shift;
17 11     11   902 no strict 'refs';
  11         20  
  11         10079  
18 66         113 my $instance = "$class\::_instance";
19 66 100       200 $$instance = shift if @_;
20 66         201 return $$instance;
21             }
22              
23             sub configure {
24 12     12 0 1471 my($class, $config) = @_;
25 12 50       50 die "no config file or configurator supplied" unless $config;
26              
27             # default configurator: AppConfig
28 12 100       82 unless (UNIVERSAL::isa($config, 'Log::Dispatch::Configurator')) {
29 8         3925 require Log::Dispatch::Configurator::AppConfig;
30 8         105 $config = Log::Dispatch::Configurator::AppConfig->new($config);
31             }
32              
33             # records conf time
34 12         133 $config->conf_time(time);
35 12         66 $class->__instance($config);
36             }
37              
38             sub configure_and_watch {
39 4     4 0 1435 my($class, $config) = @_;
40 4         17 $class->configure($config);
41              
42             # hack: __instance should return conf
43 4         10 $config = $class->__instance;
44              
45             # tells conf to watch config file
46 4         22 $config->should_watch(1);
47             }
48              
49             # backward compatibility
50             sub Log::Dispatch::instance {
51 2     2 0 636 __PACKAGE__->instance;
52             }
53              
54             sub instance {
55 18     18 0 1004330 my $class = shift;
56              
57 18         79 my $instance = $class->__instance;
58 18 50       65 unless (defined $instance) {
59 0         0 require Carp;
60 0         0 Carp::croak("Log::Dispatch::Config->configure not yet called.");
61             }
62              
63 18 100       120 if (UNIVERSAL::isa($instance, 'Log::Dispatch::Config')) {
64             # reload singleton on the fly
65 6 100       25 if ($instance->needs_reload) {
66 2         18 $class->reload;
67             }
68             }
69             else {
70             # first time call: $_instance is L::D::Configurator::*
71 12         48 $class->__instance($class->create_instance($instance));
72             }
73 17         42 return $class->__instance;
74             }
75              
76             sub needs_reload {
77 6     6 0 13 my $self = shift;
78 6   66     60 return $self->{config}->should_watch && $self->{config}->needs_reload;
79             }
80              
81             sub reload {
82 2     2 0 6 my $proto = shift;
83 2   33     13 my $class = ref $proto || $proto;
84 2         10 my $instance = $class->__instance;
85              
86             # reconfigure, and returns instance
87 2 50       10 my $meth = $instance->{config}->should_watch
88             ? \&configure_and_watch : \&configure;
89 2         9 $class->$meth($instance->{config});
90 2         14 $class->__instance($class->instance);
91             }
92              
93             sub create_instance {
94 12     12 0 25 my($class, $config) = @_;
95 12         53 $config->parse;
96              
97 12         97 my $global = $config->get_attrs_global;
98 11         287 my $callback = $class->format_to_cb($global->{format}, 0);
99 11         19 my %dispatchers;
100 11         16 foreach my $disp (@{$global->{dispatchers}}) {
  11         32  
101 17         60 $dispatchers{$disp} = $class->config_dispatcher(
102             $disp, $config->get_attrs($disp),
103             );
104             }
105 11         19 my %args;
106 11 50       36 $args{callbacks} = $callback if defined $callback;
107 11         100 my $instance = $class->new(%args);
108              
109 11         656 for my $dispname (keys %dispatchers) {
110 17         1581 my $logclass = delete $dispatchers{$dispname}->{class};
111 17         94 $instance->add(
112             $logclass->new(
113             name => $dispname,
114 17         28 %{$dispatchers{$dispname}},
115             ),
116             );
117             }
118              
119             # config info
120 11         2303 $instance->{config} = $config;
121              
122 11         85 return $instance;
123             }
124              
125             sub config_dispatcher {
126 17     17 0 79 my($class, $disp, $var) = @_;
127              
128 17 50       62 my $dispclass = $var->{class}
129             or die "class param missing for $disp";
130              
131 17         1147 eval qq{require $dispclass};
132 17 50 33     22207 die $@ if $@ && $@ !~ /locate/;
133              
134 17 100       63 if (exists $var->{format}) {
135 15         81 $var->{callbacks} = $class->format_to_cb(delete $var->{format}, 2);
136             }
137 17         72 return $var;
138             }
139              
140             sub format_to_cb {
141 26     26 0 49 my($class, $format, $stack) = @_;
142 26 100       80 return undef unless defined $format;
143              
144             # caller() called only when necessary
145 15         80 my $needs_caller = $format =~ /%[FLP]/;
146             return sub {
147 6     6   1798 my %p = @_;
148 6         18 $p{p} = delete $p{level};
149 6         13 $p{m} = delete $p{message};
150 6         12 $p{n} = "\n";
151 6         11 $p{'%'} = '%';
152              
153 6 100       16 if ($needs_caller) {
154 4         5 my $depth = 0;
155 4         47 $depth++ while caller($depth) =~ /^Log::Dispatch/;
156 4         7 $depth += $Log::Dispatch::Config::CallerDepth;
157 4         21 @p{qw(P F L)} = caller($depth);
158             }
159              
160 6         8 my $log = $format;
161 6         39 $log =~ s{
162             (%d(?:{(.*?)})?)| # $1: datetime $2: datetime fmt
163             (?:%([%pmFLPn])) # $3: others
164             }{
165 25 100 66     362 if ($1 && $2) {
    100          
    50          
166 1         4 _strftime($2);
167             }
168             elsif ($1) {
169 5         135 scalar localtime;
170             }
171             elsif ($3) {
172 19         81 $p{$3};
173             }
174             }egx;
175 6         45 return $log;
176 15         104 };
177             }
178              
179             {
180 11     11   61 use vars qw($HasTimePiece);
  11         23  
  11         630  
181 11     11   20 BEGIN { eval { require Time::Piece; $HasTimePiece = 1 }; }
  11         6524  
  11         131436  
182              
183             sub _strftime {
184 1     1   3 my $fmt = shift;
185 1 50       3 if ($HasTimePiece) {
186 1         11 return Time::Piece->new->strftime($fmt);
187             } else {
188 0           require POSIX;
189 0           return POSIX::strftime($fmt, localtime);
190             }
191             }
192             }
193              
194             1;
195             __END__