File Coverage

blib/lib/Siebel/Srvrmgr/Log/Enterprise/Parser/Comp_alias.pm
Criterion Covered Total %
statement 52 114 45.6
branch 10 30 33.3
condition 0 6 0.0
subroutine 7 13 53.8
pod 1 1 100.0
total 70 164 42.6


line stmt bran cond sub pod time code
1             package Siebel::Srvrmgr::Log::Enterprise::Parser::Comp_alias;
2              
3 1     1   189991 use Moose;
  1         336719  
  1         7  
4 1     1   7933 use namespace::autoclean;
  1         8359  
  1         3  
5 1     1   823 use Set::Tiny;
  1         1230  
  1         52  
6 1     1   6 use Carp qw(cluck confess);
  1         2  
  1         68  
7 1     1   644 use Siebel::Srvrmgr::Log::Enterprise;
  1         14789  
  1         1451  
8              
9             with 'Siebel::Srvrmgr::Comps_source';
10              
11             =pod
12              
13             =head1 NAME
14              
15             Siebel::Srvrmgr::Log::Enterprise::Parser::Comp_alias - parses of component alias from the Siebel Enterprise log file
16              
17             =head1 SYNOPSIS
18              
19             # see the proc_mon.pl script in the examples directory
20              
21             =head1 DESCRIPTION
22              
23             This class implements the L<Siebel::Srvrmgr::Comps_source> Moose Role to recover information from components by reading the Siebel Enterprise log file.
24              
25             This enables one to create a "cheap" (in the sense of not needing to connect to the Siebel Server) component monitor to recover information about CPU, memory, etc, usage by the Siebel
26             components.
27              
28             =head1 ATTRIBUTES
29              
30             =head2 process_regex
31              
32             Required attribute.
33              
34             A string of the regular expression to match the components PID logged in the Siebel Enterprise log file. The regex should match the text in the sixth "column" (considering
35             that they are delimited by a character) of a Siebel Enterprise log. Since the Siebel Enterprise may contain different language settings, this parameter is required and
36             will depend on the language set.
37              
38             An example of configuration will help understand. Take your time to review the piece of Enterprise log file below:
39              
40             ServerLog ComponentUpdate 2 0000149754f82575:0 2015-03-05 13:15:41 AdminNotify STARTING Component is starting up.
41             ServerLog ComponentUpdate 2 0000149754f82575:0 2015-03-05 13:15:41 AdminNotify INITIALIZED Component has initialized (no spawned procs).
42             ServerLog ComponentUpdate 2 0000149754f82575:0 2015-03-05 13:15:41 SvrTaskPersist STARTING Component is starting up.
43             ServerLog ProcessCreate 1 0000149754f82575:0 2015-03-05 13:15:41 Created multithreaded server process (OS pid = 9644 ) for SRProc
44             ServerLog ProcessCreate 1 0000149754f82575:0 2015-03-05 13:15:41 Created multithreaded server process (OS pid = 9645 ) for FSMSrvr
45             ServerLog ProcessCreate 1 0000149754f82575:0 2015-03-05 13:15:41 Created multithreaded server process (OS pid = 9651 ) for AdminNotify
46              
47             In this case, the string should be a regular expression something like C<Created\s(multithreaded)?\sserver\sprocess>.
48              
49             This attribute is a string, not a compiled regular expression with C<qr>.
50              
51             =cut
52              
53             has process_regex => (
54             is => 'ro',
55             isa => 'Str',
56             reader => 'get_process_regex',
57             required => 1
58             );
59              
60             =head2 archive
61              
62             An optional object instance of a class that uses the L<Moose::Role> L<Siebel::Srvrmgr::Log::Enterprise::Archive>.
63              
64             An important concept (and the reason for this paragraph) is that the reading of the Siebel Enterprise log file might be restricted or not.
65              
66             In restricted mode, the Siebel Enterprise log file is read once and the already read component aliases is persisted somehow, including the last line of the file read: that will avoid
67             reading all over the file again, and more important, minimizing association of reused PIDs with component aliases, thus generating incorrect data.
68              
69             To use "simple" mode, nothing else is necessary. Simple is much simpler to be used, but there is the risk of PIDs reutilization causing invalid data to be generated. For long running monitoring,
70             I suggest using restricted mode.
71              
72             =cut
73              
74             has 'archive' => (
75             is => 'ro',
76             does => 'Siebel::Srvrmgr::Log::Enterprise::Archive',
77             reader => 'get_archive'
78             );
79              
80             =head2 log_path
81              
82             A string of the complete pathname to the Siebel Enterprise log file.
83              
84             =cut
85              
86             has log_path =>
87             ( is => 'ro', isa => 'Str', required => 1, reader => 'get_log_path' );
88              
89             =head1 METHODS
90              
91             =head2 get_process_regex
92              
93             Getter for the attribute C<process_regex>.
94              
95             =cut
96              
97             =head2 find_comps
98              
99             Parses the Siebel Enterprise log file by using a instance of a class that implements L<Siebel::Srvrmgr::Log::Enterprise::Archive> Moose Role.
100              
101             Expects as parameter a hash reference containing as keys the PIDs and as values the respective instances of L<Siebel::Srvrmgr::OS::Process>.
102              
103             It will return the same reference with the component alias information include when possible.
104              
105             =cut
106              
107             sub find_comps {
108              
109 1     1 1 2 my $self = shift;
110 1         2 my $procs = shift;
111              
112 1 50       4 confess "the processes parameter is required" unless ( defined($procs) );
113 1 50       10 confess "must receive an hash reference as parameter"
114             unless ( ref($procs) eq 'HASH' );
115              
116 1         2 foreach my $pid ( keys( %{$procs} ) ) {
  1         9  
117              
118             confess
119             "values of process parameter must be instances of Siebel::Srvrmgr::OS::Process"
120 1 50       19 unless ( $procs->{$pid}->isa('Siebel::Srvrmgr::OS::Process') );
121              
122             }
123              
124 1         62 my $enterprise_log = Siebel::Srvrmgr::Log::Enterprise->new(
125             { path => $self->get_log_path() } );
126              
127 1         3 my $create_regex;
128              
129             {
130              
131 1         2 my $regex = $self->get_process_regex;
  1         65  
132 1         40 $create_regex = qr/$regex/;
133              
134             }
135              
136 1 50       60 if ( defined( $self->get_archive() ) ) {
137              
138 0         0 $self->_archived_recover( $procs, $enterprise_log, $create_regex );
139              
140             }
141             else {
142              
143 1         11 $self->_recover( $procs, $enterprise_log, $create_regex );
144              
145             }
146              
147 1         48 return $procs;
148              
149             }
150              
151             sub _get_last_line {
152              
153 0     0   0 my $self = shift;
154              
155 0         0 return $self->get_archive()->get_last_line();
156              
157             }
158              
159             sub _set_last_line {
160              
161 0     0   0 my $self = shift;
162 0         0 my $value = shift;
163              
164 0         0 $self->get_archive()->set_last_line($value);
165              
166             }
167              
168             sub _delete_old {
169              
170 0     0   0 my $self = shift;
171 0         0 my $procs_ref = shift;
172 0         0 my $archived = $self->get_archive->get_set();
173 0         0 my $new = Set::Tiny->new( keys( %{$procs_ref} ) );
  0         0  
174 0         0 my $to_delete = $archived->difference($new);
175              
176 0         0 foreach my $pid ( $to_delete->members ) {
177              
178 0         0 $self->get_archive()->remove($pid);
179              
180             }
181              
182             }
183              
184             sub _to_add {
185              
186 0     0   0 my $self = shift;
187 0         0 my $procs_ref = shift;
188 0         0 my $archived = $self->get_archive->get_set();
189 0         0 my $new = Set::Tiny->new( keys( %{$procs_ref} ) );
  0         0  
190 0         0 return $new->difference($archived);
191              
192             }
193              
194             sub _add_new {
195              
196 0     0   0 my $self = shift;
197 0         0 my $to_add = shift;
198 0         0 my $procs_ref = shift;
199              
200 0         0 foreach my $pid ( $to_add->members ) {
201              
202 0         0 $self->get_archive->add( $pid, $procs_ref->{$pid}->get_comp_alias() );
203              
204             }
205              
206             }
207              
208             sub _recover {
209              
210 1     1   2 my $self = shift;
211 1         2 my $procs_ref = shift;
212 1         2 my $ent_log = shift;
213 1         2 my $create_regex = shift;
214 1         2 my %comps;
215              
216 1         28 my $next = $ent_log->read();
217 1         46 my $field_delim = $ent_log->get_fs();
218 1         40 local $/ = $ent_log->get_eol();
219              
220             # for performance reasons this loop is duplicated in res_find_pid
221 1         5 while ( my $line = $next->() ) {
222              
223 49         299 chomp($line);
224 49         276 my @parts = split( /$field_delim/, $line );
225 49 100       138 next unless ( scalar(@parts) >= 7 );
226              
227             #ServerLog ProcessCreate 1 0000149754f82575:0 2015-03-05 13:15:41 Created multithreaded server process (OS pid = 9645 ) for FSMSrvr
228 34 100       144 if ( $parts[1] eq 'ProcessCreate' ) {
229              
230 8 50       75 if ( $parts[5] =~ $create_regex ) {
231              
232 8         30 $parts[7] =~ s/\s(\w)+\s//;
233 8         17 $parts[7] =~ tr/)//d;
234              
235             # pid => component alias
236 8         21 $comps{ $parts[6] } = $parts[7];
237 8         32 next;
238              
239             }
240             else {
241              
242 0         0 cluck
243             "Found a process creation statement but I cannot match process_regex against '$parts[5]'. Check the regex";
244              
245             }
246              
247             }
248              
249             }
250              
251 1         3 foreach my $proc_pid ( keys( %{$procs_ref} ) ) {
  1         4  
252              
253 1 50       5 if ( exists( $comps{$proc_pid} ) ) {
254              
255 1         51 $procs_ref->{$proc_pid}->set_comp_alias( $comps{$proc_pid} );
256              
257             }
258              
259             }
260              
261             }
262              
263             # restrict find the pid by ignoring previous read line from the Siebel Enterprise log file
264             sub _archived_recover {
265              
266 0     0     my $self = shift;
267 0           my $procs_ref = shift;
268 0           my $ent_log = shift;
269 0           my $create_regex = shift;
270 0           my %comps;
271              
272 0           my $next = $ent_log->read();
273 0           my $field_delim = $ent_log->get_fs();
274 0           $self->get_archive()->validate_archive( $ent_log->get_header() );
275 0           local $/ = $ent_log->get_eol();
276              
277 0           my $last_line = $self->_get_last_line();
278              
279             # for performance reasons this loop is duplicated in find_pid
280 0           while ( my $line = $next->() ) {
281              
282 0 0 0       next unless ( ( $last_line == 0 ) or ( $. > $last_line ) );
283 0           chomp($line);
284 0           my @parts = split( /$field_delim/, $line );
285              
286 0 0         next unless ( scalar(@parts) >= 7 );
287              
288             #ServerLog ProcessCreate 1 0000149754f82575:0 2015-03-05 13:15:41 Created multithreaded server process (OS pid = 9645 ) for FSMSrvr
289 0 0         if ( $parts[1] eq 'ProcessCreate' ) {
290              
291 0 0         if ( $parts[5] =~ $create_regex ) {
292              
293 0           $parts[7] =~ s/\s(\w)+\s//;
294 0           $parts[7] =~ tr/)//d;
295              
296             # pid => component alias
297 0           $comps{ $parts[6] } = $parts[7];
298 0           next;
299              
300             }
301             else {
302              
303 0           cluck
304             "Found a process creation statement but I cannot match process_regex against '$parts[5]'. Check the regex";
305              
306             }
307              
308             }
309              
310             }
311              
312 0           $self->_set_last_line($.);
313              
314             # consider that PIDS not available anymore in the /proc are gone and should be removed from the cache
315 0           $self->_delete_old($procs_ref);
316              
317             # must keep the pids to add before modifying the procs_ref
318 0           my $to_add = $self->_to_add($procs_ref);
319 0           my $cached = $self->get_archive()->get_set();
320              
321 0           foreach my $proc_pid ( keys( %{$procs_ref} ) ) {
  0            
322              
323 0 0 0       if ( ( exists( $comps{$proc_pid} ) ) and ( $cached->has($proc_pid) ) ) {
324              
325             # new reads from log has precendence over the cache, so cache must be also updated
326 0           $procs_ref->{$proc_pid}->set_comp_alias( $comps{$proc_pid} );
327 0           $self->get_archive()->remove($proc_pid);
328 0           next;
329              
330             }
331              
332 0 0         if ( exists( $comps{$proc_pid} ) ) {
    0          
333              
334 0           $procs_ref->{$proc_pid}->{comp_alias} = $comps{$proc_pid};
335              
336             }
337             elsif ( $cached->has($proc_pid) ) {
338              
339             $procs_ref->{$proc_pid}->{comp_alias} =
340 0           $self->get_archive()->get_alias($proc_pid);
341              
342             }
343              
344             }
345              
346 0           $self->_add_new( $to_add, $procs_ref );
347              
348             }
349              
350             =head1 SEE ALSO
351              
352             =over
353              
354             =item *
355              
356             L<Moose>
357              
358             =item *
359              
360             L<Siebel::Srvrmgr::OS::Process>
361              
362             =back
363              
364             =head1 AUTHOR
365              
366             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
367              
368             =head1 COPYRIGHT AND LICENSE
369              
370             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
371              
372             This file is part of Siebel Monitoring Tools.
373              
374             Siebel Monitoring Tools is free software: you can redistribute it and/or modify
375             it under the terms of the GNU General Public License as published by
376             the Free Software Foundation, either version 3 of the License, or
377             (at your option) any later version.
378              
379             Siebel Monitoring Tools is distributed in the hope that it will be useful,
380             but WITHOUT ANY WARRANTY; without even the implied warranty of
381             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
382             GNU General Public License for more details.
383              
384             You should have received a copy of the GNU General Public License
385             along with Siebel Monitoring Tools. If not, see <http://www.gnu.org/licenses/>.
386              
387             =cut
388              
389             __PACKAGE__->meta->make_immutable;