File Coverage

blib/lib/App/CELL/Log.pm
Criterion Covered Total %
statement 89 106 83.9
branch 41 62 66.1
condition 21 24 87.5
subroutine 15 18 83.3
pod 6 6 100.0
total 172 216 79.6


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014-2020, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32              
33             package App::CELL::Log;
34              
35 17     17   1729 use strict;
  17         43  
  17         435  
36 17     17   73 use warnings;
  17         33  
  17         352  
37 17     17   225 use 5.012;
  17         51  
38              
39             # IMPORTANT: this module must not depend on any other CELL modules
40             # except possibly App::CELL::Util
41 17     17   9134 use Data::Dumper;
  17         103540  
  17         1062  
42 17     17   122 use File::Spec;
  17         32  
  17         334  
43 17     17   6731 use Log::Any;
  17         172440  
  17         82  
44 17     17   710 use Scalar::Util;
  17         31  
  17         1432  
45              
46              
47              
48             =head1 NAME
49              
50             App::CELL::Log - the Logging part of CELL
51              
52              
53              
54             =head1 SYNOPSIS
55              
56             use App::CELL::Log qw( $log );
57              
58             # set up logging for application FooBar -- need only be done once
59             $log->init( ident => 'FooBar' );
60              
61             # do not suppess 'trace' and 'debug' messages
62             $log->init( debug_mode => 1 );
63              
64             # do not append filename and line number of caller
65             $log->init( show_caller => 0 );
66              
67             # log messages at different log levels
68             my $level = 'warn' # can be any of the levels provided by Log::Any
69             $log->$level ( "Foobar log message" );
70              
71             # the following App::CELL-specific levels are supported as well
72             $log->ok ( "Info-level message prefixed with 'OK: '");
73             $log->not_ok ( "Info-level message prefixed with 'NOT_OK: '");
74              
75             # by default, the caller's filename and line number are appended
76             # to suppress this for an individual log message:
77             $log->debug ( "Debug-level message", suppress_caller => 1 );
78              
79             # Log a status object (happens automatically when object is
80             # constructed)
81             $log->status_obj( $status_obj );
82              
83             # Log a message object
84             $log->message_obj( $message_obj );
85              
86              
87              
88             =head1 EXPORTS
89              
90             This module provides the following exports:
91              
92             =over
93              
94             =item C<$log> - App::CELL::Log singleton
95              
96             =back
97              
98             =cut
99              
100 17     17   102 use Exporter qw( import );
  17         393  
  17         19870  
