File Coverage

blib/lib/App/Framework/Feature/Logging.pm
Criterion Covered Total %
statement 57 67 85.0
branch 16 24 66.6
condition 1 3 33.3
subroutine 10 11 90.9
pod 5 5 100.0
total 89 110 80.9


line stmt bran cond sub pod time code
1             package App::Framework::Feature::Logging ;
2              
3             =head1 NAME
4              
5             App::Framework::Feature::Logging - Application logging
6              
7             =head1 SYNOPSIS
8              
9             # Include logging feature by:
10             use App::Framework '+Logging' ;
11              
12              
13             =head1 DESCRIPTION
14              
15             Logging feature that provides log file handling for applications.
16              
17             If the user specified -log command line option and specifies a valid log filename, then this module will
18             manage any logging() calls, writing the data into the specified log file.
19              
20             =cut
21              
22 3     3   3570 use strict ;
  3         4  
  3         112  
23 3     3   11 use Carp ;
  3         4  
  3         261  
24              
25             our $VERSION = "1.001" ;
26              
27              
28             #============================================================================================
29             # USES
30             #============================================================================================
31              
32 3     3   12 use App::Framework::Feature ;
  3         4  
  3         50  
33 3     3   9 use App::Framework::Base ;
  3         3  
  3         52  
34              
35 3     3   84 use App::Framework::Base::Object::DumpObj qw/prtstr_data/ ;
  3         3  
  3         1732  
