################################################################################
# #
# ############################################################################ #
# # 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;
our(@ISA,@EXPORT_OK);
BEGIN {
use subs qw(skew); #undouchify constant
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw( skew );
}
use Carp;
use FileHandle;
use File::Basename;
use File::Find;
use Class::Date qw(now);
################################
# #########################
### CONSTANTS AND DEFAULTS
# Eventually break these off into Data::Logger::Const?
use constant { #caller info
CALLER_ttl => basename($main::0),
CALLER_dir => skew(@{[ fileparse($main::0) ]}[1])
};
use constant { #defaults
DEFAULT_dir => skew(@{[ fileparse($main::0) ]}[1], 'logs'),
DEFAULT_lvl => 2,
DEFAULT_str => '\\[%h:%m:%s\\] (%L) -[ %A][ %E]',
};
use constant { #levels
LEVEL_err => 'one|first|(?:warn(?:ing)?|fatal|d(?:ie|eath))(?:s|z)?|1', #icanhazlogz?
LEVEL_log => '(?:log(?:ging)?|noted?|info(?:rmation))(?:s|z)?|second|two|2',
LEVEL_all => 'third|debug(?:g?(?:er|ing))?(?:s|z)?|all|three|3'
};
#######################################
# ################################
### START OF THE OBJECT INTERFACE
# Find a way to return _setup()'s ERR messages.
sub new {
my ($class,$config) = @_;
my $log = { _setup($config) };
return if exists $log->{ERR};
return bless $log, $class;
}
##############################
# #######################
### THE _SETUP FUNCTIONZ
sub _stp_mode {
my ($stp) = @_;
if (defined $stp->{Explicit}) {
return 1;
} else {
return 0;
}
}
sub _stp_level {
my ($stp) = @_;
if (defined $stp->{Level}) {
foreach my $gex (LEVEL_err,LEVEL_log,LEVEL_all) {
return chop($gex) if $level =~ /^$gex$/i; # this is an example of evil magic
}
}
return if _stp_mode($stp); #explicit
return DEFAULT_lvl;
}
sub _stp_string {
my ($stp) = @_;
return _charachangi($stp->{String}) if defined $stp->{String};
return if _stp_mode($stp); #explicit
return DEFAULT_str;
}
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; #fail
}
if (defined $stp->{Dated}) {
$stp->{Path} = skew $stp->{Path}, decode('%Y-%M-%D',$tok);
mkdir($stp->{Path},0777) or return; #fail
}
return $stp->{Path} if -d $stp->{Path};
return; #fail
}
sub _stp_clean_house {
my ($stp) = @_;
}
sub _setup {
my ($stp) = @_;
unless (defined $stp) { $stp = {}; }
unless (ref $stp eq 'HASH') { return _throw_error('STP','Hash'); }
my %log;
$log->{Level} = _stp_level($stp);
$log->{String} = _stp_string($stp);
$log->{Token} = { _have_a_toke_man() };
$log->{Path} = _stp_path($stp,$log->{Token});
$log->{Handle} = new FileHandle;
$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),['STP','Clean']]
);
return %log;
}
##################################
# ###########################
### RANDOM AWESOME FUNCTIONS
sub skew { #murder stupid paths
my $skew = join('/',@_);
$skew =~ s/(?:\\|\/)+/\//go;
return $skew;
}
sub housekeep { #clean out logs
my ($dir,$keep,$bydate) = @_;
my @logs;
find(
{
no_chdir => 1,
wanted => sub {
return if -d $_;
push(@logs,$_) if /\.log$/oi;
},
},
$dir
);
unlink($_) or return foreach splice(@logs,0,0-$keep);
return 1;
}
#########################
# ##################
### TOKEN FUNCTIONS
sub decode {
my ($log,$str) = @_;
$str = _deblock($log,$str);
$str = _detoke($log,$str);
return $str;
}
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 ($tak) = @_;
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;
}
sub _update_tokens {
my ($tok) = @_;
}
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)};
}
}
sub last {
my ($log) = @_;
local ($tik) = $log->{token};
my %LST = (
'ERR' => _gettoke('E'),
'MSG' => _gettoke('A'),
'LVL' => _gettoke('L')
);
}
sub reset {
}
################################
# #########################
### CORE LOGGING FUNCTIONS
sub print {
my ($log,$tik) = @_;
$log->update($tik);
$log->{token} = _update_tokens(shift);
}
##########################
# ###################
### OBJECT FUNCTIONS
sub LOGCLOSE {
my ($log) = @_;
}
sub LOGNOTE {
my ($log) = @_;
}
sub LOGDEBUG {
my ($log) = @_;
}
sub LOGWARN {
my ($log) = @_;
}
sub LOGDIE {
my ($log) = @_;
}
#################################
# ##########################
### OBJECT FUNCTION ALIASES
sub LOGPRINT { shift->print (@_); }
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
},
S => { # script name
val => basename($main::0), #'super cool script.pl', #'fake name',
toe => 1
},
L => { # log level
val => '',
toe => 1
},
E => { # error message
val => '',
toe => 0
},
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;