File Coverage

blib/lib/Dancer2/Logger/Console/Colored.pm
Criterion Covered Total %
statement 69 83 83.1
branch 31 44 70.4
condition 2 11 18.1
subroutine 19 24 79.1
pod 0 4 0.0
total 121 166 72.8


line stmt bran cond sub pod time code
1             package Dancer2::Logger::Console::Colored;
2             # ABSTRACT: Dancer2 colored console logger.
3             #
4             # This file is part of Dancer2-Logger-Console-Colored
5             #
6             # This software is Copyright (c) 2014 by BURNERSK <burnersk@cpan.org>.
7             #
8             # This is free software, licensed under:
9             #
10             # The MIT (X11) License
11             #
12              
13             BEGIN {
14 2     2   110087 our $VERSION = '0.008'; # VERSION: generated by DZP::OurPkgVersion
15             }
16              
17 2     2   665 use Term::ANSIColor;
  2         8658  
  2         151  
18 2     2   588 use Moo;
  2         9940  
  2         13  
19 2     2   2505 use Dancer2::Core::Types qw( ArrayRef HashRef Str );
  2         164342  
  2         31  
20 2     2   4770 use Encode;
  2         14861  
  2         178  
21              
22             extends 'Dancer2::Logger::Console';
23              
24 2     2   1069 use namespace::clean;
  2         27566  
  2         12  
