/[mon-modules]/parse_log.cgi
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /parse_log.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (show annotations)
Tue Oct 7 14:39:58 2003 UTC (20 years, 5 months ago) by dpavlin
Branch: MAIN
Changes since 1.6: +9 -9 lines
fixed duration sorting

1 #!/usr/bin/perl -w
2
3 # parse file.alert mon logs and report (up|down)time of services
4 #
5 # 2003-09-03 Dobrica Pavlinusic <dpavlin@rot13.org>
6 # 2003-10-05 converted to CGI script
7 #
8
9 use strict;
10 use POSIX qw(strftime);
11 use CGI qw/:standard *table/;
12 use CGI::Carp qw(fatalsToBrowser);
13 use Data::Sorting qw(:arrays);
14 use Time::ParseDate;
15 use Time::Available;
16 use Cache::FileCache;
17
18 use Data::Dumper;
19
20 my $date_fmt = "%Y-%m-%d";
21 #my $date_time_fmt = "%Y-%m-%d %H:%M:%S";
22 my $date_time_fmt = "<small>%a</small> <nobr>%Y-%m-%d</nobr> %H:%M:%S";
23
24 my $from_date = "now - 6 months";
25 my $to_date = "now";
26
27 # working days definition (1-7; mon=1)
28 my $dayMask = Time::Available::DAY_WEEKDAY;
29 # working hours
30 my $from_time_interval = "7:00";
31 my $to_time_interval = "17:00";
32
33 my $debug=0;
34 $debug++ if (grep(/-v/,@ARGV));
35 $debug++ if (grep(/-d/,@ARGV));
36
37 my %days = (
38 Time::Available::DAY_MONDAY=>'Mo',
39 Time::Available::DAY_TUESDAY=>'Tu',
40 Time::Available::DAY_WEDNESDAY=>'We',
41 Time::Available::DAY_THURSDAY=>'Th',
42 Time::Available::DAY_FRIDAY=>'Fr',
43 Time::Available::DAY_SATURDAY=>'Sa',
44 Time::Available::DAY_SUNDAY=>'Su'
45 );
46
47 my $q = new CGI;
48
49 my $print_orphans = $q->param('print_orphans') || 0;
50 my $rep_reset = $q->param('rep_reset') || 0;
51 my @sg_selected = $q->param('sg_filter');
52
53 # init misc sort parametars
54 my @sort_rules;
55 my $order;
56 my %sort_param;
57 my ($usort,$dsort);
58 if ($q->param('usort')) {
59 $sort_param{'usort'} = $q->param('usort');
60 $q->delete('usort');
61 @sort_rules = ( -compare => 'numeric', scalar $sort_param{'usort'} );
62 }
63 if ($q->param('dsort')) {
64 $sort_param{'dsort'} = $q->param('dsort');
65 $q->delete('dsort');
66 @sort_rules = ( -compare => 'numeric', -order=>'reverse', scalar $sort_param{'dsort'} );
67 }
68
69 # make interval
70 my $working_days;
71 if ($q->param('use_time_limit')) {
72 $dayMask=0;
73 foreach my $dm ($q->param('day_interval')) {
74 $dayMask |= $dm;
75 }
76 $working_days=new Time::Available(start=>$q->param('from_time_interval'),end=>$q->param('to_time_interval'),dayMask=>$dayMask);
77 }
78
79 # init cache and setup expriration
80 my $cache = new Cache::FileCache({ default_expires_in => '10 min' });
81
82 #
83 # This option (activated via command switch -r) will reset failure duration
84 # if repeated failure on same group/service happend.
85 # If you want honest reporting (or grouped only by group and service),
86 # you souldn't turn it on :-) However, if you have just failure events in your
87 # log, this will produce output which will show duration BETWEEN two failures
88 #
89
90 # pretty format date
91 sub d {
92 my $utime = shift || return "?";
93 if ($debug) {
94 return strftime($date_time_fmt." [%s]",localtime($utime));
95 } else {
96 return strftime($date_time_fmt,localtime($utime));
97 }
98 }
99 # pretty format duration
100 sub dur {
101 my $dur = shift || return "0";
102 my $out = "";
103
104 my $s = $dur;
105 my $d = int($s/(24*60*60));
106 $s = $s % (24*60*60);
107 my $h = int($s/(60*60));
108 $s = $s % (60*60);
109 my $m = int($s/60);
110 $s = $s % 60;
111
112 $out .= $d."d " if ($d > 0);
113 if ($debug) {
114 $out .= sprintf("%02d:%02d:%02d [%d]",$h,$m,$s, $dur);
115 } else {
116 $out .= sprintf("%02d:%02d:%02d",$h,$m,$s);
117 }
118
119 return $out;
120 }
121
122 # read log and calculate
123 #
124
125 my %fail;
126 my $sg_filter; # filter for service/group
127
128 my $log_file="/var/log/mon/sap.log";
129
130 my $data;
131
132 # generate unique key for this data and options
133 my $cache_key="monlog".join("|",@sg_selected)."|".$print_orphans."|".$rep_reset;
134
135 # debug disables cache
136 if (! $debug) {
137 $data = $cache->get( $cache_key );
138 $sg_filter = $cache->get("sg_filter $cache_key");
139 }
140
141 if (!$data || !$sg_filter) {
142
143 open(LOG, $log_file) || die "$log_file: $!";
144
145 while(<LOG>) {
146 chomp;
147 if (/^(failure|up)\s+(\S+)\s+(\S+)\s+(\d+)\s+\(([^)]+)\)\s+(.+)$/) {
148 my ($status,$group,$service,$utime,$date,$desc) = ($1,$2,$3,$4,$5,$6);
149 my $id = "$group/$service";
150 if ($status eq "up" && defined($fail{$id})) {
151 if (grep(m;$group/$service;,@sg_selected)) {
152 push @$data, {
153 'sg'=>"$group/$service",
154 'from'=>$fail{$id},
155 'to'=>$utime,
156 'dur'=>($utime-$fail{$id}),
157 'desc'=>$desc };
158 }
159 $sg_filter->{"$group/$service"}++;
160 delete $fail{$id};
161 } elsif ($status eq "up") {
162 if ($print_orphans && grep(m;$group/$service;,@sg_selected)) {
163 push @$data, {
164 'sg'=>"$group/$service",
165 'from'=>-1,
166 'to'=>$utime,
167 'dur'=>0,
168 'desc'=>$desc };
169 }
170 delete $fail{$id};
171 $sg_filter->{"$group/$service"}++;
172 } elsif (defined($fail{$id})) {
173 if ($rep_reset && grep(m;$group/$service;,@sg_selected)) {
174 push @$data, {
175 'sg'=>"$group/$service",
176 'from'=>$fail{$id},
177 'to'=>$utime,
178 'dur'=>($utime-$fail{$id}),
179 'desc'=>'[failure again]'};
180 $fail{$id} = $utime;
181 }
182 $sg_filter->{"$group/$service"}++;
183 } else {
184 $fail{$id} = $utime;
185 }
186 }
187 }
188 close(LOG);
189
190 $cache->set($cache_key, $data);
191 $cache->set("sg_filter $cache_key", $sg_filter);
192
193 }
194
195 # generate output
196 #
197 print header,start_html("mon availiability report");
198
199 # make some filters
200 #
201
202 print start_form,
203 start_table({-border=>0,-cellspacing=>0,-cellpadding=>0}),
204 Tr(td(
205 em("Show just service/group:"),br,
206 checkbox_group(-name=>'sg_filter',
207 -values=>[keys %$sg_filter],
208 -default=>[keys %$sg_filter],
209 -linebreak=>'true',
210 ),
211 ),td(
212 em("Other options:"),br,
213 $q->checkbox(-name=>'rep_reset',-checked=>0,
214 -label=>"show repeated failures on same service as individual failures"),
215 br,
216 $q->checkbox(-name=>'print_orphans',-checked=>0,
217 -label=>"show records which are not complete in this interval"),
218 br,
219 $q->checkbox(-name=>'use_date_limit',-checked=>1,
220 -label=>"use date limit from:"),
221 $q->textfield(-name=>'from_date',-size=>20,-default=>$from_date),
222 " to: ",
223 $q->textfield(-name=>'to_date',-size=>20,-default=>$to_date),
224 small('Using <a href="http://search.cpan.org/search?mode=module&query=Time::ParseDate">Time::ParseDate</a>'),
225 br,
226 $q->checkbox(-name=>'use_time_limit',-checked=>1, -value=>'on',
227 -label=>"use time limit for each day:"),
228 $q->textfield(-name=>'from_time_interval',-size=>8,-default=>$from_time_interval),
229 " to: ",
230 $q->textfield(-name=>'to_time_interval',-size=>8,-default=>$to_time_interval),
231 br,"Days: ",
232 $q->checkbox_group(-name=>'day_interval',
233 -values=>[ sort { $a <=> $b } keys %days ],
234 -labels=>\%days,
235 -defaults=>[
236 Time::Available::DAY_MONDAY,
237 Time::Available::DAY_TUESDAY,
238 Time::Available::DAY_WEDNESDAY,
239 Time::Available::DAY_THURSDAY,
240 Time::Available::DAY_FRIDAY,
241 ]
242 ),
243 $q->submit(-name=>'show',-value=>'Show report'),
244 )),end_table,
245 end_form;
246
247 # dump report
248 #
249
250 my %dir_html_entity = (
251 # 'u' => '&uArr;',
252 # 'd' => '&dArr;'
253 'u' => '&#9650;',
254 'd' => '&#9660;',
255 );
256
257 sub sort_link {
258 my $q = shift || return;
259 my $col = shift || return;
260 my $dir = lc(shift) || return;
261 if ($sort_param{$dir.'sort'} && $sort_param{$dir.'sort'} eq $col) {
262 return $dir_html_entity{$dir};
263 } else {
264 return '<a href="'.$q->url(-query=>1).'&'.$dir.'sort='.$col.'">'.$dir_html_entity{$dir}.'</a>';
265 }
266 }
267
268
269 my ($from_time,$to_time,$from_html,$to_html);
270 if ($q->param('use_date_limit')) {
271 $from_time = parsedate($q->param('from_date'), UK=>1);
272 $to_time = parsedate($q->param('to_date'), UK=>1);
273 $from_html = strftime($date_fmt,localtime($from_time));
274 $to_html = strftime($date_fmt,localtime($to_time));
275 $from_html .= " [$from_time] " if ($debug);
276 $to_html .= " [$to_time] " if ($debug);
277 }
278
279 # sort data
280 #
281 my @sorted = sorted_array( @$data, @sort_rules );
282
283 print "-- sort: ",Dumper(@sort_rules)," (data: ".@$data." sorted: ".@sorted.") --\n",br,"-- dayMask: $dayMask --\n",br,"-- cache_key: $cache_key --\n",br if ($debug);
284
285 print start_table({-border=>1,-cellspacing=>0,-cellpadding=>2,-width=>'100%'});
286
287 print Tr(
288 th("group/service"),
289 th({-bgcolor=>'#f0f0f0'},'<nobr>'.
290 &sort_link($q,'from','u').' from '.
291 &sort_link($q,'from','d').'</nobr>',
292 br,$from_html
293 ),
294 th( '<nobr>'.
295 &sort_link($q,'to','u').' to '.
296 &sort_link($q,'to','d').'</nobr>',
297 br,$to_html
298 ),
299 th({-bgcolor=>'#e0e0e0'},'<nobr>'.
300 &sort_link($q,'dur','u').' duration '.
301 &sort_link($q,'dur','d').'</nobr>'
302 ),
303 th("description")
304 ) if (scalar @sorted > 0);
305
306 my $downtime; # total downtime
307 my $downinterval; # total downtime in time interval
308 my $sg_count; # count number of downtimes
309
310 foreach my $row (@sorted) {
311 next if ($q->param('use_date_limit') && ($row->{from} < $from_time || $row->{to} > $to_time));
312 my ($from,$dur,$int) = ('unknown','unknown','unknown');
313
314 if ($row->{from} != -1 ) {
315 $from = d($row->{from});
316 $dur = $row->{to} - $row->{from};
317 $downtime->{$row->{sg}} += $dur;
318 if ($q->param('use_time_limit')) {
319 $int = $working_days->interval($row->{from},$row->{to});
320 $dur = dur($int)."<br><nobr><small>&sum; ".dur($dur)."</small></nobr>";
321 $downinterval->{$row->{sg}} += $int;
322 } else {
323 $dur = dur($dur);
324 }
325 }
326 $sg_count->{$row->{sg}}++;
327
328 print Tr(
329 td({-align=>'left',-valign=>'center'},$row->{sg}),
330 td({-align=>'right',-bgcolor=>'#f0f0f0'},$from),
331 td({-align=>'right'},d($row->{to})),
332 td({-align=>'center',-bgcolor=>'#e0e0e0'},$dur),
333 td({-align=>'left'},$row->{desc}),
334 ),"\n";
335 }
336
337 # dump totals
338 #
339
340 foreach my $sg (keys %$downtime) {
341 my $dur;
342 if ($downinterval->{$sg}) {
343 $dur=dur($downinterval->{$sg})."<br><nobr><small>&sum; ".dur($downtime->{$sg})."</small></nobr>";
344 } else {
345 $dur=dur($downtime->{$sg});
346 }
347 print Tr(td({-colspan=>3,-align=>'right'},"total for $sg:"),
348 td({-bgcolor=>'#e0e0e0',-align=>'right'},$dur),
349 td(small("in ".$sg_count->{$sg}." failures"))),"\n";
350 }
351
352 print end_table;
353

  ViewVC Help
Powered by ViewVC 1.1.26