36              
37             #============================================================================================
38             # OBJECT HIERARCHY
39             #============================================================================================
40             our @ISA = qw(App::Framework::Feature) ;
41              
42             #============================================================================================
43             # GLOBALS
44             #============================================================================================
45              
46             =head2 FIELDS
47              
48             The following fields should be defined either in the call to 'new()', as part of a 'set()' call, or called by their accessor method
49             (which is the same name as the field):
50              
51              
52             =over 4
53              
54             =item B - Name of log file
55              
56             Created by the object. When the application starts, if the -log option has been specified, then the filename is copied into this
57             field.
58              
59             =item B - Log file create mode
60              
61             May be 'truncate' or 'append': 'truncate' clears any previous log file contents; 'append' appends the logging to previous
62             file contents. Default is 'truncate'
63              
64             =item B - flag to echo logging
65              
66             When set, causes all logging to be echoed to STDOUT
67              
68             =back
69              
70             =cut
71              
72              
73             my %FIELDS = (
74             'logfile' => undef,
75             'mode' => 'truncate',
76             'to_stdout' => 0,
77            
78             ## private
79             '_started' => 0,
80             ) ;
81              
82              
83             =head2 ADDITIONAL COMMAND LINE OPTIONS
84              
85             This feature adds the following additional command line options to any application:
86              
87             =over 4
88              
89             =item B<-log> - Specify a log file
90              
91             If a logfile is specified at the command line, then the file is created and all logging messages get written to that file.
92             Otherwise, log messages are ignored.
93              
94             =back
95              
96             =cut
97              
98              
99             my @OPTIONS = (
100             ['log=s', 'Log file', 'Specify a log file', ],
101             ) ;
102              
103              
104             #============================================================================================
105              
106             =head2 CONSTRUCTOR
107              
108             =over 4
109              
110             =cut
111              
112             #============================================================================================
113              
114              
115             =item B< new([%args]) >
116              
117             Create a new Logging.
118              
119             The %args are specified as they would be in the B method (see L).
120              
121             =cut
122              
123             sub new
124             {
125 2     2 1 20 my ($obj, %args) = @_ ;
126              
127 2   33     50 my $class = ref($obj) || $obj ;
128              
129             # Create object
130 2         43 my $this = $class->SUPER::new(%args,
131             'feature_options' => \@OPTIONS,
132             'registered' => [qw/application_entry/],
133             ) ;
134              
135             #$this->debug(2);
136              
137            
138 2         6 return($this) ;
139             }
140              
141              
142              
143             #============================================================================================
144              
145             =back
146              
147             =head2 CLASS METHODS
148              
149             =over 4
150              
151             =cut
152              
153             #============================================================================================
154              
155              
156             #-----------------------------------------------------------------------------
157              
158             =item B< init_class([%args]) >
159              
160             Initialises the Logging object class variables.
161              
162             =cut
163              
164             sub init_class
165             {
166 2     2 1 5 my $class = shift ;
167 2         6 my (%args) = @_ ;
168              
169             # Add extra fields
170 2         24 $class->add_fields(\%FIELDS, \%args) ;
171              
172             # init class
173 2         15 $class->SUPER::init_class(%args) ;
174              
175             }
176              
177             #============================================================================================
178              
179             =back
180              
181             =head2 OBJECT METHODS
182              
183             =over 4
184              
185             =cut
186              
187             #============================================================================================
188              
189             #----------------------------------------------------------------------------
190              
191             =item B
192              
193             Called by the application framework at the start of the application.
194            
195             This method checks for the user specifying any of the options described above (see L) and handles
196             them if so.
197              
198             =cut
199              
200              
201             sub application_entry
202             {
203 2     2 1 2 my $this = shift ;
204              
205 2         10 $this->_dbg_prt(["application_entry()\n"]) ;
206              
207             ## Handle special options
208 2         39 my $app = $this->app ;
209 2         5 my %opts = $app->options() ;
210              
211 2         7 $this->_dbg_prt(["logging options=",\%opts]) ;
212              
213 2 50       6 if ($opts{'log'})
214             {
215 2         38 $this->logfile($opts{'log'}) ;
216             }
217            
218             }
219              
220              
221             #----------------------------------------------------------------------------
222              
223             =item B
224              
225             Log the argument(s) to the log file iff a log file has been specified.
226              
227             The list of arguments may be: SCALAR, ARRAY reference, HASH reference, SCALAR reference. SCALAR and SCALAR ref are printed
228             as-is without any extra newlines. ARRAY ref is printed out one entry per line with a newline added. The HASH ref is printed out
229             in the format produced by L.
230              
231              
232             =cut
233              
234             sub logging
235             {
236 15     15 1 29 my $this = shift ;
237 15         21 my (@args) = @_ ;
238              
239 15         16 my $tolog = "" ;
240 15         22 foreach my $arg (@args)
241             {
242 20 100       58 if (ref($arg) eq 'ARRAY')
    100          
    100          
    50          
243             {
244 4         11 foreach (@$arg)
245             {
246 8         13 $tolog .= "$_\n" ;
247             }
248             }
249             elsif (ref($arg) eq 'HASH')
250             {
251 1         5 $tolog .= prtstr_data($arg) . "\n" ;
252             }
253             elsif (ref($arg) eq 'SCALAR')
254             {
255 1         2 $tolog .= $$arg ;
256             }
257             elsif (!ref($arg))
258             {
259 14         18 $tolog .= $arg ;
260             }
261             else
262             {
263 0         0 $tolog .= prtstr_data($arg) . "\n" ;
264             }
265             }
266            
267             ## Log
268 15         319 my $logfile = $this->logfile ;
269 15 50       27 if ($logfile)
270             {
271             ## start if we haven't yet
272 15 100       274 if (!$this->_started)
273             {
274 2         4 $this->_start_logging() ;
275             }
276              
277 15 50       429 open my $fh, ">>$logfile" or $this->throw_fatal("Error: unable to append to logfile \"$logfile\" : $!") ;
278 15         78 print $fh $tolog ;
279 15         270 close $fh ;
280             }
281              
282             ## Echo
283 15 50       353 if ($this->to_stdout)
284             {
285 0         0 print $tolog ;
286             }
287              
288 15         30 return($this) ;
289             }
290            
291             #----------------------------------------------------------------------------
292              
293             =item B
294              
295             Same as L but echoes output to STDOUT.
296              
297             =cut
298              
299             sub echo_logging
300             {
301 0     0 1 0 my $this = shift ;
302 0         0 my (@args) = @_ ;
303            
304             # Temporarily force echoing to STDOUT on, then do logging
305 0         0 my $to_stdout = $this->to_stdout ;
306 0         0 $this->to_stdout(1) ;
307 0         0 $this->logging(@args) ;
308 0         0 $this->to_stdout($to_stdout) ;
309              
310 0         0 return($this) ;
311             }
312            
313             #----------------------------------------------------------------------------
314              
315             =item B< Logging([%args]) >
316              
317             Alias to L
318              
319             =cut
320              
321             *Logging = \&logging ;
322              
323              
324              
325             # ============================================================================================
326             # PRIVATE METHODS
327             # ============================================================================================
328              
329             #----------------------------------------------------------------------------
330             #
331             #=item B<_start_logging()>
332             #
333             #Create/append log file
334             #
335             #=cut
336             #
337             sub _start_logging
338             {
339 2     2   1 my $this = shift ;
340              
341 2         32 my $logfile = $this->logfile() ;
342 2 50       4 if ($logfile)
343             {
344 2         3 my $mode = ">" ;
345 2 50       33 if ($this->mode eq 'append')
346             {
347 0         0 $mode = ">>" ;
348             }
349            
350 2 50       236 open my $fh, "$mode$logfile" or $this->throw_fatal("Unable to write to logfile \"$logfile\" : $!") ;
351 2         13 close $fh ;
352            
353             ## set flag
354 2         48 $this->_started(1) ;
355             }
356             }
357            
358              
359              
360             # ============================================================================================
361             # END OF PACKAGE
362              
363             =back
364              
365             =head1 DIAGNOSTICS
366              
367             Setting the debug flag to level 1 prints out (to STDOUT) some debug messages, setting it to level 2 prints out more verbose messages.
368              
369             =head1 AUTHOR
370              
371             Steve Price C<< >>
372              
373             =head1 BUGS
374              
375             None that I know of!
376              
377             =cut
378              
379              
380             1;
381              
382             __END__