File Coverage

blib/lib/Plack/Middleware/LogStderr.pm
Criterion Covered Total %
statement 71 79 89.8
branch 22 30 73.3
condition 17 19 89.4
subroutine 18 20 90.0
pod 2 2 100.0
total 130 150 86.6


line stmt bran cond sub pod time code
1 1     1   80475 use strict;
  1         3  
  1         23  
2 1     1   4 use warnings;
  1         2  
  1         38  
3             package Plack::Middleware::LogStderr;
4             $Plack::Middleware::LogStderr::VERSION = '0.001';
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         2  
  1         7  
9              
10 1     1   10588 use Plack::Util::Accessor qw/logger callback tie_callback capture_callback no_tie log_level log_level_capture/;
  1         3  
  1         6  
11 1     1   90 use Scalar::Util ();
  1         3  
  1         20  
12 1     1   883 use Capture::Tiny 'capture_stderr';
  1         20116  
  1         716  
13              
14             sub prepare_app {
15 19     19 1 39696 my $self = shift;
16 19   100     67 $self->{log_level} = $self->log_level || 'error';
17 19   66     177 $self->{log_level_capture} = $self->log_level_capture || $self->{log_level} ;
18            
19 19         162 foreach my $cb (qw/logger callback tie_callback capture_callback/){
20 58 100       194 if ($self->$cb) {
21 22 100       90 if (not __isa_coderef($self->$cb)) {
22 12         408 die "'$cb' is not a coderef!"
23             }
24             }
25             }
26             }
27              
28             sub call {
29 7     7 1 23817 my ($self, $env) = @_;
30 7   100     26 my $logger = $self->logger || $env->{'psgix.logger'};
31              
32 7 100       97 die 'no psgix.logger in $env; cannot send STDERR to it!'
33             if not $logger;
34            
35             my $stderr_logger = sub {
36 12     12   65 my $message = shift;
37 12         70 $message = $self->__run_tie_callback($message);
38 12         152 $logger->({level => $self->{log_level}, message => $message });
39 6         38 };
40            
41             my ($stderr, @app) = capture_stderr {
42 6     6   4657 my ($app, $err);
43              
44 6 100       23 tie *STDERR, 'Plack::Middleware::LogStderr::Handle2Logger', $stderr_logger
45             unless $self->no_tie ;
46              
47 6         21 eval {
48 6         26 $app = $self->app->($env);
49             };
50 6 50       20603 $err = $@ if $@;
51              
52 6 100       65 untie *STDERR
53             unless $self->no_tie ;
54            
55 6 50       103 if ($err) {
56 0         0 die $@;
57             }
58 6         23 return $app;
59 6         161 };
60 6 50       3131 if ($stderr) {
61 6         65 $stderr = $self->__run_capture_callback($stderr) ;
62 6         59 $logger->({level => $self->{log_level_capture}, message => $stderr });
63             }
64            
65 6         409 return $app[0];
66             }
67              
68             sub __run_callback {
69 18     18   96 my ($self, $msg, $extra_cb) = @_;
70 18 100       102 $msg = $self->callback->($msg) if $self->callback;
71 18 50       375 if ($extra_cb) {
72 18 100 100     91 if ($extra_cb eq 'tie' && $self->tie_callback) {
73 6         59 $msg = $self->tie_callback->($msg) ;
74             }
75 18 100 100     199 if ($extra_cb eq 'capture' && $self->capture_callback) {
76 3         50 $msg = $self->capture_callback->($msg) ;
77             }
78             }
79 18         125 return $msg;
80             }
81             sub __run_capture_callback {
82 6     6   22 my ($self, $msg) = @_;
83 6         27 $msg = $self->__run_callback($msg, 'capture');
84 6         30 return $msg;
85            
86             }
87             sub __run_tie_callback {
88 12     12   39 my ($self, $msg) = @_;
89 12         54 $msg = $self->__run_callback($msg, 'tie');
90 12         32 return $msg;
91             }
92              
93             sub __isa_coderef {
94 22 100 100 22   163 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   12 use warnings::register;
  1         4  
  1         416  
104              
105             sub TIEHANDLE {
106 4     4   86 my ($pkg, $logger) = @_;
107 4         25 return bless {logger => $logger}, $pkg;
108             }
109             sub PRINT {
110 8     8   328 my ($self, @msg) = @_;
111 8         27 my $message = join('', @msg);
112 8         27 $self->{logger}->( $message );
113             }
114             sub PRINTF {
115 4     4   19926 my ($self, $fmt, @msg) = @_;
116 4         34 my $message = sprintf($fmt, @msg);
117 4         58 $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         if (warnings::enabled()) {
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   0     if (warnings::enabled()) {
130 0           warnings::warn("binmode called on tied handle Handle2Logger");
131             }
132 0           return undef;
133             }
134              
135              
136             1;
137              
138             __END__