File Coverage

blib/lib/Log/Deep/Line.pm
Criterion Covered Total %
statement 59 111 53.1
branch 8 50 16.0
condition 5 18 27.7
subroutine 12 20 60.0
pod 10 10 100.0
total 94 209 44.9


line stmt bran cond sub pod time code
1             package Log::Deep::Line;
2              
3             # Created on: 2009-05-30 21:19:07
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 2     2   29615 use strict;
  2         4  
  2         72  
10 2     2   8 use warnings;
  2         2  
  2         47  
11 2     2   375 use version;
  2         1430  
  2         11  
12 2     2   112 use Carp;
  2         3  
  2         104  
13 2     2   975 use Readonly;
  2         4383  
  2         86  
14 2     2   546 use Data::Dumper qw/Dumper/;
  2         5036  
  2         89  
15 2     2   901 use English qw/ -no_match_vars /;
  2         5882  
  2         10  
16 2     2   604 use base qw/Exporter/;
  2         3  
  2         163  
17 2     2   1104 use Term::ANSIColor;
  2         12701  
  2         2238  
18              
19             our $VERSION = version->new('0.3.3');
20             our @EXPORT_OK = qw//;
21             our %EXPORT_TAGS = ();
22              
23             Readonly my $LEVEL_COLOURS => {
24             info => '',
25             message => '',
26             debug => '',
27             warn => 'yellow',
28             error => 'red',
29             fatal => 'bold red',
30             security => '',
31             };
32              
33             sub new {
34 1     1 1 13 my $caller = shift;
35 1 50       3 my $class = ref $caller ? ref $caller : $caller;
36 1         2 my ($self, $line, $file) = @_;
37              
38 1 50       4 if (ref $self ne 'HASH') {
39 1         1 $file = $line;
40 1         2 $line = $self;
41 1         2 $self = {};
42             }
43              
44 1         3 bless $self, $class;
45              
46 1 50 33     6 $self->parse($line, $file) if $line && $file;
47              
48 1         3 return $self;
49             }
50              
51             sub parse {
52 4     4 1 3451 my ($self, $line, $file) = @_;
53              
54             # split the line into 5 parts
55             # TODO this might cause some problems if the message happens to have a \, in it
56 4         26 my @log = split /(?<!\\),/, $line, 5;
57              
58 4 50 33     17 if ( @log != 5 && $self->{verbose} ) {
59             # get the file name and line number
60 0         0 my $name = $file->{name};
61 0         0 my $line_no = $file->{handle}->input_line_number;
62              
63             # output the warnings about the bad line
64 0         0 warn "The log $name line ($line_no) did not contain 4 columns! Got ". (scalar @log) . " columns\n";
65 0 0       0 warn $line if $self->{verbose} > 1;
66             }
67              
68             # un-quote the individual columns
69 4         8 for my $col (@log) {
70 20         10 $col =~ s/ \\ \\ /\\/gxms;
71 20         25 $col =~ s/ (?<!\\) \\n /\n/gxms;
72 20         30 $col =~ s/ (?<!\\) \\, /,/gxms;
73             }
74              
75             # re-process the data so we can display what is needed.
76 4         5 my $DATA;
77 4 50 33     31 if ( $log[-1] =~ /;$/xms && length $log[-1] < 1_000_000 ) {
78 4     0   21 local $SIG{__WARN__} = sub {};
  0         0  
79 4         227 eval $log[-1]; ## no critic
80             }
81             else {
82 0 0       0 warn '' . (length $log[-1] < 1_000_000 ? 'The data is too large to process' : 'There appears to be a problem with the data' ) . ' on line ' . $file->{handle}->input_line_number . "\n";
83 0         0 $DATA = {};
84             }
85              
86 4         15 $self->{date} = $log[0];
87 4         6 $self->{session} = $log[1];
88 4         5 $self->{level} = $log[2];
89 4         6 $self->{message} = $log[3];
90 4         25 $self->{DATA} = $DATA;
91              
92 4         7 $self->{file} = $file;
93 4 50       15 $self->{position} = $file->{handle} ? tell $file->{handle} : 0;
94              
95 4         7 return $self;
96             }
97              
98 0     0 1 0 sub id { $_[0]->{session} };
99              
100             sub colour {
101 0     0 1 0 my ($self, $colour) = @_;
102              
103 0 0       0 if ($colour) {
104 0         0 my ($foreground, $background) = $colour =~ /^ ( \w+ ) \s+ on_ ( \w+ ) $/xms;
105 0         0 $self->{fg} = $foreground;
106 0         0 $self->{bg} = $background;
107             }
108              
109 0         0 return "$self->{fg} on_$self->{bg}";
110             }
111              
112             sub show {
113 2     2 1 6 my ($self) = @_;
114              
115             # TODO add real filtering body here
116 2 100 66     10 return 0 if !$self->{date} || !$self->{session};
117              
118 1         5 return 1;
119             }
120              
121             sub text {
122 0     0 1   my ($self) = @_;
123 0           my $out = '';
124              
125             # my $last = $self->{last_line_time} || 0;
126             # my $now = time;
127             #
128             # # check if we are putting line breaks when there is a large time between followed file output
129             # if ( $self->{breaks} && $now > $last + $self->{short_break} ) {
130             # my $lines = $now > $last + $self->{long_break} ? $self->{long_lines} : $self->{short_lines};
131             # $out .= "\n" x $lines;
132             # }
133             # $self->{last_line_time} = $now;
134              
135             # construct the log line determining colours to use etc
136 0 0         my $level = $self->{mono} ? $self->{level} : colored $self->{level}, $LEVEL_COLOURS->{$self->{level}};
137 0 0         $out .= $self->{mono} ? '' : color $self->colour();
138 0           $out .= "[$self->{date}]";
139              
140 0 0         if ( !$self->{verbose} ) {
141             # add the session id if the user cares
142 0           $out .= " $self->{session}";
143             }
144 0 0         if ( !$self->{mono} ) {
145             # reset the colour if we are not in mono
146 0           $out .= color 'reset';
147             }
148              
149             # finish constructing the log line
150 0           $out .= " $level - $self->{message}\n";
151              
152 0           return $out;
153             }
154              
155             sub data {
156 0     0 1   my ($self) = @_;
157 0           my $display = $self->{display};
158 0           my @fields;
159             my @out;
160 0           my $data = $self->{DATA};
161              
162 0 0         $display->{data} = defined $display->{data} ? $display->{data} : 1;
163              
164             # check for any fields that should be displayed
165 0           FIELD:
166 0           for my $field ( sort keys %{ $display } ) {
167             push @out,
168             $display->{$field} eq 0 ? ()
169             : !defined $data->{$field} ? data_missing($field, $data)
170             : ref $display->{$field} eq 'ARRAY' || $display->{$field} ne 1 ? data_sub_fields($field, $data->{$field})
171             : !ref $data->{$field} ? data_scalar($field, $data->{$field})
172 0 0 0       : $field ne 'data' || %{ $data->{$field} } ? $self->{dump}->Names($field)->Data($data->{$field})->Out()
    0 0        
    0          
    0          
    0          
173             : ();
174             }
175              
176 0           return @out;
177             }
178              
179             sub data_missing {
180 0     0 1   my ( $self, $field, $data ) = @_;
181 0 0         return if ref $field;
182 0 0         return if $field eq 'data';
183 0 0         return "\$$field = " . (exists $data->{field} ? 'undef' : 'missing') . "\n";
184             }
185              
186             sub data_sub_fields {
187 0     0 1   my ( $self, $field, $data ) = @_;
188 0           my $display = $self->{display};
189 0           my @out;
190              
191             # select the specified sub keys of $field
192 0 0         if ( !ref $display->{$field} ) {
193             # convert the display field into an array so that we can select it's sub fields
194 0           $display->{$field} = [ split /,/, $display->{$field} ];
195             }
196              
197             # out put each named sub field of $field
198 0           for my $sub_field ( @{ $display->{$field} } ) {
  0            
199 0           push @out, $self->{dump}->Names( $field . '_' . $sub_field )->Data( $data->{$sub_field} )->Out();
200             }
201              
202 0           return @out;
203             }
204              
205             sub data_scalar {
206 0     0 1   my ( $self, $field, $data ) = @_;
207              
208             # out put scalar values with out the DDS formatting
209 0 0         my $out .= "\$$field = " . ( defined $data ? $data : 'undef' );
210              
211             # safely guarentee that there is a new line at the end of this line
212 0           chomp $out;
213 0           $out .= "\n";
214 0           return $out;
215             }
216              
217             1;
218              
219             __END__
220              
221             =head1 NAME
222              
223             Log::Deep::Line - Encapsulates one line from a log file
224              
225             =head1 VERSION
226              
227             This documentation refers to Log::Deep::Line version 0.3.3.
228              
229             =head1 SYNOPSIS
230              
231             use Log::Deep::Line;
232              
233             # create a new line object
234             my $line = Log::Deep::Line->new( { show => {}, ... }, $line_text, $file );
235              
236             =head1 DESCRIPTION
237              
238             =head1 SUBROUTINES/METHODS
239              
240             =head3 C<new ( $options, $line, $file )>
241              
242             Param: C<$options> - hash ref - Configuration options for this line
243              
244             Param: C<$line> - string - The original text of the log line
245              
246             Param: C<$file> - Log::Deep::File - Object continuing the log file of interest
247              
248             Return: Log::Deep::Line - New log deep object
249              
250             Description: Create a new object from a line (C<$line>) of the log file (C<$file>)
251              
252             =head3 C<parse ( $line, $file )>
253              
254             Param: C<$line> - string - The original text of the log line
255              
256             Param: C<$file> - Log::Deep::File - Object continuing the log file of interest
257              
258             Description: Parses the log line
259              
260             =head3 C<id ( )>
261              
262             Return: The session id for this log line
263              
264             Description: Gets the session id for the log line. Will be undef if the log
265             line did not parse correctly.
266              
267             =head3 C<colour ( [ $colour ] )>
268              
269             Param: C<$colour> - string - A string containing the foreground and background
270             colour to use for this line. The format is 'I<colour> on_I<colour>'.
271              
272             Return: string - The colour set for this log line
273              
274             Description: Gets the current colour for this log line and optionally sets the
275             colour.
276              
277             =head3 C<show ( )>
278              
279             Return: bool - True if the log line should be shown.
280              
281             Description: Determines if the log line should be shown.
282              
283             =head3 C<text ( )>
284              
285             Return: The processed text of the line (sans the DATA section).
286              
287             Description: Processes log line for out putting to a terminal.
288              
289             =head3 C<data ( )>
290              
291             Return: The contents of the DATA section as specified by the display option
292              
293             Description: Out puts the DATA section of the log line.
294              
295             =head3 C<data_missing ($field, $data)>
296              
297             Param: C<$field> - string - The name of the field of data
298              
299             Param: C<$data> - any - All the data
300              
301             Return: Array - all the lines to be out put
302              
303             Description: Returns that there was no data or that the data was undefined
304              
305             =head3 C<data_sub_fields ($field, $data)>
306              
307             Param: C<$field> - string - The name of the field of data
308              
309             Param: C<$data> - any - The data being displayed
310              
311             Return: Array - all the lines to be out put
312              
313             Description: Shows only the sub keys of $data that are defined to be displayed
314              
315             =head3 C<data_scalar ($field, $data)>
316              
317             Param: C<$field> - string - The name of the field of data
318              
319             Param: C<$data> - any - The data being displayed
320              
321             Return: Array - all the lines to be out put
322              
323             Description: Just shows the simple data
324              
325             =head1 DIAGNOSTICS
326              
327             =head1 CONFIGURATION AND ENVIRONMENT
328              
329             =head1 DEPENDENCIES
330              
331             =head1 INCOMPATIBILITIES
332              
333             =head1 BUGS AND LIMITATIONS
334              
335             There are no known bugs in this module.
336              
337             Please report problems to Ivan Wills (ivan.wills@gmail.com).
338              
339             Patches are welcome.
340              
341             =head1 AUTHOR
342              
343             Ivan Wills - (ivan.wills@gmail.com)
344              
345             =head1 LICENSE AND COPYRIGHT
346              
347             Copyright (c) 2009 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
348             All rights reserved.
349              
350             This module is free software; you can redistribute it and/or modify it under
351             the same terms as Perl itself. See L<perlartistic>. This program is
352             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
353             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
354             PARTICULAR PURPOSE.
355              
356             =cut