comparison variant_effect_predictor/Bio/EnsEMBL/Utils/Logger.pm @ 0:1f6dce3d34e0

Uploaded
author mahtabm
date Thu, 11 Apr 2013 02:01:53 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1f6dce3d34e0
1 =head1 LICENSE
2
3 Copyright (c) 1999-2012 The European Bioinformatics Institute and
4 Genome Research Limited. All rights reserved.
5
6 This software is distributed under a modified Apache license.
7 For license details, please see
8
9 http://www.ensembl.org/info/about/code_licence.html
10
11 =head1 CONTACT
12
13 Please email comments or questions to the public Ensembl
14 developers list at <dev@ensembl.org>.
15
16 Questions may also be sent to the Ensembl help desk at
17 <helpdesk@ensembl.org>.
18
19 =cut
20
21 =head1 NAME
22
23 Bio::EnsEMBL::Utils::ConversionSupport - Utility module for Vega release and
24 schema conversion scripts
25
26 =head1 SYNOPSIS
27
28 my $serverroot = '/path/to/ensembl';
29 my $suport = new Bio::EnsEMBL::Utils::ConversionSupport($serverroot);
30
31 # parse common options
32 $support->parse_common_options;
33
34 # parse extra options for your script
35 $support->parse_extra_options( 'string_opt=s', 'numeric_opt=n' );
36
37 # ask user if he wants to run script with these parameters
38 $support->confirm_params;
39
40 # see individual method documentation for more stuff
41
42 =head1 DESCRIPTION
43
44 This module is a collection of common methods and provides helper
45 functions for the Vega release and schema conversion scripts. Amongst
46 others, it reads options from a config file, parses commandline options
47 and does logging.
48
49 =head1 METHODS
50
51 =cut
52
53 package Bio::EnsEMBL::Utils::Logger;
54
55 use strict;
56 use warnings;
57 no warnings 'uninitialized';
58
59 use FindBin qw($Bin $Script);
60 use POSIX qw(strftime);
61 use Bio::EnsEMBL::Utils::Argument qw(rearrange);
62 use Bio::EnsEMBL::Utils::Exception qw(throw);
63 use Bio::EnsEMBL::Utils::ScriptUtils qw(parse_bytes);
64
65 my %level_defs = (
66 'error' => 1,
67 'warn' => 2,
68 'warning' => 2,
69 'info' => 3,
70 'debug' => 4,
71 'verbose' => 4,
72 );
73
74 my @reverse_level_defs = (undef, qw(error warning info debug));
75
76 =head2 new
77
78 Arg[1] : String $serverroot - root directory of your ensembl sandbox
79 Example : my $support = new Bio::EnsEMBL::Utils::ConversionSupport(
80 '/path/to/ensembl');
81 Description : constructor
82 Return type : Bio::EnsEMBL::Utils::ConversionSupport object
83 Exceptions : thrown on invalid loglevel
84 Caller : general
85
86 =cut
87
88 sub new {
89 my $caller = shift;
90 my $class = ref($caller) || $caller;
91
92 my ($logfile, $logauto, $logautobase, $logautoid, $logpath, $logappend,
93 $loglevel, $is_component) = rearrange(
94 ['LOGFILE', 'LOGAUTO', 'LOGAUTOBASE', 'LOGAUTOID', 'LOGPATH', 'LOGAPPEND',
95 'LOGLEVEL', 'IS_COMPONENT'], @_);
96
97 my $self = { '_warnings' => 0, };
98 bless ($self, $class);
99
100 # initialise
101 $self->logfile($logfile);
102 $self->logpath($logpath);
103 $self->logappend($logappend);
104 $self->is_component($is_component);
105
106 # automatic logfile creation
107 $self->logauto($logauto);
108 $logautoid ||= strftime("%Y%m%d-%H%M%S", localtime);
109 $self->log_auto_id($logautoid);
110 $self->create_auto_logfile($logautobase);
111
112 $loglevel ||= 'info';
113 if ($loglevel =~ /^\d+$/ and $loglevel > 0 and $loglevel < 5) {
114 $self->{'loglevel'} = $loglevel;
115 } elsif ($level_defs{lc($loglevel)}) {
116 $self->{'loglevel'} = $level_defs{lc($loglevel)};
117 } else {
118 throw('Unknown loglevel: $loglevel.');
119 }
120
121 return $self;
122 }
123
124
125 =head2 log_generic
126
127 Arg[1] : String $txt - the text to log
128 Arg[2] : Int $indent - indentation level for log message
129 Example : my $log = $support->log_filehandle;
130 $support->log('Log foo.\n', 1);
131 Description : Logs a message to the filehandle initialised by calling
132 $self->log_filehandle(). You can supply an indentation level
133 to get nice hierarchical log messages.
134 Return type : true on success
135 Exceptions : thrown when no filehandle can be obtained
136 Caller : general
137
138 =cut
139
140 sub log_generic {
141 my ($self, $txt, $indent, $stamped) = @_;
142
143 $indent ||= 0;
144 my $fh = $self->log_filehandle;
145
146 # append timestamp and memory usage to log text if requested
147 if ($stamped) {
148 $txt =~ s/^(\n*)(.*)(\n*)$/$2/;
149 $txt = sprintf("%-60s%20s", $txt, $self->time_and_mem);
150 $txt = $1.$txt.$3;
151 }
152
153 # strip off leading linebreaks so that indenting doesn't break
154 $txt =~ s/^(\n*)//;
155
156 # indent
157 $txt = $1." "x$indent . $txt;
158
159 print $fh "$txt";
160
161 return(1);
162 }
163
164
165 =head2 error
166
167 Arg[1] : String $txt - the error text to log
168 Arg[2] : Int $indent - indentation level for log message
169 Example : my $log = $support->log_filehandle;
170 $support->log_error('Log foo.\n', 1);
171 Description : Logs a message via $self->log and exits the script.
172 Return type : none
173 Exceptions : none
174 Caller : general
175
176 =cut
177
178 sub error {
179 my ($self, $txt, $indent, $stamped) = @_;
180
181 return(0) unless ($self->{'loglevel'} >= 1);
182
183 $txt = "ERROR: ".$txt;
184 $self->log_generic($txt, $indent, $stamped);
185
186 $self->log_generic("\nExiting prematurely.\n\n");
187 $self->log_generic("Runtime: ".$self->runtime." ".$self->date_and_mem."\n\n");
188
189 exit(1);
190 }
191
192
193 =head2 warning
194
195 Arg[1] : String $txt - the warning text to log
196 Arg[2] : Int $indent - indentation level for log message
197 Example : my $log = $support->log_filehandle;
198 $support->log_warning('Log foo.\n', 1);
199 Description : Logs a message via $self->log and increases the warning counter.
200 Return type : true on success
201 Exceptions : none
202 Caller : general
203
204 =cut
205
206 sub warning {
207 my ($self, $txt, $indent, $stamped) = @_;
208
209 return(0) unless ($self->{'loglevel'} >= 2);
210
211 $txt = "WARNING: " . $txt;
212 $self->log_generic($txt, $indent, $stamped);
213
214 $self->{'_warnings'}++;
215
216 return(1);
217 }
218
219
220 sub info {
221 my ($self, $txt, $indent, $stamped) = @_;
222
223 return(0) unless ($self->{'loglevel'} >= 3);
224
225 $self->log_generic($txt, $indent, $stamped);
226 return(1);
227 }
228
229
230 =head2 debug
231
232 Arg[1] : String $txt - the warning text to log
233 Arg[2] : Int $indent - indentation level for log message
234 Example : my $log = $support->log_filehandle;
235 $support->log_verbose('Log this verbose message.\n', 1);
236 Description : Logs a message via $self->log if --verbose option was used
237 Return type : TRUE on success, FALSE if not verbose
238 Exceptions : none
239 Caller : general
240
241 =cut
242
243 sub debug {
244 my ($self, $txt, $indent, $stamped) = @_;
245
246 return(0) unless ($self->{'loglevel'} >= 4);
247
248 $self->log_generic($txt, $indent, $stamped);
249 return(1);
250 }
251
252
253 sub log_progress {
254 my $self = shift;
255 my $name = shift;
256 my $curr = shift;
257 my $indent = shift;
258
259 throw("You must provide a name and the current value for your progress bar")
260 unless ($name and $curr);
261
262 # return if we haven't reached the next increment
263 return if ($curr < int($self->{'_progress'}->{$name}->{'next'}));
264
265 my $index = $self->{'_progress'}->{$name}->{'index'};
266 my $num_bins = $self->{'_progress'}->{$name}->{'numbins'};
267 my $percent = $index/$num_bins*100;
268
269 my $log_str;
270 $log_str .= ' 'x$indent if ($index == 0);
271 $log_str .= "\b"x4;
272 $log_str .= sprintf("%3s%%", $percent);
273 $log_str .= "\n" if ($curr == $self->{'_progress'}->{$name}->{'max_val'});
274
275 $self->info($log_str);
276
277 # increment counters
278 $self->{'_progress'}->{$name}->{'index'}++;
279 $self->{'_progress'}->{$name}->{'next'} += $self->{'_progress'}->{$name}->{'binsize'};
280 }
281
282
283 sub log_progressbar {
284 my $self = shift;
285 my $name = shift;
286 my $curr = shift;
287 my $indent = shift;
288
289 throw("You must provide a name and the current value for your progress bar")
290 unless ($name and $curr);
291
292 # return if we haven't reached the next increment
293 return if ($curr < int($self->{'_progress'}->{$name}->{'next'}));
294
295 my $index = $self->{'_progress'}->{$name}->{'index'};
296 my $num_bins = $self->{'_progress'}->{$name}->{'numbins'};
297 my $percent = $index/$num_bins*100;
298
299 my $log_str = "\r".(' 'x$indent)."[".('='x$index).(' 'x($num_bins-$index))."] ${percent}\%";
300 $log_str .= "\n" if ($curr == $self->{'_progress'}->{$name}->{'max_val'});
301
302 $self->info($log_str);
303
304 # increment counters
305 $self->{'_progress'}->{$name}->{'index'}++;
306 $self->{'_progress'}->{$name}->{'next'} += $self->{'_progress'}->{$name}->{'binsize'};
307 }
308
309
310 sub init_progress {
311 my $self = shift;
312 my $max = shift;
313 my $num_bins = shift || 50;
314
315 throw("You must provide the maximum value for your progress bar")
316 unless (defined($max));
317
318 # auto-generate a unique name for your progressbar
319 my $name = time . '_' . int(rand(1000));
320
321 # calculate bin size; we will use 50 bins (2% increments)
322 my $binsize = $max/$num_bins;
323
324 $self->{'_progress'}->{$name}->{'max_val'} = $max;
325 $self->{'_progress'}->{$name}->{'binsize'} = $binsize;
326 $self->{'_progress'}->{$name}->{'numbins'} = $num_bins;
327 $self->{'_progress'}->{$name}->{'next'} = 0;
328 $self->{'_progress'}->{$name}->{'index'} = 0;
329
330 return $name;
331 }
332
333
334 =head2 log_filehandle
335
336 Arg[1] : (optional) String $mode - file access mode
337 Example : my $log = $support->log_filehandle;
338 # print to the filehandle
339 print $log 'Lets start logging...\n';
340 # log via the wrapper $self->log()
341 $support->log('Another log message.\n');
342 Description : Returns a filehandle for logging (STDERR by default, logfile if
343 set from config or commandline). You can use the filehandle
344 directly to print to, or use the smart wrapper $self->log().
345 Logging mode (truncate or append) can be set by passing the
346 mode as an argument to log_filehandle(), or with the
347 --logappend commandline option (default: truncate)
348 Return type : Filehandle - the filehandle to log to
349 Exceptions : thrown if logfile can't be opened
350 Caller : general
351
352 =cut
353
354 sub log_filehandle {
355 my ($self, $mode) = @_;
356
357 unless ($self->{'_log_filehandle'}) {
358 $mode ||= '>';
359 $mode = '>>' if ($self->logappend);
360
361 my $fh = \*STDERR;
362
363 if (my $logfile = $self->logfile) {
364 if (my $logpath = $self->logpath) {
365 unless (-e $logpath) {
366 system("mkdir -p $logpath") == 0 or
367 throw("Can't create log dir $logpath: $!\n");
368 }
369
370 $logfile = "$logpath/".$self->logfile;
371 }
372
373 open($fh, "$mode", $logfile) or
374 throw("Unable to open $logfile for writing: $!");
375 }
376
377 $self->{'_log_filehandle'} = $fh;
378 }
379
380 return $self->{'_log_filehandle'};
381 }
382
383
384 =head2 extract_log_identifier
385
386 Arg[1] :
387 Example :
388 Description :
389 Return type :
390 Exceptions :
391 Caller :
392 Status :
393
394 =cut
395
396 sub extract_log_identifier {
397 my $self = shift;
398
399 if (my $logfile = $self->logfile) {
400 $logfile =~ /.+\.([^\.]+)\.log/;
401 return $1;
402 } else {
403 return undef;
404 }
405 }
406
407
408 =head2 init_log
409
410 Example : $support->init_log;
411 Description : Opens a filehandle to the logfile and prints some header
412 information to this file. This includes script name, date, user
413 running the script and parameters the script will be running
414 with.
415 Return type : Filehandle - the log filehandle
416 Exceptions : none
417 Caller : general
418
419 =cut
420
421 sub init_log {
422 my $self = shift;
423 my $params = shift;
424
425 # get a log filehandle
426 my $log = $self->log_filehandle;
427
428 # remember start time
429 $self->{'_start_time'} = time;
430
431 # don't log parameters if this script is run by another one
432 if ($self->logauto or ! $self->is_component) {
433 # print script name, date, user who is running it
434 my $hostname = `hostname`;
435 chomp $hostname;
436 my $script = "$hostname:$Bin/$Script";
437 my $user = `whoami`;
438 chomp $user;
439 $self->info("Script: $script\nDate: ".$self->date."\nUser: $user\n");
440
441 # print parameters the script is running with
442 if ($params) {
443 $self->info("Parameters:\n\n");
444 $self->info($params);
445 }
446 }
447
448 return $log;
449 }
450
451
452 =head2 finish_log
453
454 Example : $support->finish_log;
455 Description : Writes footer information to a logfile. This includes the
456 number of logged warnings, timestamp and memory footprint.
457 Return type : TRUE on success
458 Exceptions : none
459 Caller : general
460
461 =cut
462
463 sub finish_log {
464 my $self = shift;
465
466 $self->info("\nAll done for $Script.\n");
467 $self->info($self->warning_count." warnings. ");
468 $self->info("Runtime: ".$self->runtime." ".$self->date_and_mem."\n\n");
469
470 return(1);
471 }
472
473
474 sub runtime {
475 my $self = shift;
476
477 my $runtime = "n/a";
478
479 if ($self->{'_start_time'}) {
480 my $diff = time - $self->{'_start_time'};
481 my $sec = $diff % 60;
482 $diff = ($diff - $sec) / 60;
483 my $min = $diff % 60;
484 my $hours = ($diff - $min) / 60;
485
486 $runtime = "${hours}h ${min}min ${sec}sec";
487 }
488
489 return $runtime;
490 }
491
492
493 =head2 date_and_mem
494
495 Example : print LOG "Time, memory usage: ".$support->date_and_mem."\n";
496 Description : Prints a timestamp and the memory usage of your script.
497 Return type : String - timestamp and memory usage
498 Exceptions : none
499 Caller : general
500
501 =cut
502
503 sub date_and_mem {
504 my $date = strftime "%Y-%m-%d %T", localtime;
505 my $mem = `ps -p $$ -o vsz |tail -1`;
506 chomp $mem;
507 $mem = parse_bytes($mem*1000);
508 return "[$date, mem $mem]";
509 }
510
511
512 sub time_and_mem {
513 my $date = strftime "%T", localtime;
514 my $mem = `ps -p $$ -o vsz |tail -1`;
515 chomp $mem;
516 $mem = parse_bytes($mem*1000);
517 $mem =~ s/ //;
518 return "[$date|$mem]";
519 }
520
521
522 =head2 date
523
524 Example : print "Date: " . $support->date . "\n";
525 Description : Prints a nicely formatted timestamp (YYYY-DD-MM hh:mm:ss)
526 Return type : String - the timestamp
527 Exceptions : none
528 Caller : general
529
530 =cut
531
532 sub date {
533 return strftime "%Y-%m-%d %T", localtime;
534 }
535
536
537 =head2 mem
538
539 Example : print "Memory usage: " . $support->mem . "\n";
540 Description : Prints the memory used by your script. Not sure about platform
541 dependence of this call ...
542 Return type : String - memory usage
543 Exceptions : none
544 Caller : general
545
546 =cut
547
548 sub mem {
549 my $mem = `ps -p $$ -o vsz |tail -1`;
550 chomp $mem;
551 return $mem;
552 }
553
554
555 =head2 warning_count
556
557 Example : print LOG "There were ".$support->warnings." warnings.\n";
558 Description : Returns the number of warnings encountered while running the
559 script (the warning counter is increased by $self->log_warning).
560 Return type : Int - number of warnings
561 Exceptions : none
562 Caller : general
563
564 =cut
565
566 sub warning_count {
567 my $self = shift;
568 return $self->{'_warnings'};
569 }
570
571
572 =head2 logfile
573
574 Arg[1] :
575 Example :
576 Description : Getter and setter for the logfile
577 Return type :
578 Exceptions :
579 Caller :
580 Status :
581
582 =cut
583
584 sub logfile {
585 my $self = shift;
586 $self->{'_logfile'} = shift if (@_);
587 return $self->{'_logfile'};
588 }
589
590
591 =head2 log_auto_id
592
593 Arg[1] :
594 Example :
595 Description :
596 Return type :
597 Exceptions :
598 Caller :
599 Status :
600
601 =cut
602
603 sub log_auto_id {
604 my $self = shift;
605 $self->{'_log_auto_id'} = shift if (@_);
606 return $self->{'_log_auto_id'};
607 }
608
609
610 sub logauto {
611 my $self = shift;
612 $self->{'_log_auto'} = shift if (@_);
613 return $self->{'_log_auto'};
614 }
615
616
617 =head2 create_auto_logfile
618
619 Arg[1] :
620 Example :
621 Description :
622 Return type :
623 Exceptions :
624 Caller :
625 Status : At Risk
626 : under development
627
628 =cut
629
630 sub create_auto_logfile {
631 my $self = shift;
632 my $logautobase = shift;
633
634 # do nothing if automatic logfile generation isn't set
635 return unless ($self->logauto);
636
637 # an explicit logfile name overrides LOGAUTO
638 return if ($self->logfile);
639
640 # argument check
641 unless ($logautobase) {
642 throw('Need a base logfile name for auto-generating logfile.');
643 }
644
645 # create a logfile name
646 $self->logfile("${logautobase}_".$self->log_auto_id.".log");
647 }
648
649
650 =head2 logpath
651
652 Arg[1] :
653 Example :
654 Description :
655 Return type :
656 Exceptions :
657 Caller :
658 Status :
659
660 =cut
661
662 sub logpath {
663 my $self = shift;
664 $self->{'_logpath'} = shift if (@_);
665 return $self->{'_logpath'};
666 }
667
668
669 =head2 logappend
670
671 Arg[1] :
672 Example :
673 Description :
674 Return type :
675 Exceptions :
676 Caller :
677 Status :
678
679 =cut
680
681 sub logappend {
682 my $self = shift;
683 $self->{'_logappend'} = shift if (@_);
684 return $self->{'_logappend'};
685 }
686
687
688 =head2 is_component
689
690 Arg[1] :
691 Example :
692 Description :
693 Return type :
694 Exceptions :
695 Caller :
696 Status :
697
698 =cut
699
700 sub is_component {
701 my $self = shift;
702 $self->{'_is_component'} = shift if (@_);
703 return $self->{'_is_component'};
704 }
705
706
707 sub loglevel {
708 my $self = shift;
709 return $reverse_level_defs[$self->{'loglevel'}];
710 }
711
712
713 #
714 # deprecated methods (left here for backwards compatibility
715 #
716 sub log_error {
717 return $_[0]->error(@_);
718 }
719
720 sub log_warning {
721 return $_[0]->warning(@_);
722 }
723
724 sub log {
725 return $_[0]->info(@_);
726 }
727
728 sub log_verbose {
729 return $_[0]->debug(@_);
730 }
731
732 sub log_stamped {
733 return $_[0]->log(@_, 1);
734 }
735
736
737
738 1;
739