File Coverage

blib/lib/Dancer2/Core/Role/Logger.pm
Criterion Covered Total %
statement 60 70 85.7
branch 20 32 62.5
condition 2 11 18.1
subroutine 25 30 83.3
pod 6 8 75.0
total 113 151 74.8


line stmt bran cond sub pod time code
1             package Dancer2::Core::Role::Logger;
2             # ABSTRACT: Role for logger engines
3             $Dancer2::Core::Role::Logger::VERSION = '2.0.1';
4 130     130   551712 use Dancer2::Core::Types;
  130         633  
  130         1549  
5              
6 130     130   2003263 use Moo::Role;
  130         12277  
  130         1877  
7 130     130   286017 use POSIX 'strftime';
  130         1060147  
  130         1538  
8 130     130   236910 use Encode ();
  130         55472  
  130         4278  
9 130     130   8314 use Data::Dumper;
  130         98703  
  130         194659  
10              
11             with 'Dancer2::Core::Role::Engine';
12              
13 116     116 0 458 sub hook_aliases { +{} }
14             sub supported_hooks {
15 36     36 0 345 qw(
16             engine.logger.before
17             engine.logger.after
18             );
19             }
20              
21 0     0   0 sub _build_type {'Logger'}
22              
23             # This is the only method to implement by logger engines.
24             # It receives the following arguments:
25             # $msg_level, $msg_content, it gets called only if the configuration allows
26             # a message of the given level to be logged.
27             requires 'log';
28              
29             has auto_encoding_charset => (
30             is => 'ro',
31             isa => Str,
32             );
33              
34             has app_name => (
35             is => 'ro',
36             isa => Str,
37             default => sub {'-'},
38             );
39              
40             has log_format => (
41             is => 'rw',
42             isa => Str,
43             default => sub {'[%a:%P] %L @%T> %m in %f l. %l'},
44             );
45              
46             my $_levels = {
47              
48             # levels < 0 are for core only
49             core => -10,
50              
51             # levels > 0 are for end-users only
52             debug => 1,
53             info => 2,
54             warn => 3,
55             warning => 3,
56             error => 4,
57             };
58              
59             has log_level => (
60             is => 'rw',
61             isa => Enum[keys %{$_levels}],
62             default => sub {'debug'},
63             );
64              
65             sub _should {
66 2826     2826   6333 my ( $self, $msg_level ) = @_;
67 2826         58531 my $conf_level = $self->log_level;
68 2826         34421 return $_levels->{$conf_level} <= $_levels->{$msg_level};
69             }
70              
71             sub format_message {
72 58     58 1 2827 my ( $self, $level, $message ) = @_;
73 58         189 chomp $message;
74              
75 58 50       284 $message = Encode::encode( $self->auto_encoding_charset, $message )
76             if $self->auto_encoding_charset;
77              
78 58         502 my @stack = caller(8);
79 58         254 my $request = $self->request;
80 58         207 my $config = $self->config;
81              
82             my $block_handler = sub {
83 5     5   22 my ( $block, $type ) = @_;
84 5 50       24 if ( $type eq 't' ) {
    50          
85 0         0 return POSIX::strftime( $block, localtime(time) );
86             }
87             elsif ( $type eq 'h' ) {
88 5   50     67 return ( $request && $request->header($block) ) || '-';
89             }
90             else {
91 0         0 Carp::carp("{$block}$type not supported");
92 0         0 return "-";
93             }
94 58         449 };
95              
96             my $chars_mapping = {
97 53     53   461 a => sub { $self->app_name },
98 0     0   0 t => sub { POSIX::strftime( "%d/%b/%Y %H:%M:%S", localtime(time) ) },
99 53     53   2993 T => sub { POSIX::strftime( "%Y-%m-%d %H:%M:%S", localtime(time) ) },
100 0     0   0 u => sub { POSIX::strftime( "%d/%b/%Y %H:%M:%S", gmtime(time) ) },
101 0     0   0 U => sub { POSIX::strftime( "%Y-%m-%d %H:%M:%S", gmtime(time) ) },
102 53     53   667 P => sub {$$},
103 53     53   246 L => sub {$level},
104 53     53   280 m => sub {$message},
105 53 100   53   415 f => sub { $stack[1] || '-' },
106 53 100   53   345 l => sub { $stack[2] || '-' },
107             h => sub {
108 0 0 0 0   0 ( $request && ( $request->remote_host || $request->address ) ) || '-'
      0        
109             },
110 5 50 33 5   41 i => sub { ( $request && $request->id ) || '-' },
111 58         1916 };
112              
113             my $char_mapping = sub {
114 376     376   761 my $char = shift;
115              
116 376         708 my $cb = $chars_mapping->{$char};
117 376 50       1201 if ( !$cb ) {
118 0         0 Carp::carp "%$char not supported.";
119 0         0 return "-";
120             }
121 376         843 $cb->($char);
122 58         333 };
123              
124 58         1869 my $fmt = $self->log_format;
125              
126 58         866 $fmt =~ s/
127             (?:
128             \%\{(.+?)\}([a-z])|
129             \%([a-zA-Z])
130             )
131 381 100       2104 / $1 ? $block_handler->($1, $2) : $char_mapping->($3) /egx;
132              
133 58         3104 return $fmt . "\n";
134             }
135              
136             sub _serialize {
137 53     53   184 my @vars = @_;
138              
139 53 50       1794 return join q{}, map +(
    50          
140             ref $_
141             ? Data::Dumper->new( [$_] )->Terse(1)->Purity(1)->Indent(0)
142             ->Sortkeys(1)->Dump()
143             : ( defined($_) ? $_ : 'undef' )
144             ), @vars;
145             }
146              
147             around 'log' => sub {
148             my ($orig, $self, @args) = @_;
149              
150             $self->execute_hook( 'engine.logger.before', $self, @args );
151             $self->$orig( @args );
152             $self->execute_hook( 'engine.logger.after', $self, @args );
153             };
154              
155             sub core {
156 2775     2775 1 8787 my ( $self, @args ) = @_;
157 2775 100       9085 $self->_should('core') and $self->log( 'core', _serialize(@args) );
158             }
159              
160             sub debug {
161 12     12 1 3569 my ( $self, @args ) = @_;
162 12 100       46 $self->_should('debug') and $self->log( 'debug', _serialize(@args) );
163             }
164              
165             sub info {
166 2     2 1 1831 my ( $self, @args ) = @_;
167 2 50       8 $self->_should('info') and $self->log( 'info', _serialize(@args) );
168             }
169              
170             sub warning {
171 9     9 1 2088 my ( $self, @args ) = @_;
172 9 50       64 $self->_should('warning') and $self->log( 'warning', _serialize(@args) );
173             }
174              
175             sub error {
176 28     28 1 2230 my ( $self, @args ) = @_;
177 28 50       101 $self->_should('error') and $self->log( 'error', _serialize(@args) );
178             }
179              
180             1;
181              
182             __END__