File Coverage

blib/lib/Bio/NEXUS/Util/Logger.pm
Criterion Covered Total %
statement 48 78 61.5
branch 14 34 41.1
condition 1 8 12.5
subroutine 9 13 69.2
pod 5 5 100.0
total 77 138 55.8


line stmt bran cond sub pod time code
1             package Bio::NEXUS::Util::Logger;
2 34     34   305 use strict;
  34         94  
  34         1117  
3             #use warnings;
4 34     34   183 use File::Spec;
  34         62  
  34         822  
5 34     34   199 use Bio::NEXUS::Util::Exceptions 'throw';
  34         62  
  34         2525  
6 34     34   300 use Config;
  34         58  
  34         1533  
7 34     34   186 use vars qw($volume $class_dir $file $VERBOSE $AUTOLOAD);
  34         70  
  34         8287  
8              
9             BEGIN {
10 34     34   93 my $class_file = __FILE__;
11 34         782 ( $volume, $class_dir, $file ) = File::Spec->splitpath( $class_file );
12 34         37407 $class_dir =~ s/Bio.NEXUS.Util.?$//;
13             #printf "[ %s starting, will use PREFIX=%s where applicable ]\n", __PACKAGE__, $class_dir;
14             }
15              
16             {
17             my $self;
18             my %VERBOSE;
19             my %LEVEL;
20             my @listeners = (
21             sub {
22             my $msg = shift;
23             print STDERR $msg;
24             }
25             );
26             @LEVEL{ qw(FATAL ERROR WARN INFO DEBUG) } = ( 0 .. 4 );
27             $VERBOSE = $LEVEL{'WARN'};
28            
29             sub new {
30 715     715 1 1996 my $package = shift;
31 715         6274 my %args;
32            
33             # singleton object
34 715 100       3292 if ( not $self ) {
35 34         140 $self = \$package;
36 34         190 bless $self, $package;
37             }
38            
39             # process args
40 715 100       2545 if (@_) {
41            
42             # create hash
43 1         3 eval { %args = @_ };
  1         5  
44 1 50       5 if ($@) {
45 0         0 throw 'OddHash' => $@;
46             }
47             }
48            
49             # set level
50 715 100       2530 if ( defined $args{'-level'} ) {
51            
52             # check validity
53 1 50 25     12 if ( $args{'-level'} > $LEVEL{'DEBUG'} xor $args{'-level'} < $LEVEL{'FATAL'} ) {
54 0         0 throw 'OutOfBounds' => "'-level' can be between $LEVEL{'FATAL'} and $LEVEL{'DEBUG'}, $args{'-level'} is outside that range";
55             }
56             else {
57 1 50       3 if ( $args{'-class'} ) {
58 0         0 $VERBOSE{$args{'-class'}} = $args{'-level'};
59             }
60             else {
61 1         3 $VERBOSE = $args{'-level'};
62             }
63             }
64             }
65            
66             # done
67 715         2878 return $self;
68             }
69            
70             sub set_listeners {
71 0     0 1 0 my ( $self, @args ) = @_;
72 0         0 for my $arg ( @args ) {
73 0 0       0 if ( UNIVERSAL::isa( $arg, 'CODE' ) ) {
74 0         0 push @listeners, $arg;
75             }
76             else {
77 0         0 throw 'BadArgs' => "$arg not a CODE reference";
78             }
79             }
80 0         0 return $self;
81             }
82            
83             sub log {
84 2626     2626 1 4356 my ( $self, $level, $msg ) = @_;
85 2626         17826 my ( $package, $file1up, $line1up, $subroutine ) = caller(2);
86 2626         11943 my ( $pack0up, $filename, $line, $sub0up ) = caller(1);
87 2626 50       6794 my $verbosity = exists $VERBOSE{$pack0up} ? $VERBOSE{$pack0up} : $VERBOSE;
88 2626 100       7875 if ( $verbosity >= $LEVEL{$level} ) {
89 11         15 my $log_string;
90 11 50       111 if ( $filename =~ s/\Q$class_dir\E// ) {
91 11         76 $log_string = sprintf( "%s %s [\$PREFIX/%s, %s] - %s\n",
92             $level, $subroutine, $filename, $line, $msg );
93             }
94             else {
95 0         0 $log_string = sprintf( "%s %s [%s, %s] - %s\n",
96             $level, $subroutine, $filename, $line, $msg );
97             }
98 11         49 $_->( $log_string ) for @listeners;
99             }
100 2626         9475 return $self;
101             }
102            
103             sub AUTOLOAD {
104 2626     2626   4760 my ( $self, $msg ) = @_;
105 2626         4132 my $method = $AUTOLOAD;
106 2626         17428 $method =~ s/.*://;
107 2626         4983 $method = uc $method;
108 2626 50       8361 if ( exists $LEVEL{$method} ) {
109 2626         6650 $self->log( $method, $msg );
110             }
111             }
112            
113             sub PREFIX {
114 0     0 1   my ( $self, $prefix ) = @_;
115 0 0         $class_dir = $prefix if $prefix;
116 0           return $class_dir;
117             }
118            
119             sub VERBOSE {
120 0     0 1   my $self = shift;
121 0 0         if (@_) {
122 0           my %opt;
123 0           eval { %opt = @_ };
  0            
124 0 0         if ($@) {
125 0           throw 'OddHash' => $@;
126             }
127 0 0         if ( defined $opt{'-level'} ) {
128            
129             # check validity
130 0 0 0       if ( $opt{'-level'} > $LEVEL{'DEBUG'} xor $opt{'-level'} < $LEVEL{'FATAL'} ) {
131 0           throw 'OutOfBounds' => "'-level' can be between $LEVEL{'FATAL'} and $LEVEL{'DEBUG'}, not $opt{'-level'}";
132             }
133            
134 0 0         if ( $opt{'-class'} ) {
135 0           $VERBOSE{ $opt{'-class'} } = $opt{'-level'};
136 0           $self->info("Changed verbosity for $opt{'-class'} to $opt{'-level'}");
137             }
138             else {
139 0           $VERBOSE = $opt{'-level'};
140 0           $self->info("Changed global verbosity to $VERBOSE");
141             }
142             }
143             }
144 0           return $VERBOSE;
145             }
146            
147 0     0     sub DESTROY {} # empty destructor so we don't go up inheritance tree at the end
148            
149             }
150              
151             1;
152              
153             =head1 NAME
154              
155             Bio::NEXUS::Util::Logger - Logging for Bio::NEXUS.
156              
157             =head1 SYNOPSIS
158              
159             use Bio::NEXUS::Util::Logger;
160            
161             # can instantiate as (singleton) object, in this case telling it that only
162             # messages from Bio::NEXUS::Forest with log level >= 3 are displayed...
163             my $logger->new( -level => 3, -class => 'Bio::NEXUS::Matrix' );
164            
165            
166             #...or use static...
167             Bio::NEXUS::Util::Logger->info("Log level too low for this to be printed");
168             Bio::NEXUS::Matrix->VERBOSE( -level => 2 );
169             Bio::NEXUS::Util::Logger->info("Not any more, now we're talking");
170            
171              
172             =head1 DESCRIPTION
173              
174             This class defines a logger, a utility object for logging messages.
175             The other objects in Bio::NEXUS use this logger to give detailed feedback
176             about what they are doing at per-class, user-configurable log levels
177             (debug, info, warn, error and fatal). You can tell the logger for each
178             class how verbose to be. The least verbose is level 0, in which case only
179             'fatal' messages are shown. The most verbose level, 4, shows debugging
180             messages, include from internal methods (i.e. ones that start with
181             underscores, and special 'ALLCAPS' perl methods like DESTROY or TIEARRAY).
182             For example, to monitor what the root class is
183             doing, you would say:
184              
185             $logger->( -class => 'Bio::NEXUS', -level => 4 )
186              
187             To define global verbosity you can omit the -class argument.
188              
189             =head1 METHODS
190              
191             =head2 CONSTRUCTOR
192              
193             =over
194              
195             =item new()
196              
197             Constructor for Logger.
198              
199             Type : Constructor
200             Title : new
201             Usage : my $logger = Bio::NEXUS::Util::Logger->new;
202             Function: Instantiates a logger
203             Returns : a Bio::NEXUS::Util::Logger object
204             Args : -verbose => verbosity, 0 .. 4 (optional)
205             -package => a package for which to set verbosity (optional)
206              
207             =back
208              
209             head2 LOGGING METHODS
210              
211             =over
212              
213             =item log()
214              
215             Prints argument debugging message, depending on verbosity.
216              
217             Type : logging method
218             Title : log
219             Usage : $logger->log( "WARN", "warning message" );
220             Function: prints logging message, depending on verbosity
221             Returns : invocant
222             Args : message log level, logging message
223              
224             =item debug()
225              
226             Prints argument debugging message, depending on verbosity.
227              
228             Type : logging method
229             Title : debug
230             Usage : $logger->debug( "debugging message" );
231             Function: prints debugging message, depending on verbosity
232             Returns : invocant
233             Args : logging message
234              
235             =item info()
236              
237             Prints argument informational message, depending on verbosity.
238              
239             Type : logging method
240             Title : info
241             Usage : $logger->info( "info message" );
242             Function: prints info message, depending on verbosity
243             Returns : invocant
244             Args : logging message
245              
246             =item warn()
247              
248             Prints argument warning message, depending on verbosity.
249              
250             Type : logging method
251             Title : warn
252             Usage : $logger->warn( "warning message" );
253             Function: prints warning message, depending on verbosity
254             Returns : invocant
255             Args : logging message
256              
257             =item error()
258              
259             Prints argument error message, depending on verbosity.
260              
261             Type : logging method
262             Title : error
263             Usage : $logger->error( "error message" );
264             Function: prints error message, depending on verbosity
265             Returns : invocant
266             Args : logging message
267              
268             =item fatal()
269              
270             Prints argument fatal message, depending on verbosity.
271              
272             Type : logging method
273             Title : fatal
274             Usage : $logger->fatal( "fatal message" );
275             Function: prints fatal message, depending on verbosity
276             Returns : invocant
277             Args : logging message
278              
279             =item set_listeners()
280              
281             Adds listeners to send log messages to.
282              
283             Type : Mutator
284             Title : set_listeners()
285             Usage : Bio::NEXUS::Util::Logger->set_listeners( sub { warn shift } )
286             Function: Sets additional listeners to log to (e.g. a file)
287             Returns : invocant
288             Args : One or more code references
289             Comments: On execution of the listeners, the first (and only) argument
290             is the log message.
291            
292             =item PREFIX()
293              
294             Getter and setter of path prefix to strip from source file paths in messages.
295              
296             Type : Mutator/Accessor
297             Title : PREFIX()
298             Usage : Bio::NEXUS::Util::Logger->PREFIX( '/path/to/Bio/NEXUS' )
299             Function: Sets/gets $PREFIX
300             Returns : Verbose level
301             Args : Optional: a path
302             Comments:
303              
304             =item VERBOSE()
305              
306             Setter for the verbose level. This comes in five levels: 0 = only
307             fatal messages (though, when something fatal happens, you'll most likely get
308             an exception object), 1 = errors (hopefully recoverable), 2 = warnings
309             (recoverable), 3 = info (useful diagnostics), 4 = debug (almost every method call)
310              
311             Type : Mutator
312             Title : VERBOSE()
313             Usage : Bio::NEXUS::Util::Logger->VERBOSE( -level => $level )
314             Function: Sets/gets verbose level
315             Returns : Verbose level
316             Args : 0 <= $level && $level <= 4
317             Comments:
318              
319             =back
320              
321             =head1 REVISION
322              
323             $Id: Logger.pm,v 1.3 2010/09/22 20:05:51 astoltzfus Exp $
324              
325             =cut