lib/Log/Abstraction/Backend.pm

Structural Coverage (Approximate)

TER1 (Statement): 100.00%
TER2 (Branch): 100.00%
TER3 (LCSAJ): -
Approximate LCSAJ segments: 5

LCSAJ Legend

● Covered — this LCSAJ path was executed during testing.

● Not covered — this LCSAJ path was never executed. These are the paths to focus on.

Multiple dots on a line indicate that multiple control-flow paths begin at that line. Hovering over any dot shows:

        start → end → jump
        

Uncovered paths show [NOT COVERED] in the tooltip.

Mutant Testing Legend

Survived (tests missed this) Killed (tests detected this) No mutation
    1: package Log::Abstraction::Backend;
    2: 
    3: # Base class of the backends that Log::Abstraction sends messages to
    4: use strict;
    5: use warnings;
    6: 
    7: use Carp ();
    8: 
    9: our $VERSION = '0.40';
   10: 
   11: # Carp and croak from a backend report the code that called Log::Abstraction,
   12: # not Log::Abstraction itself.  The subclasses trust this package through
   13: # @ISA, and so Log::Abstraction too
   14: our @CARP_NOT = ('Log::Abstraction');
   15: 
   16: # True while a message is being handed to Log::Any or Log::Dispatch.  If that
   17: # brings it back to a Log::Abstraction (e.g. through
   18: # Log::Any::Adapter::Abstraction), it isn't forwarded again, which would
   19: # loop.  Set with local by the log_any and log_dispatch backends, and read by
   20: # Log::Abstraction::_log to find the original caller
   21: our $FORWARDING = 0;
   22: 
   23: =head1 NAME
   24: 
   25: Log::Abstraction::Backend - base class of the Log::Abstraction backends
   26: 
   27: =head1 VERSION
   28: 
   29: 0.40
   30: 
   31: =head1 DESCRIPTION
   32: 
   33: For use by L<Log::Abstraction> only.  C<Log::Abstraction-E<gt>new()> builds
   34: one object of a C<Log::Abstraction::Backend::*> class for each place a
   35: message goes to (a file, an array, syslog ...), and each message is passed to
   36: every one of them.  The configuration given to C<new()> is not changed.
   37: 
   38: The backends are:
   39: 
   40:   Log::Abstraction::Backend::Array        array, or logger => \@array
   41:   Log::Abstraction::Backend::Code         logger => \&code
   42:   Log::Abstraction::Backend::Fd           fd
   43:   Log::Abstraction::Backend::File         file, or logger => $path
   44:   Log::Abstraction::Backend::Journald     journald
   45:   Log::Abstraction::Backend::LogAny       log_any, or a Log::Any logger
   46:   Log::Abstraction::Backend::LogDispatch  log_dispatch, or a Log::Dispatch object
   47:   Log::Abstraction::Backend::Object       any other object as the logger
   48:   Log::Abstraction::Backend::Sendmail     sendmail
   49:   Log::Abstraction::Backend::Syslog       syslog
   50: 
   51: =head1 METHODS
   52: 
   53: =head2 new
   54: 
   55:   my $backend = Log::Abstraction::Backend::File->new(
   56:       file   => $path,
   57:       level  => 4,        # numeric threshold, or undef for none
   58:       format => $format,  # or undef
   59:   );
   60: 
   61: Stores its arguments.  They have already been checked by
   62: C<Log::Abstraction-E<gt>new()>; C<level> is a syslog number (0-7).
   63: 
   64: =head3 API SPECIFICATION
   65: 
   66: =head4 Input
   67: 
   68:   {
   69:       level  => { type => 'integer', min => 0, max => 7, optional => 1 },
   70:       format => { type => 'string', min => 1, optional => 1 },
   71:       # and the destination, under the backend's own key (file, fd,
   72:       # array, sendmail ...)
   73:   }
   74: 
   75: =head4 Output
   76: 
   77:   { type => 'object', isa => 'Log::Abstraction::Backend' }
   78: 
   79: =cut
   80: 
   81: sub new {
   82: 	my ($class, %args) = @_;
   83: 
   84: 	return bless { %args }, $class;

Mutants (Total: 2, Killed: 2, Survived: 0)

85: } 86: 87: =head2 wants 88: 89: next unless $backend->wants($event); 90: 91: True if the backend has no level of its own, or the message is at that level 92: or more severe. 93: 94: =head3 API SPECIFICATION 95: 96: =head4 Input 97: 98: { event => { type => 'hashref', schema => { priority => { type => 'integer', min => 0, max => 7 } } } } 99: 100: =head4 Output 101: 102: { type => 'boolean' } 103: 104: =cut 105: 106: sub wants { 107: my ($self, $event) = @_; 108: 109: return 1 unless(defined($self->{'level'}));

Mutants (Total: 2, Killed: 2, Survived: 0)

110: return $event->{'priority'} <= $self->{'level'};

Mutants (Total: 5, Killed: 5, Survived: 0)

111: } 112: 113: =head2 text 114: 115: my $message = $backend->text($event, $event->{text}); 116: 117: The message formatted with the backend's own C<format>, if it has one, 118: otherwise the default given. 119: 120: =head3 API SPECIFICATION 121: 122: =head4 Input 123: 124: { 125: event => { type => 'hashref', schema => { render => { type => 'coderef' } } }, 126: default => { type => 'string' }, 127: } 128: 129: =head4 Output 130: 131: { type => 'string' } 132: 133: =cut 134: 135: sub text { 136: my ($self, $event, $default) = @_; 137: 138: return defined($self->{'format'}) ? $event->{'render'}->($self->{'format'}) : $default;

