Commits

Edward Kirton committed 86fe859

updated logger - no persistent connections

  • Participants
  • Parent commits ee36f26

Comments (0)

Files changed (3)

File lib/iTagger/ClusterOTUs.pm

 use Parallel::ForkManager;
 use POSIX qw/mkfifo/;
 use Config::Tiny;
-use Log::Log4perl;
 use iTagger::FastaDb;
 use iTagger::Stats qw(sum);
+use iTagger::Logger qw(die warn info debug error);
 
 our $VERSION = 1.0;
 our @ISA = qw(Exporter);
     die("Missing log config file") unless $logConfigFile;
     my $start = time;
 
-    Log::Log4perl->init($logConfigFile);
-    $logger = Log::Log4perl->get_logger('iTagger::ClusterOTUs');
+    $logger = new iTagger::Logger('iTagger::ClusterOTUs', $logConfigFile);
 
-    $logger->logdie("Missing args") unless $configFile and $dir;
+    $logger->die("Missing args") unless $configFile and $dir;
 
     my $outDir = "$dir/otu";
-    -d $outDir or mkdir($outDir) or $logger->logdie("Unable to mkdir $outDir: $!");
+    -d $outDir or mkdir($outDir) or $logger->die("Unable to mkdir $outDir: $!");
     my $logFile = "$outDir/cluster.log";
 
     my $config = Config::Tiny->read($configFile);
-    $logger->logdie("Config missing USEARCH section") unless exists($config->{USEARCH});
+    $logger->die("Config missing USEARCH section") unless exists($config->{USEARCH});
     my $maxRadius = _set($config, 'USEARCH', 'MAX_RADIUS', MAX_RADIUS);
