TER1 (Statement): 100.00%
TER2 (Branch): 100.00%
TER3 (LCSAJ): -
Approximate LCSAJ segments: 5
● 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.
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;