Log-Abstraction
view release on metacpan or search on metacpan
lib/Log/Abstraction.pm view on Meta::CPAN
# RETURN early if syslog_values{level} > self->{'level'} (below threshold)
#
# Flatten single-arrayref argument to a list; filter out undefs; join to $str
# Push { level, message } onto self->{messages} (always recorded)
# Set $class = '' for base package, else the blessed class name
#
# IF self->{'logger'} is a CODE ref:
# Build args hashref { class, file, line, level, message, ctx? }
# Call logger->( args )
#
# ELSIF self->{'logger'} is an ARRAY ref:
# Push { level, message }
#
# ELSIF self->{'logger'} is a HASH ref:
# IF 'file' key present:
# validate path; format line; (eval) open>>file, print, close
# IF 'array' key present:
# push { level, message }
# IF 'sendmail' key present with a 'to' address:
# IF level passes threshold AND not throttled:
# CROAK if host contains unsafe characters
# CROAK if port is out of 1-65535 range
# (eval) load Email::* modules; build email with sanitised headers;
# send via SMTP transport; carp on delivery failure
# Record timestamp for throttle
# IF 'syslog' key present:
# IF level passes threshold:
# Open syslog connection on first use (setlogsock, openlog)
# (eval) map level to syslog priority; call Sys::Syslog::syslog;
# carp with Data::Dumper output on failure
# IF 'journald' key present:
# Map level to syslog PRIORITY integer
# Build fields: MESSAGE, PRIORITY, SYSLOG_IDENTIFIER, plus any extra
# (eval) _journald_send(socket_path, %fields); carp on failure
# IF 'fd' key present:
# Format line; print to filehandle
# ELSIF no actionable key (no file/array/syslog/sendmail/journald/fd):
# CROAK (configuration error)
#
# ELSIF self->{'logger'} is an unblessed scalar (file path):
# Validate path; format line; (eval) open>>file, print, close
#
# ELSIF self->{'logger'} is a blessed object:
# Map 'notice' to 'info' for backends without notice() (e.g. Log::Log4perl)
# CROAK if object cannot handle the level
# Call $logger->$level(@messages)
#
# ELSIF self->{'array'} top-level key:
# Push { level, message }
#
# IF self->{'file'} top-level key:
# Validate path; format line; (eval) open>>file, print, close
# IF self->{'fd'} top-level key:
# Format line; print to filehandle
# END FUNCTION
# ---------------------------------------------------------------------------
sub _log :Private {
my ($self, $level, @messages) = @_;
# Reject direct calls from outside this package (also enforced by :Private)
if(!(caller)[0]->isa(__PACKAGE__)) {
Carp::croak('Illegal Operation: _log is a private method');
}
# Sanity-check the level (should not be reachable in normal use)
if(!defined($syslog_values{$level})) {
Carp::croak(ref($self), ": Invalid level '$level'");
}
# Drop messages that fall below the configured threshold
if($syslog_values{$level} > $self->{'level'}) {
return;
}
# Flatten a single arrayref argument to a plain list
if((scalar(@messages) == 1) && (ref($messages[0]) eq 'ARRAY')) {
@messages = @{$messages[0]};
}
# Remove any undef elements before joining
@messages = grep { defined } @messages;
my $str = join('', @messages);
chomp($str);
# Record in the internal message history regardless of backend
push @{$self->{messages}}, { level => $level, message => $str };
# Compute class once; suppress the package name for base-class instances
my $class = blessed($self) || $self;
if($class eq __PACKAGE__) {
$class = '';
}
# Resolve caller file/line at the correct stack depth.
# For trace/debug/info/notice: _log â public_method â user â depth=1
# For warn/error: _log â _high_priority â public_method â user â depth=2
my $depth = ((caller(1))[3] // '') =~ /::_high_priority$/ ? 2 : 1;
my $caller_file = (caller($depth))[1];
my $caller_line = (caller($depth))[2];
# -----------------------------------------------------------------------
# Dispatch to the configured backend(s)
# -----------------------------------------------------------------------
if(my $logger = $self->{'logger'}) {
if(ref($logger) eq 'CODE') {
# CODE-ref backend: build the args hashref and invoke the callback
my $args = {
class => blessed($self) || __PACKAGE__,
file => $caller_file,
line => $caller_line,
level => $level,
message => \@messages,
};
if(my $ctx = $self->{ctx}) {
$args->{ctx} = $ctx;
}
$logger->($args);
} elsif(ref($logger) eq 'ARRAY') {
# ARRAY-ref backend: push a simple hashref
push @{$logger}, { level => $level, message => $str };
} elsif(ref($logger) eq 'HASH') {
( run in 2.075 seconds using v1.01-cache-2.11-cpan-b16cb0d3907 )