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 )