All pastes #950664 Raw Edit

Miscellany

public text v1 · immutable
·published 2008-03-20 19:22 UTC
rendered paste body
################################################################################
#                                                                              #
#   ########################################################################   #
# # Title       : Data::Logger.pm                                            # #
# # Description : A super simple logger, you don't actually need to tell it  # #
# #               a single thing.                                            # #
# # Coded by    : Justin "I'm Really Tired Now" Lee                          # #
# # Version     : 0.7.0-PRE                                                  # #
# # Date        : Monday, March 10, 2008                                     # #
# # License     : GNU General Public License v.2                             # #
# #               Copyright (C) 2008  Justin Lee  <kool.name at gmail.com>   # #
#   ########################################################################   #
#                                                                              #
#   ########################################################################   #
# # This program is free software; you can redistribute it and/or            # #
# # modify it under the terms of the GNU General Public License version 2    # #
# # as published by the Free Software Foundation.                            # #
# #                                                                          # #
# # This program is distributed in the hope that it will be useful,          # #
# # but WITHOUT ANY WARRANTY; without even the implied warranty of           # #
# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            # #
# # GNU General Public License for more details.                             # #
# #                                                                          # #
# # You should have received a copy of the GNU General Public License        # #
# # along with this program; if not, write to the Free Software              # #
# # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA            # #
# # 02110-1301, USA.  Or, see: <http://www.gnu.org/licenses/>                # #
#   ########################################################################   #
#                                                                              #
################################################################################



   ###############################
  ## ########################
###### MODULE PREAMBLE

package Data::Logger;

use strict;
use warnings;
use subs qw( skew );

use Carp;
use Deans::Functions qw( skew housekeep );
use FileHandle;
use File::Basename;
use File::Find;
use Class::Date qw(now);



   ##########################################
  ## ###################################
###### `GLOBAL' VARIABLES AND CONSTANTS

use constant {
  DEFAULT_LEVEL => 2,
  DEFAULT_STRING => '\\[%h:%m:%s\\] [(%F)] %L:[ %A]'
};

my @LVL = ( # now with less evil
  '^one|first|(?:warn(?:ing)?|err(?:(?:o|0)r)?|fatal|d(?:ie|eath))(?:s|z)?|1$',
  '^(?:log(?:ging)?|noted?|info(?:rmation))(?:s|z)?|second|two|2$',
  '^third|debug(?:g?(?:er|ing))?(?:s|z)?|all|three|3$'
};

my @ORD = qw(
  MSG
  LVL
  ERR
  FNC
);



   ###############################
  ## ########################
###### START OF THE OBJECT INTERFACE

sub new {
  my ($class,$config) = @_;

  my $log = {
    _setup($config,(caller));
  };

  return if exists $log->{ERR};
  return bless $log, $class;
}



   ###############################
  ## ########################
###### THE _SETUP FUNCTIONZ

sub _stp_mode {
  my ($stp) = @_;
  if (exists $stp->{Explicit} and $stp->{Explicit}) {
    return 1;
  } else {
    return 0;
  }
}

sub _stp_level {
  my ($stp) = @_;
  if (defined $stp->{Level}) {
    for (my $i = 0; $i < $#LVL; $i++) {
      return $i if $stp->{Level} =~ /$LVL[$i]/i;
    }
  }

  return if _stp_mode($stp); #explicit

  return DEFAULT_LEVEL;
}

sub _stp_string {
  my ($stp) = @_;
  return _charachangi($stp->{String}) if defined $stp->{String};

  return if _stp_mode($stp); #explicit

  return DEFAULT_STRING;
}

sub _stp_path {
  my ($stp,$tok) = @_;
  if (not defined $stp->{Path}) {
    return if _stp_mode($stp); #explicit

    $stp->{Path} = DEFAULT_dir;
    mkdir($stp->{Path},0777) or return;
  }
  if (defined $stp->{Dated}) {
    $stp->{Path} = skew $stp->{Path}, decode('%Y-%M-%D',$tok);
    mkdir($stp->{Path},0777) or return;
  }

  return $stp->{Path} if -d $stp->{Path};
  return;
}

sub _stp_clean_house {
  my ($stp,$dir) = @_;
  if (defined $stp->{Keep}) {
    return unless housekeep(
      $dir,
      int($stp->{Keep}), # I don't even trust my mom.
      _stp_mode($stp)
    );
  }

  return 1;
}

