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   1479 use strict;
  17         42  
  17         399  
36 17     17   74 use warnings;
  17         29  
  17         348  
37 17     17   215 use 5.012;
  17         53  
38              
39             # IMPORTANT: this module must not depend on any other CELL modules
40             # except possibly App::CELL::Util
41 17     17   8499 use Data::Dumper;
  17         96454  
  17         1042  
42 17     17   110 use File::Spec;
  17         27  
  17         311  
43 17     17   6286 use Log::Any;
  17         161524  
  17         74  
44 17     17   692 use Scalar::Util;
  17         30  
  17         1477  
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   119 use Exporter qw( import );
  17         34  
  17         18391  
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 7 my ( $self, @ARGS ) = @_;
164 2 50       7 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 16 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 807 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 1546 my ( $self, %ARGS ) = @_;
227              
228             # process 'ident'
229 18 100       82 if ( defined( $ARGS{ident} ) ) {
230 15 50 33     131 if ( $ARGS{ident} eq $ident and $ident ne 'CELLtest' ) {
231 0         0 $log->info( "Logging already configured", cell => 1 );
232             } else {
233 15         39 $ident = $ARGS{ident};
234 15         114 $log_any_obj = Log::Any->get_logger(category => $ident);
235             }
236             } else {
237 3         8 $ident = 'CELLtest';
238 3         16 $log_any_obj = Log::Any->get_logger(category => $ident);
239             }
240              
241             # process 'debug_mode' argument
242 18 100       31439 if ( exists( $ARGS{debug_mode} ) ) {
243 8 100       29 $debug_mode = 1 if $ARGS{debug_mode};
244 8 100       21 $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       61 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         50 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   10019 my ( $class, $msg_text, @ARGS ) = @_;
279 956         1324 my $method = $AUTOLOAD;
280 956         3314 $method =~ s/.*:://;
281              
282             # if method is not in permitted_levels, pass through to Log::Any
283             # directly
284 956 100       1741 if ( not grep { $_ =~ m/$method/i } @permitted_levels ) {
  14340         25426  
285 19         51 return $log_any_obj->$method( $msg_text, @ARGS );
286             }
287              
288             # we are logging a message
289 937         1172 my %ARGS;
290 937 50       2439 %ARGS = @ARGS if @ARGS % 2 == 0;
291 937         1831 my ( $file, $line );
292 937         0 my ( $level, $text );
293 937         1348 my $method_uc = uc $method;
294 937 100 100     2714 if ( $method_uc eq 'OK' or $method_uc eq 'NOT_OK' ) {
295 2         3 $level = $method_uc;
296 2         3 $method_uc = 'INFO';
297 2         2 $method = 'info';
298             } else {
299 935         1220 $level = $method_uc;
300             }
301 937         1290 my $method_lc = lc $method;
302              
303             # determine what caller info will be displayed, if any
304 937 100       1337 if ( %ARGS ) {
305 824 100       1444 if ( $ARGS{caller} ) {
    100          
306 59         78 ( undef, $file, $line ) = @{ $ARGS{caller} };
  59         146  
307             } elsif ( $ARGS{suppress_caller} ) {
308 108         170 ( $file, $line ) = ( '', '' );
309             } else {
310 657         1612 ( undef, $file, $line ) = caller;
311             }
312             } else {
313 113         303 ( 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     2732 if ( $ARGS{'cell'} and ( $method_lc eq 'debug' or $method_lc eq 'trace') ) {
      100        
319 723 50       2118 return unless $ENV{'CELL_DEBUG_MODE'};
320             }
321              
322 214 50       898 $log->init( ident => $ident ) if not $log_any_obj;
323 214 50       339 die "No Log::Any object!" if not $log_any_obj;
324 214 100 100     693 return if not $debug_mode and ( $method_lc eq 'debug' or $method_lc eq 'trace' );
      100        
325 179 50       293 if ( not $msg_text ) {
326 0         0 $msg_text = ""
327             }
328 179         499 $log_any_obj->$method_lc( _assemble_log_message( "$level: $msg_text", $file, $line ) );
329 179         1592 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 115 my ( $self, $status_obj, $cell ) = @_;
341 59         101 my ( $level, $code, $text, $caller, %ARGS );
342 59         114 $level = $status_obj->level;
343 59         128 $code = $status_obj->code;
344 59         126 $text = $status_obj->text;
345 59         118 $caller = $status_obj->caller;
346 59 50       153 $ARGS{caller} = $caller if $caller;
347 59 100       129 $ARGS{cell} = $cell if $cell;
348 59 100       110 if ( $code ne $text ) {
349 38         98 $text = "($code) $text"
350             }
351 59 50       127 $text = "" if not $text;
352             #( $level, $text ) = _sanitize_level( $level, $text );
353              
354 59 50       148 $log->init( ident => $ident ) if not $log_any_obj;
355 59         413 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   330 my ( $message, $file, $line ) = @_;
388              
389 179 100 100     1128 if ( $file and File::Spec->file_name_is_absolute( $file ) ) {
390 65         696 ( undef, undef, $file ) = File::Spec->splitpath( $file );
391             }
392              
393 179 100 66     1245 return "$message at $file line $line" if $show_caller and $file;
394              
395 12         72 return $message;
396             }
397              
398             1;