File Coverage

File:blib/lib/Log/Abstraction/Backend.pm
Coverage:100.0%

linestmtbrancondsubtimecode
1package Log::Abstraction::Backend;
2
3# Base class of the backends that Log::Abstraction sends messages to
4
37
37
37
139
22
175
use strict;
5
37
37
37
28
24
386
use warnings;
6
7
37
37
37
31
16
2374
use Carp ();
8
9our $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
14our @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
21our $FORWARDING = 0;
22
23 - 79
=head1 NAME

Log::Abstraction::Backend - base class of the Log::Abstraction backends

=head1 VERSION

0.40

=head1 DESCRIPTION

For use by L<Log::Abstraction> only.  C<Log::Abstraction-E<gt>new()> builds
one object of a C<Log::Abstraction::Backend::*> class for each place a
message goes to (a file, an array, syslog ...), and each message is passed to
every one of them.  The configuration given to C<new()> is not changed.

The backends are:

  Log::Abstraction::Backend::Array        array, or logger => \@array
  Log::Abstraction::Backend::Code         logger => \&code
  Log::Abstraction::Backend::Fd           fd
  Log::Abstraction::Backend::File         file, or logger => $path
  Log::Abstraction::Backend::Journald     journald
  Log::Abstraction::Backend::LogAny       log_any, or a Log::Any logger
  Log::Abstraction::Backend::LogDispatch  log_dispatch, or a Log::Dispatch object
  Log::Abstraction::Backend::Object       any other object as the logger
  Log::Abstraction::Backend::Sendmail     sendmail
  Log::Abstraction::Backend::Syslog       syslog

=head1 METHODS

=head2 new

  my $backend = Log::Abstraction::Backend::File->new(
      file   => $path,
      level  => 4,        # numeric threshold, or undef for none
      format => $format,  # or undef
  );

Stores its arguments.  They have already been checked by
C<Log::Abstraction-E<gt>new()>; C<level> is a syslog number (0-7).

=head3 API SPECIFICATION

=head4 Input

  {
      level  => { type => 'integer', min => 0, max => 7, optional => 1 },
      format => { type => 'string', min => 1, optional => 1 },
      # and the destination, under the backend's own key (file, fd,
      # array, sendmail ...)
  }

=head4 Output

  { type => 'object', isa => 'Log::Abstraction::Backend' }

=cut
80
81sub new {
82
1743
5253
        my ($class, %args) = @_;
83
84
1743
1963
        return bless { %args }, $class;
85}
86
87 - 104
=head2 wants

  next unless $backend->wants($event);

True if the backend has no level of its own, or the message is at that level
or more severe.

=head3 API SPECIFICATION

=head4 Input

  { event => { type => 'hashref', schema => { priority => { type => 'integer', min => 0, max => 7 } } } }

=head4 Output

  { type => 'boolean' }

=cut
105
106sub wants {
107
11025
4415
        my ($self, $event) = @_;
108
109
11025
9044
        return 1 unless(defined($self->{'level'}));
110
56
149
        return $event->{'priority'} <= $self->{'level'};
111}
112
113 - 133
=head2 text

  my $message = $backend->text($event, $event->{text});

The message formatted with the backend's own C<format>, if it has one,
otherwise the default given.

=head3 API SPECIFICATION

=head4 Input

  {
      event   => { type => 'hashref', schema => { render => { type => 'coderef' } } },
      default => { type => 'string' },
  }

=head4 Output

  { type => 'string' }

=cut
134
135sub text {
136
86
64
        my ($self, $event, $default) = @_;
137
138
86
108
        return defined($self->{'format'}) ? $event->{'render'}->($self->{'format'}) : $default;
139}
140
141 - 184
=head2 emit

  $backend->emit($logger, $event);

Sends a message, which has passed the logger's level, to the backend.
C<$logger> is the C<Log::Abstraction> object.  C<$event> is a hash
reference built by C<Log::Abstraction> for each message:

  level        the level name, e.g. 'warn'
  priority     its syslog number (0-7)
  message      the message, its parts joined and redacted
  parts        the message's parts (an array reference)
  fields       the structured fields (a hash reference), or undef
  fields_text  the fields as key=value text, or undef
  text         the message with fields_text appended
  entry        the history entry (a list, as an array reference)
  class, file, line, ctx   for CODE references
  render       format a line: $event->{render}->($format), undef for
               the logger's format
  write        write a line to a path (which it checks) or a handle:
               $event->{write}->($target, $line)
  send_email, hold_email   send or keep for later an email:
               $event->{send_email}->(\%sendmail, $body)

The closures are how a backend uses Log::Abstraction's private methods.
Subclasses must override this.

=head3 API SPECIFICATION

=head4 Input

  {
      logger => { type => 'object', isa => 'Log::Abstraction' },
      event  => { type => 'hashref' },    # the keys above
  }

=head4 Output

  None.  The base class's emit() croaks "<class>: emit() is not
  implemented"; a subclass's sends the message.  A failed delivery is
  carped, not fatal; a configuration error (e.g. an invalid sendmail
  host) still croaks.

=cut
185
186sub emit {
187
1
1
        my $self = shift;
188
189
1
6
        Carp::croak(ref($self), ': emit() is not implemented');
190}
191
192 - 208
=head1 AUTHOR

Nigel Horne C<njh@nigelhorne.com>

=head1 SEE ALSO

L<Log::Abstraction>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2025-2026 Nigel Horne

Usage is subject to the GPL2 licence terms.
If you use it,
please let me know.

=cut
209
2101;