-
Notifications
You must be signed in to change notification settings - Fork 36
/
squid-analyzer
307 lines (266 loc) · 10.2 KB
/
squid-analyzer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#!/usr/bin/env perl
#
# Perl frontend to SquidAnalyzer.pm.
#
use strict;
use SquidAnalyzer;
use Getopt::Long qw(:config no_ignore_case bundling);
use Benchmark;
use POSIX ":sys_wait_h";
use Time::Local;
use File::Spec qw/ tmpdir /;
use File::Temp qw/ tempfile /;
$| = 1;
my $DEFAULT_CONFFILE = '/etc/squidanalyzer/squidanalyzer.conf';
my @logfile = ();
my $obsolete = 0;
my $configfile = '';
my $help = '';
my $rebuild = '';
my $preserve = '';
my $debug = 0;
my $version = 0;
my $build_date = '';
my $pid_dir = File::Spec->tmpdir() || '/tmp';
my $pidfile = 'squid-analyzer.pid';
my $queue_size = 0;
my $timezone = '';
my $no_year_stat = 0;
my $with_month_stat = 0;
my $no_week_stat = 0;
my $t0 = Benchmark->new;
my $start_time = '';
my $stop_time = '';
my $start_date = '';
my $stop_date = '';
my $outputdir = '';
my $skip_history = 0;
my $override_history = 0;
my $refresh_time = 0;
# get the command line parameters
my $result = GetOptions (
"c|configfile=s" => \$configfile,
"b|build_date=s" => \$build_date,
"d|debug!" => \$debug,
"h|help" => \$help,
"j|jobs=i" => \$queue_size,
"l|logfile" => \$obsolete,
"o|outputdir=s" => \$outputdir,
"p|preserve=i" => \$preserve,
"P|pid_dir=s" => \$pid_dir,
"r|rebuild!" => \$rebuild,
"R|refresh=i" => \$refresh_time,
"s|start=s" => \$start_time,
"S|stop=s" => \$stop_time,
"t|timezone=s" => \$timezone,
"v|version!" => \$version,
"no-year-stat!" => \$no_year_stat,
"no-week-stat!" => \$no_week_stat,
"with-month-stat!" => \$with_month_stat,
"startdate=s" => \$start_date,
"stopdate=s" => \$stop_date,
"skip-history!" => \$skip_history,
"override-history!" => \$override_history,
);
# Show warning for obsolete options
if ($obsolete) {
print STDERR "WARNING: use of obsolete -l option, log files must be given at command line arguments.\n"
}
# Show version and exit
if ($version || $debug) {
print "SquidAnalyzer version $SquidAnalyzer::VERSION\n";
exit 0 if ($version);
}
if ($build_date) {
$rebuild = 1;
if ( ($build_date !~ /^\d{4}-\d{2}-\d{2}$/) && ($build_date !~ /^\d{4}-\d{2}$/) && ($build_date !~ /^\d{4}$/) ) {
die("FATAL: bad syntax for build_date, expecting format: yyyy-mm-dd, yyyy-mm or yyyy\n");
exit 0;
}
}
if ($start_time && $start_time !~ /^[0-2]\d:[0-5]\d$/) {
die("FATAL: bad format on start time, must be HH:MM.\n");
}
if ($stop_time && $stop_time !~ /^[0-2]\d:[0-5]\d$/) {
die("FATAL: bad format on stop time, must be HH:MM.\n");
}
if ($start_date && $start_date !~ /^\d{4}[-\\\/]?[0-1]\d[-\\\/]?[0-3]\d\s*[0-2]\d[-:]?[0-5]\d[-:]?[0-5]\d$/) {
die("FATAL: bad format on start date, must be YYYYMMDDHHMMSS.\n");
}
$start_date =~ s/[-\\\/:\s]//g if ($start_date);
if ($stop_date && $stop_date !~ /^\d{4}[-\\\/]?[0-1]\d[-\\\/]?[0-3]\d\s*[0-2]\d[-:]?[0-5]\d[-:]?[0-5]\d$/) {
die("FATAL: bad format on stop date, must be YYYYMMDDHHMMSS.\n");
}
$stop_date =~ s/[-\\\/:\s]//g if ($stop_date);
if ($override_history and ! $skip_history) {
die("FATAL: --override-history option can be used only with --skip-history.\nSee usage (--help) for more information.\n");
}
# Add multiple log files given from command line
foreach my $f (@ARGV) {
push(@logfile, $f) if (-f $f && !-z $f);
}
# Set default configuration file
$configfile ||= $DEFAULT_CONFFILE;
if ($help) {
&usage;
exit;
}
# Check if an other process is already running
if (-e "$pid_dir/$pidfile") {
die "FATAL: pid file ($pid_dir/$pidfile) exists, an other squid-analalyzer process may still running.\n";
}
# Write the pid file
open(OUT, ">$pid_dir/$pidfile") or die "FATAL: can not write to pid file $pid_dir/$pidfile, $!\n";
print OUT "$$";
close(OUT);
# Clear multiprocess temporary file if any
unlink("$pid_dir/last_parsed.tmp");
# Instanciate SquidAnalyzer.pm perl module
my $sa = new SquidAnalyzer($configfile, join(',', @logfile), $debug, $rebuild, $pid_dir, $pidfile, $timezone, $skip_history, $refresh_time);
$sa->{no_year_stat} = $no_year_stat;
$sa->{with_month_stat} = $with_month_stat;
$sa->{no_week_stat} = $no_week_stat;
$sa->{queue_size} = $queue_size;
$sa->{TimeStart} = $start_time;
$sa->{TimeStop} = $stop_time;
$sa->{OverrideHistory} = $override_history;
# Set start and end time (for custom date range reports)
if ($start_date && $start_date =~ /^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) {
my $t = timelocal($6, $5, $4, $3, $2-1, $1);
$sa->{report_starttime} = POSIX::strftime("%a %b %e %H:%M:%S %Y", localtime($t));
--$t; # 1 second less
$sa->{history_time} = $sa->{sg_history_time} = $sa->{ug_history_time} = "$t.999";
print STDERR "DEBUG: report start time set to $sa->{report_starttime}\n" if ($debug);
}
if ($stop_date && $stop_date =~ /^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) {
my $t = timelocal($6, $5, $4, $3, $2-1, $1);
$sa->{report_endtime} = POSIX::strftime("%a %b %e %H:%M:%S %Y", localtime($t));
$sa->{history_endtime} = "$t.999";
print STDERR "DEBUG: report end time set to $sa->{report_endtime}\n" if ($debug);
}
# Set output directory
if ($outputdir) {
die "ERROR: Invalid output directory name specified\n" if ($outputdir !~ /^[-\w\/]+$/);
$outputdir = "$sa->{Output}/$outputdir" if ($outputdir !~ /^\//);
if (! -e $outputdir) {
mkdir ($outputdir) || die "ERROR: can't create directory $outputdir, $!\n";
}
$sa->{Output} = $outputdir;
print STDERR "DEBUG: Output directory set to $outputdir\n" if ($debug);
}
# Die cleanly on signal
sub terminate
{
# block signal
local $SIG{TERM} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
print("LOG: Received terminating signal.\n");
$sa->{terminate} = 1;
# Save last parse line
$sa->save_current_line();
# Wait for all child processes to die except for the logger
my $kid = 0;
do {
sleep(1);
$kid = waitpid(-1, WNOHANG);
} while ($kid > 0);
# Removed pid iand temp file
if (-e "$pid_dir/$pidfile") {
unlink("$pid_dir/$pidfile") or print("ERROR: Unable to remove pid file $pid_dir/$pidfile, $!\n");
}
foreach my $tmp_file ('last_parsed.tmp', 'sg_last_parsed.tmp', 'ug_last_parsed.tmp')
{
if (-e "$pid_dir/$tmp_file")
{
unlink("$pid_dir/$tmp_file") or print("ERROR: Unable to remove temp file $pid_dir/$tmp_file, $!\n");
}
}
exit 0;
}
# Handle signals to die cleanly
$SIG{'INT'} = \&terminate;
$SIG{'TERM'} = \&terminate;
$SIG{'CHLD'} = 'DEFAULT';
$SIG{'HUP'} = 'IGNORE'; # don't die on HUP
my $t1;
# Run parsing only if we have a log file or that we are not in rebuild mode
if (!$rebuild || ($#{$sa->{LogFile}} >= 0)) {
$sa->parseFile();
if ($debug) {
$t1 = Benchmark->new;
my $td = timediff($t1, $t0);
print STDERR "DEBUG: the log statistics gathering took:", timestr($td), "\n";
}
}
# Remove old statistics
if ($preserve) {
$sa->{preserve} = $preserve;
}
# In rebuild mode history time is not use and we must store the
# specific rebuild date if any is provided at command line.
if ($rebuild) {
$sa->{history_time} = $sa->{sg_history_time} = $sa->{ug_history_time} = '';
$sa->{build_date} = $build_date;
}
# Generate graphics and html
$sa->buildHTML();
if ($debug) {
my $t2 = Benchmark->new;
if (defined $t1) {
my $td = timediff($t2, $t1);
print STDERR "DEBUG: generating HTML output took:", timestr($td), "\n";
}
my $td = timediff($t2, $t0);
print STDERR "DEBUG: total execution time:", timestr($td), "\n";
}
# Remove PID file
unlink("$pid_dir/$pidfile");
exit(0);
sub usage
{
print qq{
Usage: squid-analyzer [ -c squidanalyzer.conf ] [logfile(s)]
-c | --configfile filename : path to the SquidAnalyzer configuration file.
By default: $DEFAULT_CONFFILE
-b | --build_date date : set the date to be rebuilt, format: yyyy-mm-dd
or yyyy-mm or yyyy. Used with -r or --rebuild.
-d | --debug : show debug information.
-h | --help : show this message and exit.
-j | --jobs number : number of jobs to run at same time. Default
is 1, run as single process.
-o | --outputdir name : set output directory. If it does not start
with / then prefixes Output from configfile
-p | --preserve number : used to set the statistic obsolescence in
number of month. Older stats will be removed.
-P | --pid_dir directory : set directory where pid file will be stored.
Default /tmp/
-r | --rebuild : use this option to rebuild all html and graphs
output from all data files.
-R | --refresh minutes : add a html refresh tag into index.html file
with a refresh intervalle in minutes.
-s | --start HH:MM : log lines before this time will not be parsed.
-S | --stop HH:MM : log lines after this time will not be parsed.
-t | --timezone +/-HH : set number of hours from GMT of the timezone.
Use this to adjust date/time of SquidAnalyzer
output when it is run on a different timezone
than the squid server.
-v | version : show version and exit.
--no-year-stat : disable years statistics, reports will start
from month level only.
--no-week-stat : disable weekly statistics.
--with-month-stat : enable month stats when --no-year-stat is used.
--startdate YYYYMMDDHHMMSS : lines before this datetime will not be parsed.
--stopdate YYYYMMDDHHMMSS : lines after this datetime will not be parsed.
--skip-history : used to not take care of the history file. Log
parsing offset will start at 0 but old history
file will be preserved at end. Useful if you
want to parse and old log file.
--override-history : when skip-history is used the current history
file will be overriden by the offset of the
last log file parsed.
Log files to parse can be given as command line arguments or as a comma separated
list of file for the LogFile configuration directive. By default SquidAnalyer will
use file: /var/log/squid/access.log
};
exit 0;
}