-    $logger->logdie("MAX_RADIUS=$maxRadius invalid; must be 1..5") unless $maxRadius >= 1 and $maxRadius <= 5;
+    $logger->die("MAX_RADIUS=$maxRadius invalid; must be 1..5") unless $maxRadius >= 1 and $maxRadius <= 5;
     my $refDb = _set($config, 'USEARCH', 'REF_DB', '');
     my $iterationSize = _set($config, 'USEARCH', 'ITERATION_SIZE', 0);
     my $minLibSize = _set($config, 'USEARCH', 'MIN_LIB_SIZE', MIN_LIB_SIZE);
     {
         $threads = `nproc`;
         chomp $threads;
-        $logger->logdie("Number of threads not defined") unless $threads;
+        $logger->die("Number of threads not defined") unless $threads;
     }
 
     my $singletBase = "$tmpDir/$$.singlets";
 sub _input
 {
     my ($dir, $outFile1, $outFile2, $singletBase, $iterationSize, $logFile, $minLibSize, $threads) = @_;
-    $logger->logdie("Missing args") unless $dir and $outFile1 and $outFile2 and $logFile and $minLibSize and $threads;
+    $logger->die("Missing args") unless $dir and $outFile1 and $outFile2 and $logFile and $minLibSize and $threads;
 
     # FIND SEQOBS FILES, CHECK LIB SIZES -- SKIP IF TOO SMALL
     my $dataDir = "$dir/data";
-    opendir(DIR, $dataDir) or $logger->logdie("Unable to readdir $dataDir: $!");
+    opendir(DIR, $dataDir) or $logger->die("Unable to readdir $dataDir: $!");
     my @contents = sort { $a cmp $b } grep { $_ !~ /\./ } readdir(DIR);
     closedir(DIR);
     my @libs;
         next unless -d "$dataDir/$lib"; 
         my $file = "$dataDir/$lib/seqobs.tsv.bz2";
         next unless -e $file;
-        open(my $fh, "bzcat $file |") or $logger->logdie("Unable to read $file: $!");
+        open(my $fh, "bzcat $file |") or $logger->die("Unable to read $file: $!");
         my $hdr = <$fh>; # header
         chomp $hdr;
-        $logger->logdie("Invalid seqobs file header") unless $hdr =~ /^#lib=(.+);size=(\d+)$/;
-        $logger->logdie("Invalid seqobs file library id") unless $1 eq $lib;
+        $logger->die("Invalid seqobs file header") unless $hdr =~ /^#lib=(.+);size=(\d+)$/;
+        $logger->die("Invalid seqobs file library id") unless $1 eq $lib;
         my $libSize = $2;
         if ( $libSize < $minLibSize )
         {
         my $line = <$fh>;
         chomp $line;
         my @row = split(/\t/, $line);
-        $logger->logdie("Invalid file: $file") unless @row == 2;
+        $logger->die("Invalid file: $file") unless @row == 2;
         my ($seq, $count) = @row;
         push @inFiles, [ $fh, $#libs, $seq, $count ];
     }
-    $logger->logdie("No seqobs files found") unless scalar(keys %libFiles);
+    $logger->die("No seqobs files found") unless scalar(keys %libFiles);
     my @obs0 = ( (0) x scalar(@libs) ); # empty obs list
 
     # DEREPLICATE, FILTER LOW-ABUNDANCE CLUSTERS, SORT.
     # WHILE LOW-ABUNDANCE SEQUENCES (E.G. SINGLETS) DO NOT HAVE .fasta.obs FILES;
     # INSTEAD A SPARSE REPRESENTATION IS USED IN THE HEADER.
     my $tmpFile = "$tmpDir/$$.seqobs.tmp";
-    open(my $out, "| sort -k1,1nr -T $tmpDir -o $tmpFile") or $logger->logdie("Unable to pipe sort $tmpFile: $!");
+    open(my $out, "| sort -k1,1nr -T $tmpDir -o $tmpFile") or $logger->die("Unable to pipe sort $tmpFile: $!");
     my $counter = 0; # number of clusterable sequences (not reads)
     my $singletCounter = 0; # unique id for singlets
     my $singletFileNum = 1; # unique id for singlets filenames
     my $singletFile = "$singletBase.$singletFileNum.fasta";
     my $singletFileCounter = 0; # number of seqs in current singlets file
-    open(my $low, '>', $singletFile) or $logger->logdie("Unable to write $singletFile: $!");
+    open(my $low, '>', $singletFile) or $logger->die("Unable to write $singletFile: $!");
     my ($i, $seq, $count) = _nextSeq(\@inFiles);
     my @obs = @obs0; # deep copy
     $obs[$i] = $count;
                     $singletFileCounter = 0;
                     ++$singletFileNum;
                     $singletFile = "$singletBase.$singletFileNum.fasta";
-                    open($low, '>', $singletFile) or $logger->logdie("Unable to write $singletFile: $!");
+                    open($low, '>', $singletFile) or $logger->die("Unable to write $singletFile: $!");
                 }
                 print $low '>', ++$singletCounter, ';size=', $size, ';obs=', _obsToSparseString(\@obs), "\n" ,$seq, "\n";
                 for ( my $i=0; $i<=$#obs; $i++ ) { $libSingletSizes[$i] += $obs[$i] }
         $clusterablePct[$i] = $libSizes[$i] ? (int($libClusterableSizes[$i]/$libSizes[$i]*1000+0.5)/10) . '%' : 'N/A';
         $singletsPct[$i] = $libSizes[$i] ? (int($libSingletSizes[$i]/$libSizes[$i]*1000+0.5)/10) . '%' : 'N/A';
     }
-    open(my $log, '>', $logFile) or $logger->logdie("Unable to write $logFile: $!");
+    open(my $log, '>', $logFile) or $logger->die("Unable to write $logFile: $!");
     print $log
         join("\t", 'LIB', 'TOTAL', map { _commify($_) } @libs),"\n",
         join("\t", 'INPUT', _commify($totLibSize), map { _commify($_) } @libSizes), "\n",
 sub _initialSplitFasta 
 {
     my ($inFile, $outFile1, $outFile2, $iterationSize) = @_;
-    open(my $in, '<', $inFile) or $logger->logdie("Unable to read $inFile: $!");
-    open(my $out, '>', $outFile1) or $logger->logdie("Unable to write $outFile1: $!");
-    open(my $obsOut, '>', "$outFile1.obs") or $logger->logdie("Unable to write $outFile1.obs: $!");
+    open(my $in, '<', $inFile) or $logger->die("Unable to read $inFile: $!");
+    open(my $out, '>', $outFile1) or $logger->die("Unable to write $outFile1: $!");
+    open(my $obsOut, '>', "$outFile1.obs") or $logger->die("Unable to write $outFile1.obs: $!");
     my $index = -1;
     while (<$in>)
     {
         {
             close($out);
             close($obsOut);
-            open($out, '>', $outFile2) or $logger->logdie("Unable to write $outFile2: $!");
-            open($obsOut, '>', "$outFile2.obs") or $logger->logdie("Unable to write $outFile2.obs: $!");
+            open($out, '>', $outFile2) or $logger->die("Unable to write $outFile2: $!");
+            open($obsOut, '>', "$outFile2.obs") or $logger->die("Unable to write $outFile2.obs: $!");
         }
         print $out '>',$index,';size=',$size,"\n",$seq,"\n";
         print $obsOut $index, "\t", $obs, "\n";
 sub _cluster
 {
     my ($inFile, $outFile, $radius, $libOrder, $threads) = @_;
-    $logger->logdie("Missing args") unless $inFile and $outFile and $radius and $threads;
+    $logger->die("Missing args") unless $inFile and $outFile and $radius and $threads;
     my $identity = (100-$radius)/100;
     my @tmpFiles = ();
 
 
     # LOAD HITS
     my %hits = ();
-    open(my $in, '<', $hitFile) or $logger->logdie("Unable to read $hitFile: $!");
+    open(my $in, '<', $hitFile) or $logger->die("Unable to read $hitFile: $!");
     while (<$in>)
     {
         chomp;
         my ($query, $subj) = split(/\t/);
         next if $query eq $subj;
-        $logger->logdie("Invalid query ID") unless $query =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid query ID") unless $query =~ /^(\d+);size=\d+$/;
         my $queryId = $1;
-        $logger->logdie("Invalid subject ID") unless $subj =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid subject ID") unless $subj =~ /^(\d+);size=\d+$/;
         my $subjId = $1;
         next if $queryId < $subjId; # don't add to smaller cluster
-        $logger->logdie("Invalid OTU $subjId") unless exists($otus->{$subjId});
-        $logger->logwarn("Clustering error, OTU $queryId should not exist; it should have been added to $subjId") if exists($otus->{$queryId}); # TODO
+        $logger->die("Invalid OTU $subjId") unless exists($otus->{$subjId});
+        $logger->warn("Clustering error, OTU $queryId should not exist; it should have been added to $subjId") if exists($otus->{$queryId}); # TODO
         $hits{$queryId} = $subjId;
     }
     close($in);
 
     # GET QUERY OBS, ADD TO OTU
-    open($in, '<', "$inFile.obs") or $logger->logdie("Unable to read $inFile.obs: $!");
+    open($in, '<', "$inFile.obs") or $logger->die("Unable to read $inFile.obs: $!");
     while (<$in>)
     {
         chomp;
     my ($inFile, $outFile1, $outFile2, $iterationSize) = @_;
     unlink($outFile2, "$outFile2.obs") if -e $outFile2;
     my $in = new iTagger::FastaDb($inFile);
-    open(my $obsIn, '<', "$inFile.obs") or $logger->logdie("Unable to read $inFile.obs: $!");
-    open(my $out, '>', $outFile1) or $logger->logdie("Unable to write $outFile1: $!");
-    open(my $obsOut, '>', "$outFile1.obs") or $logger->logdie("Unable to write $outFile1.obs: $!");
+    open(my $obsIn, '<', "$inFile.obs") or $logger->die("Unable to read $inFile.obs: $!");
+    open(my $out, '>', $outFile1) or $logger->die("Unable to write $outFile1: $!");
+    open(my $obsOut, '>', "$outFile1.obs") or $logger->die("Unable to write $outFile1.obs: $!");
     my $counter = 0;
     while ( my $rec = $in->next_seq )
     {
         {
             close($out);
             close($obsOut);
-            open($out, '>', $outFile2) or $logger->logdie("Unable to write $outFile2: $!");
-            open($obsOut, '>', "$outFile2.obs") or $logger->logdie("Unbale to write $outFile2.obs: $!");
+            open($out, '>', $outFile2) or $logger->die("Unable to write $outFile2: $!");
+            open($obsOut, '>', "$outFile2.obs") or $logger->die("Unbale to write $outFile2.obs: $!");
         }
     }
     close($out);
     my @ids = sort { $otus->{$b}->[2] <=> $otus->{$a}->[2] } keys %$otus;
 
     # OUTPUT
-    open(my $out1, '>', $fastaFile) or $logger->logdie("Unable to write $fastaFile: $!");
-    open(my $out2, '>', $obsFile) or $logger->logdie("Unable to write $obsFile: $!");
+    open(my $out1, '>', $fastaFile) or $logger->die("Unable to write $fastaFile: $!");
+    open(my $out2, '>', $obsFile) or $logger->die("Unable to write $obsFile: $!");
     my $index = -1; # NEW ID
     while (@ids)
     {
     while ( my $rec = $db->next_seq )
     {
         my $hdr = $rec->id;
-        $logger->logdie("Invalid OTU ID: $hdr") unless $hdr =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid OTU ID: $hdr") unless $hdr =~ /^(\d+);size=\d+$/;
         my $id = $1;
         $otus{$id} = [ $rec->seq ];
     }
     # GET OBS FOR OTUS FOUND ABOVE ONLY (SOME MAY HAVE BEEN FILTERED AS CHIMERIC)
-    open(my $in, '<', $obsFile) or $logger->logdie("Unable to read $obsFile: $!");
+    open(my $in, '<', $obsFile) or $logger->die("Unable to read $obsFile: $!");
     while (<$in>)
     {
         chomp;
 {
     my ($inFile) = @_;
     my @sums;
-    open (my $in, '<', $inFile) or $logger->logdie("Unable to read $inFile: $!");
+    open (my $in, '<', $inFile) or $logger->die("Unable to read $inFile: $!");
     while (<$in>)
     {
         chomp;
 sub _search
 {
     my ($otuFile, $file1, $file2, $radius, $threads, $iterationSize) = @_;
-    $logger->logdie("Missing args") unless $otuFile and $file1 and $file2 and $radius and $threads and $iterationSize;
+    $logger->die("Missing args") unless $otuFile and $file1 and $file2 and $radius and $threads and $iterationSize;
     my $identity = (100-$radius)/100;
 
     # MAP FILE2 VS OTU (CENTROIDS) FILE
 
     # LOAD HITS
     my %hits = ();
-    open(my $in, '<', $hitFile) or $logger->logdie("Unable to read $hitFile: $!");
+    open(my $in, '<', $hitFile) or $logger->die("Unable to read $hitFile: $!");
     while (<$in>)
     {
         chomp;
         my ($query, $subj) = split(/\t/);
         next if $query eq $subj;
-        $logger->logdie("Invalid query ID: $query") unless $query =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid query ID: $query") unless $query =~ /^(\d+);size=\d+$/;
         my $queryId = $1;
-        $logger->logdie("Invalid subject ID: $subj") unless $subj =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid subject ID: $subj") unless $subj =~ /^(\d+);size=\d+$/;
         my $subjId = $1;
-        $logger->logdie("OTU not found: $subjId") unless exists($otus->{$subjId});
+        $logger->die("OTU not found: $subjId") unless exists($otus->{$subjId});
         $hits{$queryId} = $subjId;
     }
     close($in);
 
     # GET QUERY OBS, ADD TO OTU
-    open($in, '<', "$file2.obs") or $logger->logdie("Unable to read $file2.obs: $!");
+    open($in, '<', "$file2.obs") or $logger->die("Unable to read $file2.obs: $!");
     while (<$in>)
     {
         chomp;
     my $tmpFile1 = "$tmpDir/$$.$time.tmpFile.1.fasta";
     my $tmpFile2 = "$tmpDir/$$.$time.tmpFile.2.fasta";
     my $in1 = new iTagger::FastaDb($file2);
-    open(my $in2, '<', "$file2.obs") or $logger->logdie("Unable to read $file2.obs: $!");
-    open(my $out1, '>', $tmpFile1) or $logger->logdie("Unable to write $tmpFile1: $!");
-    open(my $out2, '>', "$tmpFile1.obs") or $logger->logdie("Unable to write $tmpFile1.obs: $!");
+    open(my $in2, '<', "$file2.obs") or $logger->die("Unable to read $file2.obs: $!");
+    open(my $out1, '>', $tmpFile1) or $logger->die("Unable to write $tmpFile1: $!");
+    open(my $out2, '>', "$tmpFile1.obs") or $logger->die("Unable to write $tmpFile1.obs: $!");
     while ( my $rec1 = $in1->next_seq )
     {
-        $logger->logdie("Invalid header") unless $rec1->id =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid header") unless $rec1->id =~ /^(\d+);size=\d+$/;
         my $id1 = $1;
         my $rec2 = <$in2>;
         my ($id2, $obs) = split(/\t/, $rec2);
         chomp $obs;
-        $logger->logdie("Fasta:obs mismatch ($id1:$id2)") unless $id1 == $id2;
+        $logger->die("Fasta:obs mismatch ($id1:$id2)") unless $id1 == $id2;
         next if exists($hits{$id1});
         print $out1 $rec1->output;
         print $out2 $rec2;
         {
             close($out1);
             close($out2);
-            open($out1, '>', $tmpFile2) or $logger->logdie("Unable to write $tmpFile2: $!");
-            open($out2, '>', "$tmpFile2.obs") or $logger->logdie("Unable to write $tmpFile2.obs: $!");
+            open($out1, '>', $tmpFile2) or $logger->die("Unable to write $tmpFile2: $!");
+            open($out2, '>', "$tmpFile2.obs") or $logger->die("Unable to write $tmpFile2.obs: $!");
         }
     }
     close($in2);
     unlink($file2, "$file2.obs", $hitFile);
     if ( -e $tmpFile2 )
     {
-        move($tmpFile2, $file2) or $logger->logdie("Unable to mv $tmpFile2 $file2: $!");
-        move("$tmpFile2.obs", "$file2.obs") or $logger->logdie("Unable to mv $tmpFile2.obs $file2.obs: $!");
+        move($tmpFile2, $file2) or $logger->die("Unable to mv $tmpFile2 $file2: $!");
+        move("$tmpFile2.obs", "$file2.obs") or $logger->die("Unable to mv $tmpFile2.obs $file2.obs: $!");
     }
 
     # OUTPUT OTUS AND APPEND UNMAPPED PART 1
     {
         $chimericPct[$i] = $libClusterableSizes->[$i] ? (int($chimeric[$i]/$libClusterableSizes->[$i]*1000+0.5)/10) . '%' : 'N/A';
     }
-    open(my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+    open(my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
     print $log 
         join("\t", 'CLUST CHIMERA', _commify(sum(\@chimeric)), map { _commify($_) } @chimeric), "\n",
         join("\t", 'CLUST CHIMERA PCT', $totChimPct, @chimericPct), "\n";
 sub _searchSinglets
 {
     my ($otuFile, $singletBase, $radius, $threads, $libs, $libSingletSizes, $logFile) = @_;
-    $logger->logdie("Missing args") unless $otuFile and $singletBase and $radius and $threads and $libs and $libSingletSizes and $logFile;
+    $logger->die("Missing args") unless $otuFile and $singletBase and $radius and $threads and $libs and $libSingletSizes and $logFile;
     my $identity = (100-$radius)/100;
 
     # LOAD OTUS
         $usearchTime += (time-$start);
 
         # PARSE HITS, ADD TO OTUS
-        open(my $in, '<', $hitFile) or $logger->logdie("Unable to read $hitFile: $!");
+        open(my $in, '<', $hitFile) or $logger->die("Unable to read $hitFile: $!");
         while (<$in>)
         {
             chomp;
             my ($query, $subj) = split(/\t/);
             # QUERY
-            $logger->logdie("Invalid query ID: $query") unless $query =~ /^(\d+);size=\d+;obs=(.+)$/;
+            $logger->die("Invalid query ID: $query") unless $query =~ /^(\d+);size=\d+;obs=(.+)$/;
             my $queryId = $1;
             my $queryObs = $2;
             my @queryObs = split(/,/, $queryObs);
             # TARGET/SUBJECT
-            $logger->logdie("Invalid subject ID: $subj") unless $subj =~ /^(\d+);size=\d+$/;
+            $logger->die("Invalid subject ID: $subj") unless $subj =~ /^(\d+);size=\d+$/;
             my $subjId = $1;
-            $logger->logdie("OTU not found: $subjId") unless exists($otus->{$subjId});
+            $logger->die("OTU not found: $subjId") unless exists($otus->{$subjId});
             my $subjObs = $otus->{$subjId}->[1];
             # ADD
             foreach my $item (@queryObs)
         }
     }
     my $totSingMapPct = $totSingSize ? (int($totSingClus/$totSingSize*1000+0.5)/10) . '%' : 'N/A';
-    open(my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+    open(my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
     print $log
         join("\t", 'SINGLETS MAPPED', _commify(sum(\@libSingletsClustered)), map { _commify($_) } @libSingletsClustered), "\n",
         join("\t", 'SINGLETS MAPPED PCT', $totSingMapPct, @libSingletsClusteredPct), "\n",
 sub _chimeraFilter
 {
     my ($inFile, $refDb, $outFile, $beforeSizes, $logFile) = @_;
-    $logger->logdie("Missing args") unless $inFile and $outFile;
+    $logger->die("Missing args") unless $inFile and $outFile;
 
     my $afterSizes = $beforeSizes;
     if ( $refDb )
         my $totBefore = sum($beforeSizes);
         my $totChimeric = $totBefore - sum($afterSizes);
         my $totChimericPct = $totBefore ? int($totChimeric/$totBefore*1000+0.5)/10 . '%' : 'N/A';
-        open(my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+        open(my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
         print $log
             join("\t", 'REF-CHIMERA', _commify($totChimeric), map { _commify($_) } @chimeric), "\n",
             join("\t", 'REF-CHIMERA PCT', $totChimericPct, @chimericPct), "\n";
     my $totBeforeSizes = sum($beforeSizes);
     my $totAfterSizes = sum($afterSizes);
     my $totAfterSizesPct = $totBeforeSizes ? int($totAfterSizes/$totBeforeSizes*1000+0.5)/10 . '%' : 'N/A';
-    open(my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+    open(my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
     print $log
         join("\t", 'CLUSTERED', _commify($totAfterSizes), map { _commify($_) } @$afterSizes), "\n",
         join("\t", 'CLUSTERED PCT', $totAfterSizesPct, @afterSizesPct), "\n";
 sub _classify
 {
     my ($config, $inFile, $outFasta, $rdpOutFile, $otuPassFile, $otuFailFile, $libNames, $logFile, $libClustered, $threads) = @_;
-    $logger->logdie("Missing args") unless $config and $inFile and $outFasta and $rdpOutFile and $otuPassFile and $otuFailFile and $libNames and $logFile and $threads;
-    $logger->logdie("\$RDP_JAR_PATH not defined") unless $RDP_JAR_PATH;
-    $logger->logdie("\$TMPDIR not defined") unless $TMPDIR;
+    $logger->die("Missing args") unless $config and $inFile and $outFasta and $rdpOutFile and $otuPassFile and $otuFailFile and $libNames and $logFile and $threads;
+    $logger->die("\$RDP_JAR_PATH not defined") unless $RDP_JAR_PATH;
+    $logger->die("\$TMPDIR not defined") unless $TMPDIR;
     my $start = time;
 
     # CONFIG
     my $minWords = _set($config, 'RDP_CLASSIFIER', 'MIN_WORDS', 120);
     my $level = _set($config, 'RDP_CLASSIFIER', 'LEVEL', 'class');
     my $cutoff = _set($config, 'RDP_CLASSIFIER', 'CUTOFF', 0.5);
-    $logger->logdie("Invalid cutoff, $cutoff") if $cutoff < 0 or $cutoff > 1;
+    $logger->die("Invalid cutoff, $cutoff") if $cutoff < 0 or $cutoff > 1;
     $cutoff = 0 unless defined($cutoff);
     $minWords = 120 unless $minWords;
     my %levelIndex = 
         'order'   => 3, 'family'  => 4, 'genus'   => 5
     );
     $level = lc($level);
-    $logger->logdie("Invalid level $level") unless exists($levelIndex{$level});
+    $logger->die("Invalid level $level") unless exists($levelIndex{$level});
 
     # SPLIT INPUT TO TMPFILES, ROUND-ROBIN STYLE.  FIFOS ARE NOT USED FOR INPUT BECAUSE RDP CLASSIFIER WON'T READ FROM A FIFO.
     my @inFiles = map { "$tmpDir/$$.rdp.in.$_.fasta" } (1..$threads);
     my @fhs;
     for ( my $i=0; $i<$threads; $i++)
     {
-        open( my $fh, '>', $inFiles[$i] ) or $logger->logdie("Unable to write $inFiles[$i]: $!");
+        open( my $fh, '>', $inFiles[$i] ) or $logger->die("Unable to write $inFiles[$i]: $!");
         push @fhs, $fh;
     }
-    open( my $out, "| bzip2 --best > $outFasta") or $logger->logdie("Unable to pipe gzip $outFasta: $!");
+    open( my $out, "| bzip2 --best > $outFasta") or $logger->die("Unable to pipe gzip $outFasta: $!");
     my $db = new iTagger::FastaDb($inFile);
     my $i = -1;
     while ( my $rec = $db->next_seq )
     {
         # remove ";size=X" from header
         my $id = $rec->id;
-        $logger->logdie("Invalid id: $id") unless $id =~ /^(\d+);size=\d+$/;
+        $logger->die("Invalid id: $id") unless $id =~ /^(\d+);size=\d+$/;
         $id = $1;
         $rec->base($id);
         print $out $rec->output; # save copy
     my @buffer = ();
     for ( my $i=0; $i<$threads; $i++)
     {
-        open( my $fh, '<', $outFiles[$i] ) or $logger->logdie("Unable to read $outFiles[$i]: $!");
+        open( my $fh, '<', $outFiles[$i] ) or $logger->die("Unable to read $outFiles[$i]: $!");
         my $line = <$fh>;
         if ( defined($line) )
         {
             $buffer[$i] = [ $id, \@row ];
         }
     }
-    open(my $in, '<', "$inFile.obs") or $logger->logdie("Unable to read $inFile.obs: $!");
-    open($out, '>', $rdpOutFile) or $logger->logdie("Unable to write $rdpOutFile: $!"); # save a copy
-    open(my $pass, '>', $otuPassFile) or $logger->logdie("Unable to write $otuPassFile: $!");
-    open(my $fail, '>', $otuFailFile) or $logger->logdie("Unable to write $otuFailFile: $!");
+    open(my $in, '<', "$inFile.obs") or $logger->die("Unable to read $inFile.obs: $!");
+    open($out, '>', $rdpOutFile) or $logger->die("Unable to write $rdpOutFile: $!"); # save a copy
+    open(my $pass, '>', $otuPassFile) or $logger->die("Unable to write $otuPassFile: $!");
+    open(my $fail, '>', $otuFailFile) or $logger->die("Unable to write $otuFailFile: $!");
     print $pass join("\t", '#OTU', @$libNames, 'Consensus lineage'), "\n";
     print $fail join("\t", '#OTU', @$libNames, 'Consensus lineage'), "\n";
     while ( my $queryLine = <$in> )
     close($pass);
     close($fail);
     unlink(@outFiles);
-    open (my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+    open (my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
     my $numClassified = sum(\@libPass);
     my $numUnclassified = sum(\@libFail);
     my $numClustered = $numClassified + $numUnclassified;
 sub _taxFilter
 {
     my ($config, $inFile, $outFile, $logFile, $libClassified) = @_;
-    $logger->logdie("Missing args") unless $config and $inFile and $outFile and $logFile and $libClassified;
+    $logger->die("Missing args") unless $config and $inFile and $outFile and $logFile and $libClassified;
     my $taxFilter = _set($config, 'RDP_CLASSIFIER', 'FILTER', undef);
     my $re;
     my @filter = split(/\|/, $taxFilter);
     foreach my $filter (@filter)
     {
-        $logger->logdie("Invalid filter string, $filter") unless $filter =~ /^[kpcofg]__\w+/i;
+        $logger->die("Invalid filter string, $filter") unless $filter =~ /^[kpcofg]__\w+/i;
     }
     $re = qr/^$taxFilter/i;
 
     my $numLibs = scalar(@$libClassified);
     my @libPass = my @libFail = ( (0) x $numLibs );
-    open(my $in, '<', $inFile) or $logger->logdie("Unable to read $inFile: $!");
-    open(my $out, '>', $outFile) or $logger->logdie("Unable to write $outFile: $!");
+    open(my $in, '<', $inFile) or $logger->die("Unable to read $inFile: $!");
+    open(my $out, '>', $outFile) or $logger->die("Unable to write $outFile: $!");
     my $line = <$in>;
     print $out $line; # header
     while ($line = <$in>)
         $libPassPct[$i] = $libClassified->[$i] ? int($libPass[$i]/$libClassified->[$i]*1000+0.5)/10 . '%' : 'N/A';
         $libFailPct[$i] = $libClassified->[$i] ? int($libFail[$i]/$libClassified->[$i]*1000+0.5)/10 . '%' : 'N/A';
     }
-    open(my $log, '>>', $logFile) or $logger->logdie("Unable to append $logFile: $!");
+    open(my $log, '>>', $logFile) or $logger->die("Unable to append $logFile: $!");
     print $log
         join("\t", 'TAX-FILTER PASS', _commify($totPass), map { _commify($_) } @libPass), "\n",
         join("\t", 'TAX-FILTER PASS PCT', $totPassPct, @libPassPct), "\n",
 {
     my ($cmd) = @_;
     my $output = `$cmd 2>&1`;
-    $logger->logdie("FAILURE RUNNING $cmd : $output") unless $? == 0;
+    $logger->die("FAILURE RUNNING $cmd : $output") unless $? == 0;
 }
 
 =item _set
 sub _set
 {
     my ($config, $part, $key, $default) = @_;
-    $logger->logdie("Missing args") unless $config and $part and $key;
+    $logger->die("Missing args") unless $config and $part and $key;
     unless ( exists($config->{$part}) )
     {
         return $default if $default;
-        $logger->logdie("Config file missing section, $part");
+        $logger->die("Config file missing section, $part");
     }
     if ( exists($config->{$part}->{$key}) ) { return $config->{$part}->{$key} } 
     elsif ( defined($default) ) { return $default }
-    else { $logger->logdie("Config missing required $part/$key") }
+    else { $logger->die("Config missing required $part/$key") }
 }
 
 =item _commify

File lib/iTagger/Logger.pm

+=pod
+
+=head1 NAME
+
+iTagger::Logger
+
+=head1 DESCRIPTION
+
+Logger class.  Currently wraps log4perl.  Persistent connections are not used because when many concurrent jobs are run, we may hit the db connection limit.  Consequently, connections are created for each logging event, so be brief.
+
+=head1 METHODS
+
+=cut
+
+package iTagger::Logger;
+
+use strict;
+use warnings;
+use Env qw(ITAGGER_LOG_CONFIG);
+use Log::Log4perl;
+
+our $VERSION = 1.3;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(new die warn error info debug);
+
+=head2 CONSTRUCTOR AND DESTRUCTOR
+
+=over 5
+
+=item new
+
+Constructor.  Config is either a hashref or the path to an .ini format file.
+
+=cut
+
+sub new
+{
+    my ($class, $loggerName, $loggerConfigFile) = @_;
+    die("Logger: logger name required\n") unless $loggerName;
+    my $this = \$loggerName;
+    bless $this, $class;
+    if ( $loggerConfigFile )
+    {
+        Log::Log4perl->init($loggerConfigFile);
+    } elsif ( $ITAGGER_LOG_CONFIG )
+    {
+        Log::Log4perl->init($ITAGGER_LOG_CONFIG);
+    } else
+    {
+        die("Logger: either log config file parameter or environment variable ITAGGER_LOG_CONFIG is required\n");
+    }
+    return $this;
+}
+
+=item _log
+
+Private method handles all logging events.
+
+=cut
+
+sub _log
+{
+    my ($this, $type, $msg) = @_;
+    if ( !defined($msg) ) { $msg = '' }
+    elsif ( $msg =~ /^(.*)\n+$/ ) { $msg = $1 }
+    my $logger = Log::Log4perl->get_logger($$this);
+    if ( $type eq 'die' ) { $logger->logdie($msg) }
+    elsif ( $type eq 'warn' ) { $logger->logwarn($msg) }
+    elsif ( $type eq 'error' ) { $logger->error($msg) }
+    elsif ( $type eq 'info' ) { $logger->info($msg) }
+    elsif ( $type eq 'debug' ) { $logger->debug($msg) }
+    else { $logger->logdie("Invalid log type, '$type', for message: $msg\n") }
+    Log::Log4perl->remove_logger($logger);
+}
+
+=item logdie
+
+Log fatal message and die.
+
+=cut
+
+sub die { shift->_log('die', @_) }
+
+=item logwarn
+
+Log fatal message and die.
+
+=cut
+
+sub warn { shift->_log('warn', @_) }
+
+=item error
+
+Log error message.
+
+=cut
+
+sub error { shift->_log('error', @_) }
+
+=item info
+
+Log info message.
+
+=cut
+
+sub info { shift->_log('info', @_) }
+
+=item debug
+
+Log debug message.
+
+=cut
+
+sub debug { shift->_log('debug', @_) }
+
+1;
+
+=back
+
+=head1 AUTHORS
+
+Edward Kirton, Julien Tremblay
+
+=head1 COPYRIGHT
+
+Copyright (c) 2013 US DOE Joint Genome Institute.  Use freely under the same license as Perl itself.  Refer to duk and flash documentation for their own copyright/license information.
+
+=cut

File lib/iTagger/QIIME.pm

 use strict;
 use warnings;
 use Env qw(TMPDIR);
-use Log::Log4perl;
 use Date::Format;
 use JSON;
 use File::Copy;
 use threads;
 require Exporter;
 use iTagger::Stats qw(trimmedStdDev);
+use iTagger::Logger qw(die warn info debug error);
 
 our $VERSION = 1.0;
 our @ISA = qw(Exporter);
 sub qiimeReport
 {
     my ($logConfigFile, $configFile, $dir) = @_;
-    die("Missing log config file\n") unless $logConfigFile;
-    Log::Log4perl->init($logConfigFile);
-    $logger = Log::Log4perl->get_logger('iTagger::QIIME');
-    $logger->logdie("Missing args") unless $configFile and $dir;
+    $logger = new iTagger::Logger('iTagger::QIIME', $logConfigFile);
+    $logger->die("Missing args") unless $configFile and $dir;
     my $start = time;
     my $config = Config::Tiny->read($configFile);
 
 {
     my ($cmd) = @_;
     my $output = `$cmd 2>&1`;
-    $logger->logdie("FAILURE RUNNING $cmd : $output") unless $? == 0;
+    $logger->die("FAILURE RUNNING $cmd : $output") unless $? == 0;
 }
 
 =item otuToBiom
 sub otuToBiom
 {
     my ($inFile, $outFile) = @_;
-    $logger->logdie("Missing args") unless $inFile and $outFile;
+    $logger->die("Missing args") unless $inFile and $outFile;
 
     # INIT JSON RECORD
     my $biom = 
     };
 
     # LIBRARIES
-    open ( my $in, '<', $inFile) or $logger->logdie($!);
+    open ( my $in, '<', $inFile) or $logger->die($!);
     my $hdr = <$in>;
     my @hdr = split(/\t/, $hdr);
     my @libs = @hdr[1..($#hdr-1)];
     $biom->{shape} = [ $numOtus, $numLibs ];
 
     # WRITE
-    open ( my $out, '>', $outFile) or $logger->logdie($!);
+    open ( my $out, '>', $outFile) or $logger->die($!);
     print $out to_json($biom);
     close($out);
 
     # CALCULATE CUTOFF OF RAREFACTION OF TRIMMED MEAN
     # (DISCARDING SMALLEST 5% AND LARGEST 5% OF VALUES)
     my ($trStDev, $mean) = trimmedStdDev(\@libSizes, 0.05);
-    $logger->logdie("Unable to calculate mean and stdev of trimmed lib sizes list") unless $mean;
+    $logger->die("Unable to calculate mean and stdev of trimmed lib sizes list") unless $mean;
     my $cutoff = 0;
     my $i = 2;
     while ( $cutoff <= 0 )
 sub filterOtuTable
 {
     my ($inFile, $outFile, $threshold, $frequency) = @_;
-    $logger->logdie("Missing args") unless $inFile and $outFile and $threshold and $frequency;
-	open(my $in, '<', $inFile) or $logger->logdie($!);
-	open(my $out, '>', $outFile) or $logger->logdie($!);
+    $logger->die("Missing args") unless $inFile and $outFile and $threshold and $frequency;
+	open(my $in, '<', $inFile) or $logger->die($!);
+	open(my $out, '>', $outFile) or $logger->die($!);
     my $line = <$in>;
     print $out $line;
 	while( my $line = <$in> )
 sub abundanceThreshold
 {
     my ($inFile, $outDir) = @_;
-    $logger->logdie("Missing args") unless $inFile and $outDir;
+    $logger->die("Missing args") unless $inFile and $outDir;
 
     # LOAD OTUS, CALC LIB SIZES
     my @otus = ();
     my @sizes = ();
     my $total = 0;
-    open(my $in, '<', $inFile) or $logger->logdie($!);
+    open(my $in, '<', $inFile) or $logger->die($!);
     my $hdr = <$in>;
-    $logger->logdie("Invalid OTU file") unless $hdr =~ /^#/;
+    $logger->die("Invalid OTU file") unless $hdr =~ /^#/;
     while (<$in>)
     {
         push @otus, $_;
 
     # OUTPUT FILTERED OTU TABLES
     # keep only OTUs having abundance higher than xx%
-    -d $outDir or mkdir($outDir) or $logger->logdie($!);
+    -d $outDir or mkdir($outDir) or $logger->die($!);
     my @thresholds = (1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1);
     my @otuFiles = map { "$outDir/otu.$_.tsv" } @thresholds;
     my @biomFiles = map { "$outDir/otu.$_.biom" } @thresholds;
     my @fhs;
     foreach my $otuFile (@otuFiles)
     {
-        open(my $fh, '>', $otuFile) or $logger->logdie($!);
+        open(my $fh, '>', $otuFile) or $logger->die($!);
         print $fh $hdr;
         push @fhs, $fh;
     }
     for (my $i=0; $i<=$#thresholds; $i++)
     {
         ## Check if OTU table is empty.
-        open(my $in, '<', $otuFiles[$i]) or $logger->logdie($!);
+        open(my $in, '<', $otuFiles[$i]) or $logger->die($!);
         my $ok = -1;
         while (<$in>) { last if ++$ok }
         close($in);
     my ($inFile, $outFile) = @_;
     _run("alpha_diversity.py -i $inFile -o $outFile -m chao1,observed_species,shannon,simpson");
     # REFORMAT HEADER LINE
-    open(my $in, '<', $outFile) or $logger->logdie("Unable to open $outFile: $!");
-    open(my $out, '>', "$outFile.tmp") or $logger->logdie($!);
+    open(my $in, '<', $outFile) or $logger->die("Unable to open $outFile: $!");
+    open(my $out, '>', "$outFile.tmp") or $logger->die($!);
     print $out "#Sample\tchao1\tobserved_species\tshannon\tsimpson\n";
     my $head = <$in>;
     while (<$in>) { print $out $_ }
 sub _set
 {
     my ($config, $part, $key, $default) = @_;
-    $logger->logdie("Missing args") unless $config and $part and $key;
+    $logger->die("Missing args") unless $config and $part and $key;
     if ( !exists($config->{$part}) )
     {
         $config->{$part} = {};
         return $config->{$part}->{$key} = $default if defined($default);
-        $logger->logdie("Config file missing section, $part");
+        $logger->die("Config file missing section, $part");
     } elsif ( exists($config->{$part}->{$key}) )
     {
         return $config->{$part}->{$key}
         return $config->{$part}->{$key} = $default;
     } else
     {
-        $logger->logdie("Config missing required $part/$key");
+        $logger->die("Config missing required $part/$key");
     }
 }
 
 sub calcMinDepths
 {
     my ($inFile, $pctAR) = @_;
-    $logger->logdie("Missing args") unless $inFile and @$pctAR;
+    $logger->die("Missing args") unless $inFile and @$pctAR;
     # CALC TOTAL SIZE
-    open( my $in, '<', $inFile ) or $logger->logdie("Can't open file, $inFile: $!");
+    open( my $in, '<', $inFile ) or $logger->die("Can't open file, $inFile: $!");
     my $hdr = <$in>;
     my @sizes = ();
     my $totSize = 0;
         $totSize += $size;
     }
     close($in);
-    $logger->logdie("Empty infile") unless $totSize;
+    $logger->die("Empty infile") unless $totSize;
     # CALC MIN DEPTHS
     my $sum = 0;
     my $minDepth;