File Coverage

blib/lib/FirePHP/Log4perl/Layout.pm
Criterion Covered Total %
statement 18 93 19.3
branch 0 36 0.0
condition 0 24 0.0
subroutine 6 8 75.0
pod 2 2 100.0
total 26 163 15.9


line stmt bran cond sub pod time code
1             package FirePHP::Log4perl::Layout;
2              
3             =pod
4              
5             =head1 NAME
6              
7             FirePHP::Log4perl::Layout
8              
9             =head1 SYNOPSIS
10              
11              
12             In your C<Log::Log4perl> config:
13              
14             log4perl.rootLogger = DEBUG, FIREPHP
15              
16             log4perl.appender.FIREPHP = FirePHP::Appender
17             log4perl.appender.FIREPHP.layout = FirePHP::Layout
18              
19             =head1 DESCRIPTION
20              
21             B<FirePHP::Layout> is a specialized layout for FirePHP
22             based on (and hopefully mostly compatible to)
23             L<Log::Log4perl::Layout::PatternLayout>
24              
25             =cut
26              
27 1     1   1980 use strict;
  1         2  
  1         51  
28 1     1   5 use warnings;
  1         1  
  1         23  
29              
30 1     1   4 use base qw/Log::Log4perl::Layout::PatternLayout/;
  1         2  
  1         82  
31              
32 1     1   5 use Carp;
  1         2  
  1         84  
33 1     1   6 use Scalar::Util qw/looks_like_number blessed/;
  1         1  
  1         40  
34 1     1   4 use JSON::Any;
  1         1  
  1         14  
