Commit | Line | Data |
---|---|---|
9e8e5516 C |
1 | #!/usr/bin/perl |
2 | # $Source: /f/osi/others/ntp/RCS/stat.pl,v $ $Revision: 7.1 $ $Date: 91/02/22 09:34:10 $ | |
3 | # | |
4 | # Make plots from ntpd syslog messages. Invoked as: | |
5 | # | |
6 | # stat.pl [-o outputfile] [-i interval] [-t termtype] [-S] [-l] < logmessages | |
7 | # | |
8 | # Where interval is the number of hours per plot, default is all data on | |
9 | # on set of plots. | |
10 | # | |
11 | # termtype is the terminal type passed to gnuplot. Default is postscript, | |
12 | # other useful alternative include 'tek', or 'unixplot' | |
13 | # | |
14 | # output file is the name of the file which will receive plot data. The | |
15 | # default is "stats.plot". | |
16 | # | |
17 | # The -l option will also create log scale plots. | |
18 | # | |
19 | # The -S option will "save" the intermedite data files, which are normally | |
20 | # deleted. | |
21 | # | |
22 | # Louis A. Mamakos <louie@TRANTOR.UMD.EDU> | |
23 | # with many thanks to Larry Wall for `perl', a wonderful tool for hacking | |
24 | # up things like this so easily. | |
25 | # | |
26 | ||
27 | # | |
28 | # Mar 7 18:46:58 trantor ntpd[20838]: adjust: SLEW 192.41.177.92 st 2 | |
29 | # off -0.015756 drft 0.000000 cmpl 0.000000 | |
30 | # Mar 10 08:56:19 trantor ntpd[27755]: clock: select peer 128.8.10.1 stratum 1 | |
31 | # was 130.126.174.40 stratum 1 | |
32 | # Mar 31 16:55:19 trantor ntpd[2195]: /usr/local/etc/ntpd version $Revision: | |
33 | # 3.4.1.5 $# | |
34 | # | |
35 | $scriptfile = $0; | |
36 | ||
37 | $month{'Jan'} = 0; $month{'Feb'} = 1; $month{'Mar'} = 2; $month{'Apr'} = 3; | |
38 | $month{'May'} = 4; $month{'Jun'} = 5; $month{'Jul'} = 6; $month{'Aug'} = 7; | |
39 | $month{'Sep'} = 8; $month{'Oct'} = 9; $month{'Nov'} = 10; $month{'Dec'} = 11; | |
40 | ||
41 | # | |
42 | # Currently, the year is not included in the syslog messages. We'll have to | |
43 | # assume that the log files be processed were written this year. | |
44 | # | |
45 | ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); | |
46 | ||
47 | if ($year % 4) { | |
48 | # not leap year | |
49 | $days[0] = 0; $days[1] = 31; $days[2] = 59; $days[3] = 90; | |
50 | $days[4] = 120; $days[5] = 151; $days[6] = 181; $days[7] = 212; | |
51 | $days[8] = 243; $days[9] = 273; $days[10] = 304; $days[11] = 334; | |
52 | } else { | |
53 | # leap year | |
54 | $days[0] = 0; $days[1] = 31; $days[2] = 60; $days[3] = 91; | |
55 | $days[4] = 121; $days[5] = 152; $days[6] = 182; $days[7] = 213; | |
56 | $days[8] = 244; $days[9] = 274; $days[10] = 305; $days[11] = 335; | |
57 | } | |
58 | ||
59 | die "Can't open drift compansation file\n" unless open(DRIFT, ">stats.drift"); | |
60 | die "Can't open offset file\n" unless open(OFF, ">stats.off"); | |
61 | die "Can't open compliance file\n" unless open(COMP, ">stats.comp"); | |
62 | die "Can't open clock file\n" unless open(CLK, ">stats.clk"); | |
63 | ||
64 | $# = '%.6g'; | |
65 | $plottype = "postscript"; | |
66 | $recs = 0; | |
67 | $start = 0; | |
68 | $clocks = 1; | |
69 | $clk{'UNSYNCED'} = 0; | |
70 | ||
71 | do Getopt('tio'); | |
72 | ||
73 | if ($opt_h) { | |
74 | die "Usage: $scriptfile [-o outputfile] [-i interval] [-t termtype] [-l] [-S] < logmessages\n"; | |
75 | } | |
76 | ||
77 | if ($opt_t) { | |
78 | $plottype = $opt_t; | |
79 | } | |
80 | ||
81 | if ($opt_i) { | |
82 | $interval = $opt_i; | |
83 | } else { | |
84 | $interval = 99999999; | |
85 | } | |
86 | ||
87 | while (<>) { | |
88 | if (/.* ntpd\[[0-9]*\]: (.*\/ntpd) version \$Revision: \b(.*)\b/) { | |
89 | chop; | |
90 | @in = split; | |
91 | $recs++; | |
92 | $revision = $1 . " " . $2; | |
93 | ||
94 | print "Revision $revision\n"; | |
95 | ||
96 | @time = split(/:/,$in[2]); | |
97 | $t = $in[1]*24 + $time[0] + $time[1]/60 + $time[2]/3600 + | |
98 | $days[$month{$in[0]}]*24; | |
99 | ||
100 | if (!$start) { | |
101 | $start = $t; | |
102 | printf "Start time is %s %s %s\n",$in[0],$in[1],$in[2]; | |
103 | } | |
104 | } | |
105 | if (/.* ntpd\[[0-9]*\]: clock:/) { | |
106 | chop; | |
107 | @in = split; | |
108 | @time = split(/:/,$in[2]); | |
109 | $t = $in[1]*24 + $time[0] + $time[1]/60 + $time[2]/3600 + | |
110 | $days[$month{$in[0]}]*24; | |
111 | ||
112 | if (!$start) { | |
113 | $start = $t; | |
114 | printf "Start time is %s %s %s\n",$in[0],$in[1],$in[2]; | |
115 | } | |
116 | if (!$clk{$in[8]}) { | |
117 | printf "Clock %d is %s\n", $clocks, $in[8]; | |
118 | $clk{$in[8]} = $clocks++; | |
119 | } | |
120 | $t = $t - $start; | |
121 | print CLK $t," ",$clk{$in[8]},"\n"; | |
122 | ||
123 | } | |
124 | if (/.* ntpd\[[0-9]*\]: adjust:/) { | |
125 | chop; | |
126 | @in = split; | |
127 | $recs++; | |
128 | ||
129 | @time = split(/:/,$in[2]); | |
130 | $t = $in[1]*24 + $time[0] + $time[1]/60 + $time[2]/3600 + | |
131 | $days[$month{$in[0]}]*24; | |
132 | if (!$start) { | |
133 | $start = $t; | |
134 | printf "Start time is %s %s %s\n",$in[0],$in[1],$in[2]; | |
135 | } | |
136 | ||
137 | $t = $t - $start; | |
138 | ||
139 | # offset=11 drift=13 compliance=15 | |
140 | ||
141 | print OFF $t, " ", $in[11],"\n"; | |
142 | # | |
143 | # Scale the drift compensation by 256.0 to convert to PPM. | |
144 | # | |
145 | print DRIFT $t," ", $in[13]/256.0, "\n"; | |
146 | ||
147 | # | |
148 | # Scale compliance by T (2**18) | |
149 | # | |
150 | if ( $in[15] < 0 ) { | |
151 | $in[15] = -$in[15]; | |
152 | } | |
153 | print COMP $t," ",$in[15] * 2**18, "\n"; | |
154 | } | |
155 | } | |
156 | ||
157 | if ($t = int($t)) { | |
158 | $last = int($t) + 1; | |
159 | } else { | |
160 | $last = int($t); | |
161 | } | |
162 | print "$recs records spanning $t hours.\n"; | |
163 | ||
164 | close OFF; | |
165 | close DRIFT; | |
166 | close COMP; | |
167 | close CLK; | |
168 | ||
169 | if ($last == $start) { | |
170 | unlink "stats.script"; | |
171 | unlink "stats.drift"; | |
172 | unlink "stats.off"; | |
173 | unlink "stats.comp"; | |
174 | unlink "stats.clk"; | |
175 | die "No statistics records found\n"; | |
176 | } | |
177 | ||
178 | die "Can't open script file\n" unless open(TMP, ">stats.script"); | |
179 | # | |
180 | # Write script file for GNU plot. Generate multiple sets of plots, each set | |
181 | # displaying the data over a specified interval. | |
182 | # | |
183 | print TMP "set samples ",$recs,"\n"; | |
184 | print TMP "set term $plottype\n"; | |
185 | ||
186 | if ($opt_o) { | |
187 | printf TMP 'set output "%s"', $opt_o; print TMP "\n"; | |
188 | } else { | |
189 | print TMP 'set output "stats.plot"'; print TMP "\n"; | |
190 | } | |
191 | ||
192 | if ($interval > $last) { | |
193 | if ($interval != 99999999) { | |
194 | print "Interval truncated to available data ($last)\n"; | |
195 | } | |
196 | $interval = $last; | |
197 | } | |
198 | # | |
199 | # Plot multiple sets of plots, each set of which covers the specified number | |
200 | # of hours. | |
201 | # | |
202 | $start = 0; | |
203 | $end = $interval; | |
204 | while (($start < $last)) { | |
205 | print TMP "set autoscale\n"; | |
206 | print TMP "plot [$start:$end] ",'"stats.drift"'," with lines\n"; | |
207 | print TMP "plot [$start:$end] ",'"stats.comp"'," with lines\n"; | |
208 | if ($opt_l) { | |
209 | print TMP "set logscale y\n"; | |
210 | print TMP "plot [$start:$end] ",'"stats.comp"'," with lines\n"; | |
211 | print TMP "set nologscale\n"; | |
212 | } | |
213 | print TMP "plot [$start:$end] [-0.1:0.1] ", | |
214 | '"stats.off"'," with lines\n"; | |
215 | print TMP "plot [$start:$end] [0:$clocks]", | |
216 | '"stats.clk"'," with impulse\n"; | |
217 | $start = $end; | |
218 | $end += $interval; | |
219 | } | |
220 | close TMP; | |
221 | ||
222 | # | |
223 | # Now, run gnuplot on the script file. | |
224 | # | |
225 | system "gnuplot < stats.script > /dev/null 2>&1" || | |
226 | die "gnuplot croaked: exit=" . $? . "\n"; | |
227 | ||
228 | if (!$opt_S) { | |
229 | unlink "stats.script"; | |
230 | unlink "stats.drift"; | |
231 | unlink "stats.off"; | |
232 | unlink "stats.comp"; | |
233 | unlink "stats.clk"; | |
234 | } | |
235 | \f | |
236 | ;# Process single-character switches with switch clustering. Pass one argument | |
237 | ;# which is a string containing all switches that take an argument. For each | |
238 | ;# switch found, sets $opt_x (where x is the switch name) to the value of the | |
239 | ;# argument, or 1 if no argument. Switches which take an argument don't care | |
240 | ;# whether there is a space between the switch and the argument. | |
241 | ||
242 | ;# Usage: | |
243 | ;# do Getopt('oDI'); # -o, -D & -I take arg. Sets opt_* as a side effect. | |
244 | ||
245 | sub Getopt { | |
246 | local($argumentative) = @_; | |
247 | local($_,$first,$rest); | |
248 | ||
249 | while (($_ = $ARGV[0]) =~ /^-(.)(.*)/) { | |
250 | ($first,$rest) = ($1,$2); | |
251 | if (index($argumentative,$first) >= $[) { | |
252 | if ($rest ne '') { | |
253 | shift; | |
254 | } | |
255 | else { | |
256 | shift; | |
257 | $rest = shift; | |
258 | } | |
259 | eval "\$opt_$first = \$rest;"; | |
260 | } | |
261 | else { | |
262 | eval "\$opt_$first = 1;"; | |
263 | if ($rest ne '') { | |
264 | $ARGV[0] = "-$rest"; | |
265 | } | |
266 | else { | |
267 | shift; | |
268 | } | |
269 | } | |
270 | } | |
271 | } | |
272 | ||
273 | # | |
274 | # Local Variables: | |
275 | # mode: text | |
276 | # End: |