101             our @EXPORT_OK = qw( $log );
102              
103              
104              
105             =head1 PACKAGE VARIABLES
106              
107             =over
108              
109             =item C<$ident> - the name of our application
110              
111             =item C<$show_caller> - boolean value, determines if caller information is
112             displayed in log messages
113              
114             =item C<$debug_mode> - boolean value, determines if we display debug
115             messages
116              
117             =item C<$log> - App::CELL::Log singleton object
118              
119             =item C<$log_any_obj> - Log::Any singleton object
120              
121             =item C<@permitted_levels> - list of permissible log levels
122              
123             =back
124              
125             =cut
126              
127             our $debug_mode = 0;
128             our $ident = 'CELLtest';
129             our $show_caller = 1;
130             our $log = bless {}, __PACKAGE__;
131             our $log_any_obj;
132             our @permitted_levels = qw( OK NOT_OK TRACE DEBUG INFO INFORM NOTICE
133             WARN WARNING ERR ERROR CRIT CRITICAL FATAL EMERGENCY );
134             our $AUTOLOAD;
135              
136              
137              
138             =head1 DESCRIPTION
139              
140             App::CELL's logs using L. This C module exists
141             to: (1) provide documentation, (2) store the logging category (C<$ident>),
142             (3) store the L log object, (4) provide convenience functions for
143             logging 'OK' and 'NOT_OK' statuses.
144              
145              
146              
147             =head1 METHODS
148              
149              
150             =head2 debug_mode
151              
152             If argument provided, set the $debug_mode package variable.
153             If no argument, simply return the current debug-mode setting.
154             Examples:
155              
156             $log->debug_mode(0); # turn debug mode off
157             $log->debug_mode(1); # turn debug mode on
158             print "Debug mode is on\n" if $log->debug_mode;
159              
160             =cut
161              
162             sub debug_mode {
163 2     2 1 11 my ( $self, @ARGS ) = @_;
164 2 50       9 return $debug_mode = $ARGS[0] if @ARGS;
165 0         0 return $debug_mode;
166             }
167              
168              
169             =head2 ident
170              
171             Set the $ident package variable and the Log::Any category
172              
173             =cut
174              
175             sub ident {
176 0     0 1 0 my $self = shift;
177 0         0 $ident = shift;
178 0         0 return $log_any_obj = Log::Any->get_logger(category => $ident);
179             }
180              
181              
182             =head2 show_caller
183              
184             Set the $show_caller package variable
185              
186             =cut
187              
188 2     2 1 4 sub show_caller { return $show_caller = $_[1]; }
189              
190              
191             =head2 permitted_levels
192              
193             Access the C<@permitted_levels> package variable.
194              
195             =cut
196              
197 206     206 1 845 sub permitted_levels { return @permitted_levels };
198              
199              
200             =head2 init
201              
202             Initializes (or reconfigures) the logger. Although in most cases folks will
203             want to call this in order to set C, it is not required for logging
204             to work. See L for instructions on how to log with
205             L.
206              
207             Takes PARAMHASH as argument. Recognized parameters:
208              
209             =over
210              
211             =item C -- (i.e., category) string, e.g. 'FooBar' for
212             the FooBar application, or 'CELLtest' if none given
213              
214             =item C -- sets the C<$show_caller> package variable (see
215             above)
216              
217             =item C -- sets the C<$debug_mode> package variable (see above)
218              
219             =back
220              
221             Always returns 1.
222              
223             =cut
224              
225             sub init {
226 18     18 1 1750 my ( $self, %ARGS ) = @_;
227              
228             # process 'ident'
229 18 100       84 if ( defined( $ARGS{ident} ) ) {
230 15 50 33     136 if ( $ARGS{ident} eq $ident and $ident ne 'CELLtest' ) {
231 0         0 $log->info( "Logging already configured", cell => 1 );
232             } else {
233 15         45 $ident = $ARGS{ident};
234 15         126 $log_any_obj = Log::Any->get_logger(category => $ident);
235             }
236             } else {
237 3         9 $ident = 'CELLtest';
238 3         18 $log_any_obj = Log::Any->get_logger(category => $ident);
239             }
240              
241             # process 'debug_mode' argument
242 18 100       34678 if ( exists( $ARGS{debug_mode} ) ) {
243 8 100       28 $debug_mode = 1 if $ARGS{debug_mode};
244 8 100       24 $debug_mode = 0 if not $ARGS{debug_mode};
245             }
246             #$log->info( "debug_mode is $debug_mode", cell => 1 );
247            
248             # process 'show_caller'
249 18 50       70 if ( exists( $ARGS{show_caller} ) ) {
250 0 0       0 $show_caller = 1 if $ARGS{show_caller};
251 0 0       0 $show_caller = 0 if not $ARGS{show_caller};
252             }
253              
254 18         61 return 1;
255             }
256              
257              
258             =head2 DESTROY
259              
260             For some reason, Perl 5.012 seems to want a DESTROY method
261              
262             =cut
263              
264             sub DESTROY {
265 0     0   0 my $self = shift;
266 0 0       0 $self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
267             }
268              
269              
270             =head2 AUTOLOAD
271              
272             Call Log::Any methods after some pre-processing
273              
274             =cut
275              
276             sub AUTOLOAD {
277            
278 956     956   11734 my ( $class, $msg_text, @ARGS ) = @_;
279 956         1328 my $method = $AUTOLOAD;
280 956         3456 $method =~ s/.*:://;
281              
282             # if method is not in permitted_levels, pass through to Log::Any
283             # directly
284 956 100       1867 if ( not grep { $_ =~ m/$method/i } @permitted_levels ) {
  14340         27483  
285 19         66 return $log_any_obj->$method( $msg_text, @ARGS );
286             }
287              
288             # we are logging a message
289 937         1214 my %ARGS;
290 937 50       2567 %ARGS = @ARGS if @ARGS % 2 == 0;
291 937         1867 my ( $file, $line );
292 937         0 my ( $level, $text );
293 937         1435 my $method_uc = uc $method;
294 937 100 100     2961 if ( $method_uc eq 'OK' or $method_uc eq 'NOT_OK' ) {
295 2         5 $level = $method_uc;
296 2         4 $method_uc = 'INFO';
297 2         4 $method = 'info';
298             } else {
299 935         1294 $level = $method_uc;
300             }
301 937         1360 my $method_lc = lc $method;
302              
303             # determine what caller info will be displayed, if any
304 937 100       1383 if ( %ARGS ) {
305 824 100       1616 if ( $ARGS{caller} ) {
    100          
306 59         90 ( undef, $file, $line ) = @{ $ARGS{caller} };
  59         159  
307             } elsif ( $ARGS{suppress_caller} ) {
308 108         194 ( $file, $line ) = ( '', '' );
309             } else {
310 657         1664 ( undef, $file, $line ) = caller;
311             }
312             } else {
313 113         334 ( undef, $file, $line ) = caller;
314             }
315              
316             # if this is a CELL internal debug message, continue only if
317             # the CELL_DEBUG_MODE environment variable exists and is true
318 937 100 100     2944 if ( $ARGS{'cell'} and ( $method_lc eq 'debug' or $method_lc eq 'trace') ) {
      100        
319 723 50       2243 return unless $ENV{'CELL_DEBUG_MODE'};
320             }
321              
322 214 50       913 $log->init( ident => $ident ) if not $log_any_obj;
323 214 50       368 die "No Log::Any object!" if not $log_any_obj;
324 214 100 100     719 return if not $debug_mode and ( $method_lc eq 'debug' or $method_lc eq 'trace' );
      100        
325 179 50       304 if ( not $msg_text ) {
326 0         0 $msg_text = ""
327             }
328 179         544 $log_any_obj->$method_lc( _assemble_log_message( "$level: $msg_text", $file, $line ) );
329 179         1865 return;
330             }
331              
332              
333             =head2 status_obj
334              
335             Take a status object and log it.
336              
337             =cut
338              
339             sub status_obj {
340 59     59 1 130 my ( $self, $status_obj, $cell ) = @_;
341 59         86 my ( $level, $code, $text, $caller, %ARGS );
342 59         140 $level = $status_obj->level;
343 59         144 $code = $status_obj->code;
344 59         158 $text = $status_obj->text;
345 59         128 $caller = $status_obj->caller;
346 59 50       150 $ARGS{caller} = $caller if $caller;
347 59 100       130 $ARGS{cell} = $cell if $cell;
348 59 100       129 if ( $code ne $text ) {
349 38         111 $text = "($code) $text"
350             }
351 59 50       137 $text = "" if not $text;
352             #( $level, $text ) = _sanitize_level( $level, $text );
353              
354 59 50       151 $log->init( ident => $ident ) if not $log_any_obj;
355 59         423 return $log->$level( $text, %ARGS );
356             }
357              
358              
359             #=head2 msg
360             #
361             #Take a message object and log it.
362             #
363             #=cut
364             #
365             #sub msg {
366             # my ( $self, $msgobj, @ARGS ) = @_;
367             # return if not blessed( $msgobj );
368             # $log->init( ident => $ident ) if not $log_any_obj;
369             # my $level = $msgobj->level;
370             # my $text = $msgobj->text;
371             #}
372              
373              
374             sub _sanitize_level {
375 0     0   0 my ( $level, $msg_text ) = @_;
376 0 0       0 if ( $level eq 'OK' ) {
    0          
377 0         0 $level = 'INFO';
378 0         0 $msg_text = "OK: " . $msg_text;
379             } elsif ( $level eq 'NOT_OK' ) {
380 0         0 $level = 'INFO';
381 0         0 $msg_text = "NOT_OK: " . $msg_text;
382             }
383 0         0 return ( lc $level, $msg_text );
384             }
385              
386             sub _assemble_log_message {
387 179     179   345 my ( $message, $file, $line ) = @_;
388              
389 179 100 100     1157 if ( $file and File::Spec->file_name_is_absolute( $file ) ) {
390 65         740 ( undef, undef, $file ) = File::Spec->splitpath( $file );
391             }
392              
393 179 100 66     1363 return "$message at $file line $line" if $show_caller and $file;
394              
395 12         53 return $message;
396             }
397              
398             1;