File Coverage

blib/lib/Log/Any/Adapter/Multiplex.pm
Criterion Covered Total %
statement 67 67 100.0
branch 12 14 85.7
condition 4 6 66.6
subroutine 14 14 100.0
pod 0 2 0.0
total 97 103 94.1


line stmt bran cond sub pod time code
1             package Log::Any::Adapter::Multiplex;
2             # ABSTRACT: Adapter to use allow structured logging across other adapters
3             our $VERSION = '1.718';
4              
5 2     2   137077 use Log::Any;
  2         7  
  2         13  
6 2     2   565 use Log::Any::Adapter;
  2         6  
  2         10  
7 2     2   11 use Log::Any::Adapter::Util qw(make_method);
  2         3  
  2         111  
8 2     2   9 use Log::Any::Manager;
  2         1056  
  2         76  
9 2     2   10 use Log::Any::Proxy;
  2         4  
  2         37  
10 2     2   9 use Carp;
  2         21  
  2         124  
11 2     2   10 use strict;
  2         3  
  2         72  
12 2     2   9 use warnings;
  2         18  
  2         108  
13 2     2   10 use base qw(Log::Any::Adapter::Base);
  2         3  
  2         1179  
14              
15             sub init {
16 7     7 0 9 my $self = shift;
17              
18 7         11 my $adapters = $self->{adapters};
19 7 100 100     23 if ( ( ref($adapters) ne 'HASH' ) ||
20 6         21 ( grep { ref($_) ne 'ARRAY' } values %$adapters ) ) {
21 4         646 Carp::croak("A list of adapters and their arguments must be provided");
22             }
23             }
24              
25             sub structured {
26 4     4 0 10 my ($self, $level, $category, @structured_log_args) = @_;
27 4         6 my %adapters = %{ $self->{adapters} };
  4         10  
28 4         5 my $unstructured_msg;
29              
30 4         8 for my $adapter ( $self->_get_adapters($category) ) {
31 7         26 my $is_level = "is_$level";
32              
33 7 100       25 if ($adapter->$is_level) {
34             # Very simple mimicry of Log::Any::Proxy
35             # We don't have to handle anything but the difference in
36             # non-structured interfaces
37 5 100       1188 if ($adapter->can('structured')) {
38 2         16 $adapter->structured($level, $category, @structured_log_args)
39             }
40             else {
41 3 50       6 if (!$unstructured_msg) {
42 3         5 $unstructured_msg = _unstructured_msg(@structured_log_args);
43             }
44 3         9 $adapter->$level($unstructured_msg);
45             }
46             }
47             }
48             }
49              
50             sub _unstructured_msg {
51 3     3   5 my @structured = @_;
52 3         3 my @unstructured = @structured;
53              
54 3 50 33     12 if ( @structured && ( ( ref $structured[-1] ) eq ref {} ) ) {
55 3         13 @unstructured = (
56             @structured[ 0 .. $#structured - 1 ],
57             Log::Any::Proxy::_stringify_params( $structured[-1] ),
58             )
59             }
60              
61 3         136 return join(' ' => @unstructured);
62             }
63              
64             # Delegate detection methods to other adapters
65             #
66             foreach my $method ( Log::Any->detection_methods() ) {
67             make_method(
68             $method,
69             sub {
70 8     8   12 my ($self) = @_;
71             # Not using List::Util::any because it could break older perl builds
72 8         17 my @logging_adaptors = grep { $_->$method } $self->_get_adapters();
  15         54  
73 8 100       44 return @logging_adaptors ? 1 : 0;
74             }
75             );
76             }
77              
78             sub _get_adapters {
79 12     12   14 my ($self) = @_;
80 12         15 my $category = $self->{category};
81             # Log::Any::Manager#get_adapter has similar code
82             # But has to handle rejiggering the stack
83             # And works with one adapter at a time (instead of a list, as below)
84             # Keeping track of multiple categories here is just future-proofing.
85             #
86 12         17 my $category_cache = $self->{category_cache};
87 12 100       24 if ( !defined( $category_cache->{$category} ) ) {
88 2         2 my $new_cache = [];
89 2         2 my %adapters = %{ $self->{adapters} };
  2         5  
90 2         7 while ( my ($adapter_name, $adapter_args) = each %adapters ) {
91             # XXX: This is also duplicated with Log::Any::Manager. It'd
92             # be nice if we could instead use a Log::Any::Manager to do
93             # the work here somehow, or just make Log::Any::Manager
94             # automatically multiplex when provided with more than one
95             # adapter in a single `->set()` call
96 3         7 my $adapter_class = Log::Any::Manager->_get_adapter_class($adapter_name);
97 3         6 Log::Any::Manager::_require_dynamic($adapter_class);
98 3         14 push @$new_cache, $adapter_class->new(
99             @$adapter_args,
100             category => $category
101             );
102             }
103              
104 2         5 $self->{category_cache}{$category} = $new_cache;
105             }
106              
107 12         14 return @{ $self->{category_cache}{$category} };
  12         28  
108             }
109              
110             1;
111              
112             __END__