35              
36              
37             =head1 METHODS
38              
39             =head2 $class->new
40              
41             Returns: a FirePHP compatible L<Log::Log4perl::Layout::PatternLayout> object
42              
43             =cut
44              
45             sub new {
46 0     0 1   my $this = shift;
47 0           my $self = $this->SUPER::new( @_ );
48 0           $self->{info_needed}{$_} = 1 for qw/F L M l/;
49 0           $self->{json} = JSON::Any->new;
50 0           return $self;
51             }
52              
53             # unfortunately this had to be lifted almost verbatim from
54             # Log::Log4perl::Layout::PatternLayout because there is no way
55             # we can access the the info hash otherwise
56              
57              
58             =head2 $self->render( $message, $category, $priority, $caller_level )
59              
60             Overriden L<Log::Log4perl::Layout> renderer.
61              
62             =cut
63              
64             sub render {
65 0     0 1   my ( $self, $message, $category, $priority, $caller_level ) = @_;
66              
67 0 0         $caller_level = 0 unless defined $caller_level;
68              
69 0           my %info = ();
70              
71 0           $info{m} = $message;
72             # See 'define'
73 0 0         chomp $info{m} if $self->{message_chompable};
74              
75 0           my @results = ();
76              
77 0 0 0       if ($self->{info_needed}->{L} or
      0        
      0        
      0        
      0        
78             $self->{info_needed}->{F} or
79             $self->{info_needed}->{C} or
80             $self->{info_needed}->{l} or
81             $self->{info_needed}->{M} or
82             0
83             ) {
84 0           my ($package, $filename, $line,
85             $subroutine, $hasargs,
86             $wantarray, $evaltext, $is_require,
87             $hints, $bitmask) = caller($caller_level);
88              
89             # If caller() choked because of a whacko caller level,
90             # correct undefined values to '[undef]' in order to prevent
91             # warning messages when interpolating later
92 0 0         unless(defined $bitmask) {
93 0           for ($package,
94             $filename, $line,
95             $subroutine, $hasargs,
96             $wantarray, $evaltext, $is_require,
97             $hints, $bitmask) {
98 0 0         $_ = '[undef]' unless defined $_;
99             }
100             }
101              
102 0           $info{L} = $line;
103 0           $info{F} = $filename;
104 0           $info{C} = $package;
105              
106 0 0 0       if ($self->{info_needed}->{M} or
      0        
107             $self->{info_needed}->{l} or
108             0) {
109             # To obtain the name of the subroutine which triggered the
110             # logger, we need to go one additional level up.
111 0           my $levels_up = 1;
112             {
113 0           $subroutine = (caller($caller_level+$levels_up))[3];
  0            
114             # If we're inside an eval, go up one level further.
115 0 0 0       if (defined $subroutine and
116             $subroutine eq "(eval)") {
117 0           $levels_up++;
118 0           redo;
119             }
120             }
121 0 0         $subroutine = "main::" unless $subroutine;
122 0           $info{M} = $subroutine;
123 0           $info{l} = "$subroutine $filename ($line)";
124             }
125             }
126              
127 0           $info{X} = "[No curlies defined]";
128 0 0         $info{x} = Log::Log4perl::NDC->get() if $self->{info_needed}->{x};
129 0           $info{c} = $category;
130 0           $info{d} = 1; # Dummy value, corrected later
131 0           $info{n} = "\n";
132 0           $info{p} = $priority;
133 0           $info{P} = $$;
134 0           $info{H} = $Log::Log4perl::Layout::PatternLayout::HOSTNAME;
135              
136 0 0         if ( $self->{info_needed}->{r} ) {
137 0 0         if ( $Log::Log4perl::Layout::PatternLayout::TIME_HIRES_AVAILABLE ) {
138 0           $info{r} = int((
139             Time::HiRes::tv_interval(
140             $Log::Log4perl::Layout::PatternLayout::PROGRAM_START_TIME
141             )) * 1000 );
142             } else {
143 0 0         if ( ! $Log::Log4perl::Layout::PatternLayout::TIME_HIRES_AVAILABLE_WARNED) {
144 0           $Log::Log4perl::Layout::PatternLayout::TIME_HIRES_AVAILABLE_WARNED++;
145             # warn "Requested %r pattern without installed Time::HiRes\n";
146             }
147 0           $info{r} = time() - $Log::Log4perl::Layout::PatternLayout::PROGRAM_START_TIME;
148             }
149             }
150              
151             # Stack trace wanted?
152 0 0         if ($self->{info_needed}->{T}) {
153 0           my $mess = Carp::longmess();
154 0           chomp($mess);
155 0           $mess =~ s/(?:\A\s*at.*\n|^\s*Log::Log4perl.*\n|^\s*)//mg;
156 0           $mess =~ s/\n/, /g;
157 0           $info{T} = $mess;
158             }
159              
160             # As long as they're not implemented yet ..
161 0           $info{t} = "N/A";
162              
163 0           foreach my $cspec (keys %{$self->{USER_DEFINED_CSPECS}}) {
  0            
164 0 0         next unless $self->{info_needed}->{$cspec};
165 0           $info{$cspec} = $self->{USER_DEFINED_CSPECS}->{$cspec}->(
166             $self,$message, $category, $priority, $caller_level+1
167             );
168             }
169              
170             # Iterate over all info fields on the stack
171 0           for my $e (@{$self->{stack}}) {
  0            
172 0           my($op, $curlies) = @$e;
173 0 0         if (exists $info{$op}) {
174 0           my $result = $info{$op};
175 0 0         if ($curlies) {
176 0           $result = $self->curly_action($op, $curlies, $info{$op});
177             } else {
178             # just for %d
179 0 0         if ($op eq 'd') {
180 0           $result = $info{$op}->format($self->{time_function}->());
181             }
182             }
183 0 0         $result = "[undef]" unless defined $result;
184 0           push @results, $result;
185             } else {
186 0           warn "Format %'$op' not implemented (yet)";
187 0           push @results, "FORMAT-ERROR";
188             }
189             }
190              
191             #print STDERR "sprintf $self->{printformat}--$results[0]--\n";
192              
193 0           my $rendered_message = sprintf( $self->{printformat}, @results );
194              
195 0           my ( $type ) = ( grep { $info{p} eq $_ } qw/INFO WARN ERROR/ );
  0            
196 0   0       $type ||= 'INFO';
197              
198 0           my $source = $info{c};
199              
200 0           my ( $source_method ) = reverse split( '::', $info{M} );
201              
202 0           my %info_hash = (
203             Type => $type,
204             File => $info{F},
205             Line => $info{L},
206             );
207              
208 0           return $self->{json}->objToJson(
209             [ \%info_hash, $rendered_message ]
210             );
211             }
212              
213              
214             1;
215              
216             __END__
217              
218              
219             =head1 SEE ALSO
220              
221             L<http://www.firephp.org>, L<Log::Log4perl>, L<FirePHP::Catalyst::Plugin>
222              
223             =head1 AUTHOR
224              
225             Sebastian Willert, C<willert@cpan.org>
226              
227             =head1 COPYRIGHT AND LICENSE
228              
229             Copyright 2009 by Sebastian Willert E<lt>willert@cpan.orgE<gt>
230              
231             This library is free software; you can redistribute it and/or modify
232             it under the same terms as Perl itself.
233              
234             =cut
235              
236