25              
26             has colored_origin => (
27             is => 'rw',
28             isa => Str,
29             );
30              
31             has colored_levels => (
32             is => 'rw',
33             isa => HashRef [Str],
34             default => sub { {} },
35             );
36              
37             has colored_messages => (
38             is => 'rw',
39             isa => HashRef [Str],
40             default => sub { {} },
41             );
42              
43             has colored_regex => (
44             is => 'rw',
45             isa => ArrayRef [ HashRef [Str] ],
46             default => sub { [] },
47             );
48              
49             sub colorize_origin {
50 48     48 0 108 my ( $self, $string ) = @_;
51              
52             # Configured color.
53 48 100       893 return colored( $string, $self->colored_origin ) if $self->colored_origin;
54              
55             # Default colors.
56 27         219 return colored( $string, 'cyan' );
57             }
58              
59             sub colorize_level {
60 16     16 0 38 my ( $self, $level ) = @_;
61 16         59 my $level_tmp = $level =~ s/\s+//gr;
62 16 50       56 $level_tmp = 'warning' if $level_tmp eq 'warn';
63              
64             # Configured color.
65 16 100       310 return colored( $level, $self->colored_levels->{$level_tmp} ) if $self->colored_levels->{$level_tmp};
66              
67             # Default colors.
68 9 100       82 return colored( $level, 'bold bright_white' ) if $level_tmp eq 'core';
69 8 100       29 return colored( $level, 'bold bright_blue' ) if $level_tmp eq 'debug';
70 6 100       22 return colored( $level, 'bold green' ) if $level_tmp eq 'info';
71 4 100       15 return colored( $level, 'bold yellow' ) if $level_tmp eq 'warning';
72 2 50       12 return colored( $level, 'bold yellow on_red' ) if $level_tmp eq 'error';
73 0         0 return colored( $level, 'bold magenta' );
74             }
75              
76             sub colorize_message {
77 16     16 0 43 my ( $self, $level, $message ) = @_;
78 16         59 my $level_tmp = $level =~ s/\s+//gr;
79 16 50       61 $level_tmp = 'warning' if $level_tmp eq 'warn';
80              
81             # Check for regex match.
82 16         30 foreach my $pattern ( @{ $self->colored_regex } ) {
  16         343  
83 3 100       43 if ($message =~ m/$pattern->{re}/) {
84 2         25 $message =~ s{($pattern->{re})}{colored($1, $pattern->{color} )}eg;
  3         47  
85 2         74 return $message;
86             }
87             }
88              
89             # Configured color.
90 14 100       323 return colored( $message, $self->colored_messages->{$level_tmp} ) if $self->colored_messages->{$level_tmp};
91              
92             # Default colors.
93 9 100       81 return colored( $message, 'bold bright_white' ) if $level_tmp eq 'core';
94 8 100       26 return colored( $message, 'bold bright_blue' ) if $level_tmp eq 'debug';
95 6 100       25 return colored( $message, 'bold green' ) if $level_tmp eq 'info';
96 4 100       19 return colored( $message, 'bold yellow' ) if $level_tmp eq 'warning';
97 2 50       12 return colored( $message, 'bold yellow on_red' ) if $level_tmp eq 'error';
98 0         0 return colored( $message, 'bold magenta' );
99             }
100              
101             # This comes original from Dancer2::Logger::Console. There are a few hooks
102             # required in order to colorize log messages properly.
103             sub format_message {
104 17     17 0 286698 my ( $self, $level, $message ) = @_;
105 17         49 chomp $message;
106              
107 17         66 $level = sprintf( '%5s', $level );
108 17 50       81 $message = Encode::encode( $self->auto_encoding_charset, $message )
109             if $self->auto_encoding_charset;
110              
111 17         145 my @stack = caller(8);
112 17         55 my $request = $self->request;
113 17         47 my $config = $self->config;
114              
115             my $block_handler = sub {
116 0     0   0 my ( $block, $type ) = @_;
117 0 0       0 if ( $type eq 't' ) {
    0          
118 0         0 POSIX::strftime( $block, localtime(time) );
119             }
120             elsif ( $type eq 'h' ) {
121 0   0     0 return ( $request && $request->header($block) ) || '-';
122             }
123             else {
124 0         0 Carp::carp("{$block}$type not supported");
125 0         0 return "-";
126             }
127 17         86 };
128              
129             my $chars_mapping = {
130 16     16   69 a => sub { $self->colorize_origin( $self->app_name ) },
131             t => sub {
132 1     1   59 POSIX::strftime( "%d/%b/%Y %H:%M:%S", localtime(time) );
133             },
134 16     16   995 T => sub { POSIX::strftime( "%Y-%m-%d %H:%M:%S", localtime(time) ) },
135 0     0   0 u => sub { POSIX::strftime( "%d/%b/%Y %H:%M:%S", gmtime(time) ) },
136 0     0   0 U => sub { POSIX::strftime( "%Y-%m-%d %H:%M:%S", gmtime(time) ) },
137 16     16   91 P => sub { $$ },
138 16     16   45 L => sub { $self->colorize_level($level) },
139 16     16   47 m => sub { $self->colorize_message( $level => $message ) },
140 16   50 16   77 f => sub { $self->colorize_origin( $stack[1] || '-' ) },
141 16   50 16   62 l => sub { $self->colorize_origin( $stack[2] || '-' ) },
142             h => sub {
143 0   0 0   0 $self->colorize_origin(
144             ( $request && ( $request->remote_host || $request->address ) ) || '-'
145             )
146             },
147 0 0 0 0   0 i => sub { ( $request && $request->id ) || '-' },
148 17         369 };
149              
150             my $char_mapping = sub {
151 113     113   299 my $char = shift;
152              
153 113         228 my $cb = $chars_mapping->{$char};
154 113 50       248 if ( !$cb ) {
155 0         0 Carp::carp "\%$char not supported.";
156 0         0 return "-";
157             }
158 113         276 $cb->($char);
159 17         81 };
160              
161 17         370 my $fmt = $self->log_format;
162              
163 17         197 $fmt =~ s/
164             (?:
165             \%\{(.+?)\}([a-z])|
166             \%([a-zA-Z])
167             )
168 113 50       3328 / $1 ? $block_handler->($1, $2) : $char_mapping->($3) /egx;
169              
170 17         1827 return $fmt . "\n";
171             }
172              
173             1;
174              
175             __END__
176              
177             =pod
178              
179             =encoding UTF-8
180              
181             =head1 NAME
182              
183             Dancer2::Logger::Console::Colored - Dancer2 colored console logger.
184              
185             =head1 VERSION
186              
187             version 0.008
188              
189             =head1 DESCRIPTION
190              
191             This is a logging engine that allows you to print colored debug messages on
192             the standard error output. It is based on L<Dancer2::Logger::Console>. Refer
193             to its documentation for how to configure the format of your log message.
194              
195             =head2 log
196              
197             Writes the log message to the console.
198              
199             =head1 CONFIGURATION
200              
201             The setting C<logger> should be set to C<Console::Colored> in order to use
202             this logging engine in a Dancer2 application.
203              
204             # environment.yml or production.yml
205             logger: "Console::Colored"
206              
207             # config.yml (these are the defaults)
208             engines:
209             logger:
210             Console::Colored:
211             colored_origin: "cyan"
212             colored_levels:
213             core: "bold bright_white"
214             debug: "bold bright_blue"
215             info: "bold green"
216             warning: "bold yellow"
217             error: "bold yellow on_red"
218             colored_messages:
219             core: "bold bright_white"
220             debug: "bold bright_blue"
221             info: "bold green"
222             warning: "bold yellow"
223             error: "bold yellow on_red"
224              
225             =head2 Using Regex
226              
227             You can also provide a configuration key C<colored_regex>, which will allow you
228             to give multiple pairs of regular expression patterns and colors. The logger will
229             then change the colors of anything that matches a pattern according to the configuration.
230              
231             To enable it, use this (additional) configuration.
232              
233             colored_regex:
234             - re: "customer number \d+"
235             color: "bold red"
236              
237             It can also be used to highlight full lines. Just provide a pattern that grabs everything.
238              
239             colored_regex:
240             - re: ".+error.+"
241             color: "white on_red"
242              
243             Note that in YAML and other config formats, the pattern can only be a string. If you enable
244             this from within your application, you also also need to supply a string, not a C<qr//>.
245              
246             $logger->colored_regex(
247             [
248             {
249             re => 'foobar',
250             color => 'cyan',
251             },
252             {
253             re => '\d+',
254             color => 'magenta',
255             },
256             ]
257             );
258              
259             =head1 BREAKING CHANGES
260              
261             If you are running on L<Dancer2> older than 0.166001_01 you will need to use
262             L<Dancer2::Logger::Console::Colored> version 0.001 because L<Dancer2> changed
263             the way the logging was handled.
264              
265             =head1 BLOG POSTS
266              
267             =over
268              
269             =item *
270              
271             L<2018 Dancer Advent Calendar article|http://advent.perldancer.org/2018/23>
272              
273             =back
274              
275             =head1 SEE ALSO
276              
277             L<Dancer2::Logger::Console>, L<Dancer2::Core::Role::Logger>,
278             L<Term::ANSIColor>
279              
280             =for Pod::Coverage colorize_message colorize_origin format_message colorize_level
281              
282             =head1 AUTHOR
283              
284             BURNERSK <burnersk@cpan.org>
285              
286             =head1 COPYRIGHT AND LICENSE
287              
288             This software is Copyright (c) 2014 by BURNERSK <burnersk@cpan.org>.
289              
290             This is free software, licensed under:
291              
292             The MIT (X11) License
293              
294             =cut