File Coverage

blib/lib/MooX/Role/Chatty.pm
Criterion Covered Total %
statement 67 68 98.5
branch 21 24 87.5
condition 7 12 58.3
subroutine 13 13 100.0
pod 2 2 100.0
total 110 119 92.4


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