Mutants (Total: 2, Killed: 2, Survived: 0)

139: } 140: 141: =head2 emit 142: 143: $backend->emit($logger, $event); 144: 145: Sends a message, which has passed the logger's level, to the backend. 146: C<$logger> is the C<Log::Abstraction> object. C<$event> is a hash 147: reference built by C<Log::Abstraction> for each message: 148: 149: level the level name, e.g. 'warn' 150: priority its syslog number (0-7) 151: message the message, its parts joined and redacted 152: parts the message's parts (an array reference) 153: fields the structured fields (a hash reference), or undef 154: fields_text the fields as key=value text, or undef 155: text the message with fields_text appended 156: entry the history entry (a list, as an array reference) 157: class, file, line, ctx for CODE references 158: render format a line: $event->{render}->($format), undef for 159: the logger's format 160: write write a line to a path (which it checks) or a handle: 161: $event->{write}->($target, $line) 162: send_email, hold_email send or keep for later an email: 163: $event->{send_email}->(\%sendmail, $body) 164: 165: The closures are how a backend uses Log::Abstraction's private methods. 166: Subclasses must override this. 167: 168: =head3 API SPECIFICATION 169: 170: =head4 Input 171: 172: { 173: logger => { type => 'object', isa => 'Log::Abstraction' }, 174: event => { type => 'hashref' }, # the keys above 175: } 176: 177: =head4 Output 178: 179: None. The base class's emit() croaks "<class>: emit() is not 180: implemented"; a subclass's sends the message. A failed delivery is 181: carped, not fatal; a configuration error (e.g. an invalid sendmail 182: host) still croaks. 183: 184: =cut 185: 186: sub emit { 187: my $self = shift; 188: 189: Carp::croak(ref($self), ': emit() is not implemented'); 190: } 191: 192: =head1 AUTHOR 193: 194: Nigel Horne C<njh@nigelhorne.com> 195: 196: =head1 SEE ALSO 197: 198: L<Log::Abstraction> 199: 200: =head1 COPYRIGHT AND LICENSE 201: 202: Copyright (C) 2025-2026 Nigel Horne 203: 204: Usage is subject to the GPL2 licence terms. 205: If you use it, 206: please let me know. 207: 208: =cut 209: 210: 1;