File Coverage

blib/lib/Mojo/Weixin/Log.pm
Criterion Covered Total %
statement 28 98 28.5
branch 1 42 2.3
condition 0 27 0.0
subroutine 10 30 33.3
pod 8 17 47.0
total 47 214 21.9


line stmt bran cond sub pod time code
1             package Mojo::Weixin::Log;
2 1     1   5 use base qw(Mojo::Base Mojo::EventEmitter Mojo::Log);
  1         2  
  1         499  
3 1     1   1686 use Carp 'croak';
  1         2  
  1         37  
4 1     1   12 use Fcntl ':flock';
  1         2  
  1         68  
5 1     1   5 use Encode;
  1         2  
  1         92  
6 1     1   6 use POSIX qw();
  1         1  
  1         13  
7 1     1   408 use Encode::Locale;
  1         2683  
  1         37  
8 1     1   5 use IO::Handle;
  1         2  
  1         66  
9             BEGIN{
10 1     1   3 eval{require Term::ANSIColor};
  1         722  
11 1 50       7558 $Mojo::Weixin::Log::is_support_color = 1 unless $@;
12             }
13 11     11 1 23 sub has { Mojo::Base::attr(__PACKAGE__, @_) };
14            
15             has format => sub { \&_format };
16             has handle => sub {
17             # STDERR
18             return \*STDERR unless my $path = shift->path;
19             # File
20             croak qq{Can't open log file "$path": $!} unless open my $file, '>>', $path;
21             return $file;
22             };
23             has history => sub { [] };
24             has level => 'debug';
25             has head => '';
26             has encoding => undef;
27             has unicode_support => 1;
28             has disable_color => 0;
29             has console_output => 0;
30             has max_history_size => 10;
31             has 'path';
32            
33             # Supported log levels
34             my $LEVEL = {debug => 1, info => 2, msg=>3, warn => 4, error => 5, fatal => 6};
35             sub _format {
36 0     0     my ($time, $level, @lines) = @_;
37 0 0         my %opt = ref $lines[0] eq "HASH"?%{shift @lines}:();
  0            
38 0 0         $time = $opt{time} if defined $opt{time};
39 0 0         $time = $time?POSIX::strftime('[%y/%m/%d %H:%M:%S]',localtime($time)):"";
40             my $log = {
41             head => $opt{head} // "",
42             head_color => $opt{head_color},
43             'time' => $time,
44             time_color => $opt{time_color},
45             level => $opt{level} // $level,
46             level_color => $opt{level_color},
47             title => defined $opt{title}?"$opt{title} ":"",
48             title_color => $opt{title_color},
49             content => [split /\n/,join "",@lines],
50             content_color=> $opt{content_color},
51 0 0 0       };
      0        
52 0           return $log;
53             }
54             sub colored {
55             #black red green yellow blue magenta cyan white
56 0     0 0   my $self = shift;
57 0 0 0       return $_[0] if (!$_[0] or !$_[1] or $self->disable_color or !$Mojo::Weixin::Log::is_support_color);
      0        
      0        
58 0 0         return Term::ANSIColor::colored(@_) if $Mojo::Weixin::Log::is_support_color;
59             }
60             sub reform_encoding{
61 0     0 0   my $self = shift;
62 0           my $log = shift;
63 1     1   9 no strict;
  1         2  
  1         918  
64 0           my $msg ;
65 0 0 0       if($self->unicode_support and Encode::is_utf8($log)){
66 0   0       $msg = encode($self->encoding || console_out,$log);
67             }
68             else{
69 0 0         if($self->encoding =~/^utf-?8$/i ){
70 0           $msg = $log;
71             }
72             else{
73 0   0       $msg = encode($self->encoding || console_out,decode("utf8",$log));
74             }
75             }
76 0           return $msg;
77             }
78             sub append {
79 0     0 1   my ($self,$log) = @_;
80 0 0         return unless my $handle = $self->handle;
81 0           flock $handle, LOCK_EX;
82 0           $log->{$_} = $self->reform_encoding($log->{$_}) for(qw(head level title ));
83 0           $_ = $self->reform_encoding($_) for @{$log->{content}};
  0            
84 0 0         if( -t $handle){
85 0           my $color_msg;
86 0           for(@{$log->{content}}){
  0            
87             $color_msg .= $self->colored($log->{head},$log->{head_color})
88             . $self->colored($log->{time},$log->{time_color})
89             . " "
90             . ( $log->{level}?"[".$self->colored($log->{level},$log->{level_color})."]":"" )
91             . " "
92             . $self->colored($log->{title},$log->{title_color})
93             . $self->colored($_,$log->{content_color})
94 0 0         . "\n";
95             }
96 0 0         $handle->print($color_msg) or croak "Can't write to log: $!";
97             }
98             else{
99 0           my $msg;
100 0           for(@{$log->{content}}){
  0            
101             $msg .= $log->{head}
102             . $log->{time}
103             . " "
104             . ($log->{level}?"[$log->{level}]":"")
105             . " "
106             . $log->{title}
107 0 0         . $_
108             . "\n";
109             }
110 0 0         $handle->print($msg) or croak "Can't write to log: $!";
111 0 0 0       if($self->console_output and -t STDOUT){
112 0           my $color_msg;
113 0           for(@{$log->{content}}){
  0            
114             $color_msg .= $self->colored($log->{head},$log->{head_color})
115             . $self->colored($log->{time},$log->{time_color})
116             . " "
117             . ( $log->{level}?"[".$self->colored($log->{level},$log->{level_color})."]":"" )
118             . " "
119             . $self->colored($log->{title},$log->{title_color})
120             . $self->colored($_,$log->{content_color})
121 0 0         . "\n";
122             }
123 0           print STDERR $color_msg;#or croak "Can't write to log: $!"
124             }
125             }
126 0           flock $handle, LOCK_UN;
127             }
128            
129 0     0 1   sub debug { shift->_log(debug => @_) }
130 0     0 1   sub error { shift->_log(error => @_) }
131 0     0 1   sub fatal { shift->_log(fatal => @_) }
132 0     0 1   sub info { shift->_log(info => @_) }
133 0     0 1   sub warn { shift->_log(warn => @_) }
134 0     0 0   sub msg { shift->_log(msg => @_) }
135            
136 0     0 0   sub is_debug { shift->_now('debug') }
137 0     0 0   sub is_error { shift->_now('error') }
138 0     0 0   sub is_info { shift->_now('info') }
139 0     0 0   sub is_warn { shift->_now('warn') }
140 0     0 0   sub is_msg { shift->_now('msg') }
141 0     0 0   sub is_fatal { shift->_now('fatal') }
142            
143             sub new {
144 0     0 1   my $self = shift->SUPER::new(@_);
145 0           $self->on(message => \&_message);
146 0           return $self;
147             }
148            
149 0 0   0     sub _log { shift->emit('message', shift, ref $_[0] eq 'CODE' ? $_[0]() : @_) }
150            
151             sub _message {
152 0     0     my ($self, $level) = (shift, shift);
153            
154 0 0         return unless $self->_now($level);
155            
156 0           my $max = $self->max_history_size;
157 0           my $history = $self->history;
158 0 0         if(ref $_[0] eq 'HASH'){
159 0 0         $_[0]{head} = $self->head if not defined $_[0]{head};
160             }
161             else{
162 0           unshift @_,{head=>$self->head};
163             }
164 0           push @$history, my $msg = [time, $level, @_];
165 0           shift @$history while @$history > $max;
166              
167 0           $self->append($self->format->(@$msg));
168             }
169            
170 0   0 0     sub _now { $LEVEL->{pop()} >= $LEVEL->{$ENV{MOJO_LOG_LEVEL} || shift->level} }
171            
172             1;