File Coverage

blib/lib/Siebel/Srvrmgr/Log/Enterprise.pm
Criterion Covered Total %
statement 69 76 90.7
branch 8 18 44.4
condition 1 3 33.3
subroutine 13 13 100.0
pod 2 2 100.0
total 93 112 83.0


line stmt bran cond sub pod time code
1             package Siebel::Srvrmgr::Log::Enterprise;
2              
3 2     2   29876 use Moose 2.0401;
  2         62  
  2         22  
4 2     2   20873 use namespace::autoclean 0.13;
  2         74  
  2         20  
5 2     2   1203 use File::Copy;
  2         4875  
  2         158  
6 2     2   25 use File::Temp qw(tempfile);
  2         6  
  2         152  
7 2     2   14 use Carp qw(cluck confess);
  2         6  
  2         131  
8 2     2   1069 use String::BOM 0.3 qw(strip_bom_from_string);
  2         72  
  2         16  
9             our $VERSION = '0.29'; # VERSION
10              
11             =pod
12              
13             =head1 NAME
14              
15             Siebel::Srvrmgr::Log::Enterprise - module to read a Siebel Enterprise log file
16              
17             =head1 SYNOPSIS
18              
19             use Siebel::Srvrmgr::Log::Enterprise;
20             my $enterprise_log = Siebel::Srvrmgr::Log::Enterprise->new( { path => File::Spec->catfile('somewhere', 'under', 'the', 'rainbow')} );
21             my $next = $enterprise_log->read();
22              
23             while (my $line = $next->()) {
24              
25             # do something
26              
27             }
28              
29              
30             =head1 DESCRIPTION
31              
32             A class that knows how to read Siebel Enterprise log files: it knows the header details and how to safely read lines from the file.
33              
34             =head1 ATTRIBUTES
35              
36             =head2 path
37              
38             A string with the complete pathname to the Siebel Enterprise log file.
39              
40             This attribute is required during object creation.
41              
42             =cut
43              
44             has path => ( is => 'ro', isa => 'Str', reader => 'get_path', required => 1 );
45              
46             =head2 eol
47              
48             A string identifying the character(s) used as end-of-line in the Siebel Enterprise log file is configured.
49              
50             This attribute is read-only, this class will automatically try to define the field separator being used.
51              
52             =cut
53              
54             has eol => (
55             is => 'ro',
56             isa => 'Str',
57             reader => 'get_eol',
58             writer => '_set_eol',
59             default => 0
60             );
61              
62             =head2 fs
63              
64             A string identifying the character(s) used to separate the fields ("fs" stands for "field separator") in the Siebel Enterprise log file is configured.
65              
66             This attribute is read-only, this class will automatically try to define the EOL being used.
67              
68             =cut
69              
70             has fs => (
71             is => 'ro',
72             isa => 'Str',
73             reader => 'get_fs',
74             writer => '_set_fs',
75             default => 0
76             );
77              
78             =head2 fh
79              
80             The file handle reference to the Siebel Enterprise log file, after was opened.
81              
82             =cut
83              
84             has fh =>
85             ( is => 'ro', isa => 'FileHandle', reader => 'get_fh', writer => '_set_fh' );
86              
87             =head2 filename
88              
89             The complete path to the temporary filename that this class uses to store the lines of the Siebel Enterprise Log file.
90              
91             =cut
92              
93             has filename => (
94             is => 'ro',
95             isa => 'Str',
96             reader => 'get_filename',
97             writer => '_set_filename'
98             );
99              
100             =head2 header
101              
102             The header of the Siebel Enterprise log file, without the BOM.
103              
104             =cut
105              
106             has header => (
107             is => 'ro',
108             isa => 'Str',
109             reader => 'get_header',
110             writer => '_set_header',
111             trigger => \&_check_header
112             );
113              
114             =head1 SEE ALSO
115              
116             =over
117              
118             =item *
119              
120             L<Moose>
121              
122             =item *
123              
124             L<Siebel::Srvrmgr::OS::Unix>
125              
126             =back
127              
128             =head1 METHODS
129              
130             =head2 read
131              
132             Reads the Siebel Enterprise log file, returning a iterator over the lines of the file.
133              
134             The method will try to read the file as safely as possible, copying it to a temporary location before reading.
135              
136             Several attributes will be defined during the file reading, automatically whenever it is possible. In some cases, if unable to
137             define those attributes, an exception will be raised.
138              
139             =cut
140              
141             sub read {
142              
143 2     2 1 5127 my $self = shift;
144 2         7 my $template = __PACKAGE__ . '_XXXXXX';
145 2         20 $template =~ s/\:{2}/_/g;
146              
147             # :TODO:09/18/2015 09:14:14 PM:: insecure, must check if it not possible to keep the file handle, copy the file
148             # over and use seek to go back to the beginning of the file
149 2         29 my ( $fh, $filename ) = tempfile($template);
150 2         1078 close($fh);
151 2         121 copy( $self->get_path(), $filename );
152              
153 2 50   2   23 open( $fh, '<:encoding(utf8)', $filename )
  2         4  
  2         23  
  2         787  
154             or die "Cannot read $filename: $!";
155 2         23550 $self->_set_filename($filename);
156 2         55 my $header = <$fh>;
157              
158             # remove BOM, see https://rt.cpan.org/Public/Bug/Display.html?id=101175
159 2         41 $header = strip_bom_from_string($header);
160 2         34 $header =~ s/^\x{feff}//;
161              
162             # don't know which EOL is available
163 2         17 $header =~ tr/\012//d;
164 2         15 $header =~ tr/\015//d;
165              
166 2         91 $self->_set_fh($fh);
167              
168 2         89 $self->_set_header($header);
169 2         85 my $eol = $self->get_eol();
170              
171             return sub {
172              
173 51     51   1624 local $/ = $eol;
174 51         198 return <$fh>;
175              
176             }
177              
178 2         30 }
179              
180             =head2 DEMOLISH
181              
182             During object termination, the associated temporary log file will be closed and removed automatically, if available.
183              
184             =cut
185              
186             sub DEMOLISH {
187              
188 2     2 1 7 my $self = shift;
189              
190 2         84 my $fh = $self->get_fh();
191              
192 2 50       12 if ( defined($fh) ) {
193              
194 2         41 close($fh);
195              
196             }
197              
198 2         96 my $file = $self->get_filename();
199              
200 2 50 33     105 if ( ( defined($file) ) and ( -e $self->get_filename() ) ) {
201              
202 2 50       179 unlink $file or cluck "Could not remove $file: $!";
203              
204             }
205              
206             }
207              
208             sub _check_header {
209              
210 2     2   8 my $self = shift;
211 2         101 my @parts = split( /\s/, $self->get_header() );
212 2         15 $self->_define_eol( $parts[0] );
213 2         11 $self->_define_fs( $parts[9], $parts[10] );
214              
215             }
216              
217             sub _define_fs {
218              
219 2     2   6 my $self = shift;
220 2         6 my $field_del_length = shift;
221 2         5 my $field_delim = shift;
222 2         7 my $num;
223              
224 2         11 for my $i ( 1 .. 4 ) {
225              
226 4         11 my $temp = chop($field_del_length);
227 4 100       16 if ( $temp != 0 ) {
228              
229 2         9 $num .= $temp;
230              
231             }
232             else {
233              
234 2         8 last;
235              
236             }
237              
238             }
239              
240 2 50       11 confess "field delimiter unimplemented" if ( $num > 1 );
241              
242             # converting hex number to the corresponding character as defined in ASCII table
243 2         108 $self->_set_fs( chr( unpack( 's', pack 's', hex($field_delim) ) ) );
244              
245             }
246              
247             sub _define_eol {
248              
249 2     2   6 my $self = shift;
250 2         7 my $part = shift;
251 2         12 my $eol = substr $part, 0, 1;
252              
253             CASE: {
254              
255 2 50       6 if ( $eol eq '2' ) {
  2         8  
256              
257 2         94 $self->_set_eol("\015\012");
258 2         9 last CASE;
259              
260             }
261              
262 0 0         if ( $eol eq '1' ) {
263              
264 0           $self->_set_eol("\012");
265 0           last CASE;
266              
267             }
268              
269 0 0         if ( $eol eq '0' ) {
270              
271 0           $self->_set_eol("\015");
272 0           last CASE;
273              
274             }
275             else {
276              
277 0           confess "EOL is custom, don't know what to use!";
278              
279             }
280              
281             }
282              
283             }
284              
285             =head1 AUTHOR
286              
287             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
288              
289             =head1 COPYRIGHT AND LICENSE
290              
291             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
292              
293             This file is part of Siebel Monitoring Tools.
294              
295             Siebel Monitoring Tools is free software: you can redistribute it and/or modify
296             it under the terms of the GNU General Public License as published by
297             the Free Software Foundation, either version 3 of the License, or
298             (at your option) any later version.
299              
300             Siebel Monitoring Tools is distributed in the hope that it will be useful,
301             but WITHOUT ANY WARRANTY; without even the implied warranty of
302             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
303             GNU General Public License for more details.
304              
305             You should have received a copy of the GNU General Public License
306             along with Siebel Monitoring Tools. If not, see <http://www.gnu.org/licenses/>.
307              
308             =cut
309              
310             __PACKAGE__->meta->make_immutable;