File Coverage

blib/lib/Siebel/Srvrmgr/Log/Enterprise/Parser/Comp_alias.pm
Criterion Covered Total %
statement 49 114 42.9
branch 8 30 26.6
condition 0 6 0.0
subroutine 7 13 53.8
pod 1 1 100.0
total 65 164 39.6


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