File Coverage

blib/lib/MooX/Role/Chatty.pm
Criterion Covered Total %
statement 70 71 98.5
branch 21 24 87.5
condition 7 12 58.3
subroutine 14 14 100.0
pod 2 2 100.0
total 114 123 92.6


line stmt bran cond sub pod time code
1             #!perl
2             #
3              
4 4     4   29667 use 5.010;
  4         9  
  4         108  
5 4     4   19 use strict;
  4         3  
  4         111  
6 4     4   17 use warnings;
  4         5  
  4         183  
7              
8             package MooX::Role::Chatty;
9              
10             our ($VERSION) = '1.00';
11              
12 4     4   16 use Scalar::Util;
  4         3  
  4         159  
13 4     4   1519 use Type::Tiny::Duck;
  4         49840  
  4         95  
14 4     4   1445 use Log::Any::Adapter::Util;
  4         23016  
  4         134  
15              
16 4     4   375 use Moo::Role 2;
  4         5409  
  4         22  
17              
18             sub _prefix_message {
19 9     9   3746 my ( $category, $level, $message ) = @_;
20 9         376 my ( $sec, $min, $hr, $mday, $mon, $yr ) = localtime;
21 9         24 state $months = [qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )];
22 9         15 $yr += 1900;
23 9         14 $mon = $months->[$mon];
24 9 50       23 $message = '' unless defined $message;
25 9         25 my @lines = split /\n/, $message;
26              
27 9         60 return join(
28             "\n",
29             map {
30 9         14 sprintf '%04d-% 3s-%02d %02d:%02d:%02d :: %s',
31             $yr, $mon, $mday, $hr, $min, $sec, $_
32             } @lines
33             );
34             }
35              
36             has 'verbose' => (
37             is => 'rw',
38             isa => sub { shift =~ /^\d+$/; },
39             default => 0,
40             trigger => 1
41             );
42              
43             sub _verbose_to_log_level {
44 9     9   12 my $self = shift;
45 9         20 my $verbose = $self->verbose;
46              
47 9 100       1014 return 0 unless $verbose;
48              
49 6         23 require Log::Any::Adapter::Util;
50 6         14 state $base_level = Log::Any::Adapter::Util::numeric_level('notice');
51              
52 6         42 return $verbose + $base_level - !!( $verbose > 0 );
53             }
54              
55             sub _trigger_verbose {
56 10     10   83 my $self = shift;
57 10 100       82 return unless $self->_internal_logger;
58 6   33     32 my $category = Scalar::Util::blessed($self) || $self;
59 6         17 my $my_adapter = $self->_internal_logger->adapter ==
60             Log::Any->get_logger( category => $category )->adapter;
61 6         195 Log::Any::Adapter->remove( $self->_internal_logger->adapter );
62              
63             # If the current adapter is the one we installed, replace it.
64             # If the user installed their own, don't get in its way.
65             # Unfortunately, Log::Any doesn't provide a way to install our own
66             # fallback logger behind the user's
67 6 50       251 if ($my_adapter) {
68 6         16 Log::Any::Adapter->set(
69             { category => $category }, 'Carp',
70             no_trace => 1,
71             log_level => $self->_verbose_to_log_level
72             );
73             }
74             }
75              
76             has '_internal_logger' => ( is => 'rw', init_arg => undef, default => 0 );
77              
78             has 'logger' => (
79             is => 'rw',
80             lazy => 1,
81             isa => Type::Tiny::Duck->new( methods => [qw/info warn/] ),
82             builder => '_build_logger',
83             clearer => 'clear_logger',
84             trigger => 1
85             );
86              
87             sub _build_logger {
88 3     3   1284 my $self = shift;
89 3   33     21 my $category = Scalar::Util::blessed($self) || $self;
90 3         17 require Log::Any;
91 3         1335 require Log::Any::Adapter;
92 3         676 Log::Any::Adapter->set(
93             { category => $category }, 'Carp',
94             no_trace => 1,
95             log_level => $self->_verbose_to_log_level
96             );
97 3         5712 $self->_internal_logger(
98             Log::Any->get_logger(
99             category => $category,
100             filter => \&_prefix_message
101             )
102             );
103             }
104              
105             sub _trigger_logger {
106 5     5   13446 my $self = shift;
107 5 100       78 if ( $self->_internal_logger ) {
108 2         11 Log::Any::Adapter->remove( $self->_internal_logger->adapter );
109 2         155 $self->_internal_logger(0);
110             }
111             }
112              
113             before 'clear_logger' => sub {
114             my $self = shift;
115             if ( $self->_internal_logger ) {
116             Log::Any::Adapter->remove( $self->_internal_logger );
117             $self->_internal_logger(0);
118             }
119             };
120              
121             # Alias to mimic Log::Any API
122 1     1 1 1904 sub get_logger { shift->logger(@_); }
123              
124             sub remark {
125 9     9 1 1220 my ( $self, $msg ) = @_;
126              
127 9 100       19 return unless $self->verbose;
128              
129 6         489 my $logger = $self->logger;
130              
131 6 100 100     1466 if ( ( Scalar::Util::reftype($msg) || '' ) eq 'HASH' ) {
132 2 100 50     4 return if $self->verbose < ( $msg->{level} // -5 );
133 1         19 $msg = $msg->{message};
134             }
135              
136             # Log::Log4perl doesn't support 'notice', and Log::Dispatch
137             # supports 'notice' but not 'noticef', so do crude duck typing and
138             # go through some contortions for compatibility
139 5 100 100     19 if ( ( Scalar::Util::reftype($msg) || '' ) eq 'ARRAY' ) {
140 2 100       11 if ( $logger->can('noticef') ) { $logger->noticef(@$msg); }
  1         3  
141             else {
142 1         2 my $formatted = sprintf $msg->[0], @$msg[ 1 .. $#{$msg} ];
  1         4  
143 1 50       3 if ( $logger->can('notice') ) { $logger->notice($formatted) }
  0         0  
144 1         2 else { $logger->info($formatted) }
145             }
146             }
147             else {
148 3 100       12 if ( $logger->can('notice') ) { $logger->notice($msg); }
  2         4  
149 1         2 else { $logger->info($msg); }
150             }
151             }
152              
153             1;
154              
155             __END__