File Coverage

blib/lib/Plack/Middleware/LogStderr.pm
Criterion Covered Total %
statement 71 80 88.7
branch 22 30 73.3
condition 17 25 68.0
subroutine 18 20 90.0
pod 2 2 100.0
total 130 157 82.8


line stmt bran cond sub pod time code
1 1     1   77036 use strict;
  1         2  
  1         21  
2 1     1   4 use warnings;
  1         1  
  1         36  
3             package Plack::Middleware::LogStderr;
4             $Plack::Middleware::LogStderr::VERSION = '0.002';
5             # ABSTRACT: Everything printed to STDERR sent to psgix.logger or other logger
6             # KEYWORDS: plack middleware errors logging environment I/O handle stderr
7              
8 1     1   4 use parent 'Plack::Middleware';
  1         1  
  1         6  
9              
10 1     1   9228 use Plack::Util::Accessor qw/logger callback tie_callback capture_callback no_tie log_level log_level_capture no_warnings/;
  1         2  
  1         3  
11 1     1   59 use Scalar::Util ();
  1         2  
  1         13  
12 1     1   391 use Capture::Tiny 'capture_stderr';
  1         13482  
  1         479  
13              
14             sub prepare_app {
15 19     19 1 40371 my $self = shift;
16 19   100     74 $self->{log_level} = $self->log_level || 'error';
17 19   66     239 $self->{log_level_capture} = $self->log_level_capture || $self->{log_level} ;
18            
19 19         166 foreach my $cb (qw/logger callback tie_callback capture_callback/){
20 58 100       225 if ($self->$cb) {
21 22 100       104 if (not __isa_coderef($self->$cb)) {
22 12         519 die "'$cb' is not a coderef!"
23             }
24             }
25             }
26             }
27              
28             sub call {
29 7     7 1 25261 my ($self, $env) = @_;
30 7   100     25 my $logger = $self->logger || $env->{'psgix.logger'};
31              
32 7 100       90 die 'no psgix.logger in $env; cannot send STDERR to it!'
33             if not $logger;
34            
35             my $stderr_logger = sub {
36 12     12   51 my $message = shift;
37 12         70 $message = $self->__run_tie_callback($message);
38 12         127 $logger->({level => $self->{log_level}, message => $message });
39 6         34 };
40            
41             my ($stderr, @app) = capture_stderr {
42 6     6   4301 my ($app, $err);
43              
44 6 100       21 tie *STDERR, 'Plack::Middleware::LogStderr::Handle2Logger', $stderr_logger, $self->no_warnings
45             unless $self->no_tie ;
46              
47 6         16 eval {
48 6         26 $app = $self->app->($env);
49             };
50 6 50       18296 $err = $@ if $@;
51              
52 6 100       56 untie *STDERR
53             unless $self->no_tie ;
54            
55 6 50       143 if ($err) {
56 0         0 die $@;
57             }
58 6         26 return $app;
59 6         144 };
60 6 50       2506 if ($stderr) {
61 6         33 $stderr = $self->__run_capture_callback($stderr) ;
62 6         52 $logger->({level => $self->{log_level_capture}, message => $stderr });
63             }
64            
65 6         239 return $app[0];
66             }
67              
68             sub __run_callback {
69 18     18   74 my ($self, $msg, $extra_cb) = @_;
70 18 100       94 $msg = $self->callback->($msg) if $self->callback;
71 18 50       188 if ($extra_cb) {
72 18 100 100     71 if ($extra_cb eq 'tie' && $self->tie_callback) {
73 6         33 $msg = $self->tie_callback->($msg) ;
74             }
75 18 100 100     148 if ($extra_cb eq 'capture' && $self->capture_callback) {
76 3         31 $msg = $self->capture_callback->($msg) ;
77             }
78             }
79 18         73 return $msg;
80             }
81             sub __run_capture_callback {
82 6     6   32 my ($self, $msg) = @_;
83 6         22 $msg = $self->__run_callback($msg, 'capture');
84 6         14 return $msg;
85            
86             }
87             sub __run_tie_callback {
88 12     12   39 my ($self, $msg) = @_;
89 12         56 $msg = $self->__run_callback($msg, 'tie');
90 12         25 return $msg;
91             }
92              
93             sub __isa_coderef {
94 22 100 100 22   181 ref $_[0] eq 'CODE'
      66        
95             or (Scalar::Util::reftype($_[0]) || '') eq 'CODE'
96             or overload::Method($_[0], '&{}')
97             }
98              
99             package # hide from PAUSE
100             Plack::Middleware::LogStderr::Handle2Logger;
101             our $VERSION = '0.001';
102             # ABSTRACT: Tie File Handle to a logger
103 1     1   7 use warnings::register;
  1         8  
  1         298  
104              
105             sub TIEHANDLE {
106 4     4   87 my ($pkg, $logger, $no_warnings) = @_;
107 4         25 return bless {logger => $logger, no_warnings => $no_warnings}, $pkg;
108             }
109             sub PRINT {
110 8     8   293 my ($self, @msg) = @_;
111 8         24 my $message = join('', @msg);
112 8         23 $self->{logger}->( $message );
113             }
114             sub PRINTF {
115 4     4   17925 my ($self, $fmt, @msg) = @_;
116 4         37 my $message = sprintf($fmt, @msg);
117 4         53 $self->{logger}->($message);
118             }
119             ## if something tries to reopen FILEHANDLE just return true -- noop
120             sub OPEN {
121 0     0     my ($self) = @_;
122 0 0 0       if (warnings::enabled() && !$self->{no_warnings}) {
123 0           warnings::warn("open called on tied handle Handle2Logger");
124             }
125 0           return 1;
126             }
127             ## if something tries to set BINMODE -- noop
128             sub BINMODE {
129 0     0     my ($self) = @_;
130 0 0 0       if (warnings::enabled() && !$self->{no_warnings}) {
131 0           warnings::warn("binmode called on tied handle Handle2Logger");
132             }
133 0           return undef;
134             }
135              
136              
137             1;
138              
139             __END__