sub _stp_tokens {
  my ($stp) = @_;
  my $tok = _have_a_toke_man();

  if (defined $stp->{Functional}) {
    $tok->{F}->{toe} = 1;
  }
  if (defined $stp->{Title}) {
    $tok->{
}

sub _setup {
  my ($stp,@caller) = @_;

  unless (defined $stp) { $stp = {}; }
  unless (ref $stp eq 'HASH') { return _throw_error('STP','Hash'); }

  my %log;
  $log->{Handle}   = new FileHandle;
  $log->{Level}    = _stp_level($stp);
  $log->{String}   = _stp_string($stp);
  $log->{Token}    = _stp_tokens($stp);
  $log->{Path}     = _stp_path($stp,$log->{Token});
  $log->{Explicit} = _stp_mode($stp);

  $log->{Handle}->open($log->{Path},'>');

  defined $_->[0] or _throw_error(@{$_->[1]}) foreach (
    [$log->{Level},    ['STP','Level']],
    [$log->{String},   ['STP','String']],
    [$log->{Path},     ['STP','Path']],
    [$log->{Handle},   ['STP','Handle']],
    [_stp_clean($stp,$log->{Path}),
                       ['STP','Clean']]
  );

  undef $stp;
  return %log;
}



   ###############################
  ## ########################
###### TOKEN FUNCTIONS

sub _deblock {
  my ($str) = @_;
  while ($str =~ s/\[([^\[\]]*)\]/\%0/o) {
    my $blk = $1;
    if ($blk =~ /\%([^\d])/o) {
      my $wtf = _gettoke($1);
      if ($wtf and $wtf ne '?') {
        $str =~ s/\%0/$blk/;
        next;
      }
    } else {
      $str =~ s/\%0//o;
    }
  }

  return $str;
}

sub _detoke {
  my ($str) = @_;
  $str =~ s/\%(.)/_gettoke($1)/ge;
  return $str;
}

sub _gettoke {
  my ($log,$tak) = @_;
  my $tik = $log->{token};
  if (exists $tik->{$tak} and $tik->{$tak}->{toe}) { # exists & active
    if (defined $tik->{$tok}->{val}) { # defined
      if (ref $tik->{$tok}->{val} eq 'CODE') {
        return &{$tik->{$tok}->{val}};
      } else {
        return $tik->{$tok}->{val};
      }
    } else {
      return '?'; # active, but no value (suggests problem)
    }
  } else {
    return ''; # doesn't exist or not active
  }
}

sub _charachangi {
  my ($str) = @_;
  $str =~ s/\\\\/\%1/og;
  $str =~ s/\\\%/\%2/og;
  $str =~ s/\\\[/\%3/og;
  $str =~ s/\\\]/\%4/og;
  return $str;
}



   #################################
  ## ##########################
###### STUFF THAT BUILDS STUFF

sub _mk_hash {
  return $_[0] if ref $_[0] eq 'HASH';
  return {
    MSG => $_[0], 
    LVL => $_[1],
    ERR => $_[2],
    FNC => $_[3]
  };
}

sub _mk_dt_obj_thg {
  my ($gm) = @_;
  return unless defined $gm;
  return sub {
    my %dt;
    @dt{
      qw( year
          month
          day
          hour
          minute
          second )
    } = split(/(?:\s|:|-|;)+/,now);

    return scalar $dt{lc($gm)};
  }
}



   ###############################
  ## ########################
###### CORE LOGGING FUNCTIONS

sub print {
  my ($log,@tik) = @_;
  $log = $log->update($tik);
}

sub decode {
  my ($log,$str) = @_;
  $str = _deblock($log,$str);
  $str = _detoke($log,$str);
  return $str;
}

sub update {
  my ($log,@tik) = @_;
  if (ref $tik[0] eq 'HASH') {
    $log = $log->_update_tokens(map {
      exists $tik[0]->{$_} ? $tik[0]->{$_} : undef
    } @ORD);
  } else {
    $log = $log->_update_tokens(@tik)
  }

  $log or return;
  return $log;
}



   ###############################
  ## ########################
###### OBJECT FUNCTION ALIASES

sub LOGPRINT { shift->print    (@_); }
sub LOGDEBUG { shift->print(_mk_hash('DEBUG',@_)) }
sub LOGDIE   { shift->print(_mk_hash('FATAL',@_)) }
sub LOGWARN  { shift->print(_mk_hash('WARNING',@_)) }
sub LOGNOTE  { shift->print(_mk_hash('INFO',@_)) }
sub raw      { shift->print    (@_); }
sub log      { shift->LOGNOTE  (@_); }
sub die      { shift->LOGDIE   (@_); }
sub warn     { shift->LOGWARN  (@_); }
sub close    { shift->LOGCLOSE (@_); }
sub debug    { shift->LOGDEBUG (@_); }
sub note     { shift->LOGNOTE  (@_); }
sub DEBUG    { shift->LOGDEBUG (@_); }
sub WARN     { shift->LOGWARN  (@_); }
sub DIE      { shift->LOGDIE   (@_); }
sub LOG      { shift->LOGNOTE  (@_); }
sub NOTE     { shift->LOGNOTE  (@_); }
sub PRINT    { shift->print    (@_); }
 # add yer own!!! PARRTYYYYYY!!



   ###############################
  ## ########################
###### REALLY LONG FUNCTIONS

sub _have_a_toke_man {
  return (
    A => { # message
      val => '',
      toe => 1
    },
    F => { # function title
      val => '',
      toe => 0
    },
    T => { # script name
      val => '',
      toe => 1
    },
    L => { # log level
      val => '',
      toe => 1
    },
    Y => {
      val => _mk_dt_obj_thg('year'),
      toe => 1
    },
    M => {
      val => _mk_dt_obj_thg('month'),
      toe => 1
    },
    LETS_GET_DRUGS => {
      val => 'lets get drugs!',
      toe => 0
    },
    D => {
      val => _mk_dt_obj_thg('day'),
      toe => 1
    },
    h => {
      val => _mk_dt_obj_thg('hour'),
      toe => 1
    },
    m => {
      val => _mk_dt_obj_thg('minute'),
      toe => 1
    },
    s => {
      val => _mk_dt_obj_thg('second'),
      toe => 1
    },
  );
}



 #####################
 # ##############
 ### ONE!!!1 ... 

1;