calamaris-2.99.4.7/0000755000175000017500000000000014161616434012366 5ustar cordcordcalamaris-2.99.4.7/calamaris0000755000175000017500000061741314161616434014264 0ustar cordcord#!/usr/bin/perl -w # # DESCRIPTION: calamaris - statistic package for diverse Proxy-Cache-Servers # $VERSION = '2.99.4.7'; # # Copyright (C) 1997-2006, 2013, 2015, 2017, 2021 # Cord Beermann # # URL: https://Calamaris.Cord.de/ # Announcement-Mailing-list: send Mail with 'subscribe' in the Mail-Body to # Calamaris-announce-request@Cord.de # # AUTHORS: Cord Beermann # Michael Pophal # # Als a big thanks to all contributors, bug reporters, and feature # requesters: # Please see the CONTRIBUTORS file. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # (If you modify and want to publish it under the name 'Calamaris', please ask # me. I don't want to confuse the 'audience' with many different versions of # the same name and/or Version number. (This is not part of the license, it # is only a favour i asked of you.)) # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 59 Temple # Place - Suite 330, Boston, MA 02111-1307, USA. # A Perl script is "correct" if it gets the job done before your boss fires # you. # -- 'Programming Perl Second Edition' # by Larry Wall, Tom Christiansen & Randal L. Schwartz # If you have to remove this, read the README! require 5.002; # if you can't use Graphics, you should point this to a directory where calamaris/*.pm is located. # use lib '/usr/local'; use Getopt::Long; Getopt::Long::Configure("bundling"); GetOptions( "all-useful-reports|a" => \$opt_a, "benchmark|b=i" => \$opt_b, "cache-input-file|i=s" => \$opt_i, "cache-output-file|o=s" => \$opt_o, "config-file=s" => \$opt_config_file, "copyright|C" => \$opt_C, "domain-report|d=i" => \$opt_d, "domain-report-limit=i" => \$opt_domain_report_limit, "domain-report-n-level|N=i" => \$opt_N, "dump-loop|L" => \$opt_L, "errorcode-distribution-report" => \$opt_errorcode_distribution, "generate-index" => \$opt_generate_index, "help|h" => \$opt_h, "hostname|H=s" => \$opt_H, "input-format|f=s" => \$opt_f, "image-type=s" => \$opt_image_type, "ipfilter-exclude=s" => \$opt_ipfilter_exclude, "ipfilter-include=s" => \$opt_ipfilter_include, "logo|l=s" => \$opt_l, "meta|M=s" => \$opt_M, "no-input|z" => \$opt_z, "output-file=s" => \$opt_output_file, "output-file-prefix=s" => \$opt_output_file_prefix, "output-format|F=s" => \$opt_F, "output-path=s" => \$opt_output_path, "peak-report|p=s" => \$opt_p, "performance-report|P=i" => \$opt_P, "performance-report_adjust|T=i" => \$opt_T, "requester-report|r=i" => \$opt_r, "requester-report-no-dns-lookup|n" => \$opt_n, "requester-report-use-user-info|u" => \$opt_u, "requester-report-with-targets|R=i" => \$opt_R, "response-time-report" => \$opt_response_time, "show-reports|S=s" => \$opt_S, "size-distribution-report|D=i" => \$opt_D, "sort-order|O" => \$opt_O, "status-report|s" => \$opt_s, "time-interval|I=s" => \$opt_I, "type-report|t=i" => \$opt_t, "type-report-ignore-case|c" => \$opt_c, "unit|U=s" => \$opt_U, "verbose|v" => \$opt_v, "version|V" => \$opt_V, ); readconfig(); unless ($opt_n) { use Socket qw(:DEFAULT inet_pton getnameinfo); } print "$USAGE\n\n" if $opt_h; print "Calamaris $VERSION\n\n" if $opt_V; print "$COPYRIGHT\n\n$LICENSE\n\n$HOMEPAGE\n" if $opt_C or $opt_h or $opt_V; exit 0 if $opt_h or $opt_C or $opt_V; if ($usage_err) { print STDERR "run '$0 -h' for help.\n\n"; exit 1; } # initialize variables $test_string = "\nTest results:\n\n" if $test; $counter = $hier = $hier_direct = $hier_direct_size = $hier_direct_time = $hier_parent = $hier_parent_size = $hier_parent_time = $hier_sibling = $hier_sibling_size = $hier_sibling_time = $hier_size = $hier_time = $invalid = $ordered_tcp_req_time_max = $ordered_tcp_req_time_max_interval = $ordered_udp_req_time_max = $ordered_udp_req_time_max_interval = $peak_all_hour = $peak_all_hour_time = $peak_all_min = $peak_all_min_time = $peak_all_sec = $peak_all_sec_time = $peak_tcp_hour = $peak_tcp_hour_time = $peak_tcp_min = $peak_tcp_min_time = $peak_tcp_sec = $peak_tcp_sec_time = $peak_udp_hour = $peak_udp_hour_time = $peak_udp_min = $peak_udp_min_time = $peak_udp_sec = $peak_udp_sec_time = $size = $skipped = $tcp = $tcp_hit = $tcp_hit_size = $tcp_hit_time = $tcp_miss = $tcp_miss_none = $tcp_miss_none_size = $tcp_miss_none_time = $tcp_miss_size = $tcp_miss_time = $tcp_size = $tcp_time = $time = $time_end = $time_run = $udp = $udp_hit = $udp_hit_size = $udp_hit_time = $udp_miss = $udp_miss_size = $udp_miss_time = $udp_size = $udp_time = 0; $time_begin = 1e10; @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); undef(%udp_reqtime_size); undef(%udp_hit_reqtime_size); undef(%udp_hit_reqtime); undef(%tcp_reqtime_size); undef(%tcp_hit_reqtime_size); undef(%tcp_hit_reqtime); undef(%perf_ip); $loop = ''; readcache() if ($opt_i); unless ($opt_z) { while ( defined( $line = <> ) ) { if ( not defined $opt_f or $opt_f eq 'auto' ) { if ( $line =~ m#^\s*\d+\.\d+\s+\d+\s+[\w\-\.:]+\s+\w+/\d+\s+\d+\s+[\w-]+\s+\S+\s+\S+\s+\w+/\S+\s+\S+$# ) { $opt_f = 'squid'; print STDERR "guessing... using '-f squid'\n" if ($opt_v); last; } elsif ( $line =~ m#^\d+\s+\d+\s+[\w\-\.:]+\s+\w+/\d+\s+\d+\s+\w+\s+\S+\s+\S+\s+\w+/\S+\s+\S+$# ) { $opt_f = 'its'; print STDERR "guessing... using '-f its'\n" if ($opt_v); last; } elsif ( $line =~ m#^\d+\.\d+\s+\d+\s+[\w\-\.:]+\s+\w+/\d+\s+\d+\s+\w+\s+\S+\s+\S+\s+\w+/\S+$# ) { $opt_f = 'squid-old'; print STDERR "guessing... using '-f squid-old'\n" if ($opt_v); last; } elsif ( $line =~ m#^\d+\.\d+\s+\d+\s+[\w\-\.:]+\s+\w+/\d+\s+\d+\s+\w+\s+\S+\s+\S+\s+\w+/\S+\s+(\S|; c)+\s+\S+$# ) { $opt_f = 'nc'; print STDERR "guessing... using '-f nc'\n" if ($opt_v); last; } elsif ( $line =~ s/^\s*#\s*Fields:\s*// ) { $opt_f = 'elff'; print STDERR "guessing... using '-f elff'\n" if ($opt_v); last; } elsif ( $line =~ s/^\s*format=\s*// ) { $opt_f = 'nse'; print STDERR "guessing... using '-f nse'\n" if ($opt_v); last; } elsif ( $line =~ m#^\d+\.\d+\s+\d+\s+[\w\-\.:]+\s+\w+/\-?\d+\s+\d+\s+[\w-]+\s+\S+\s+\S+\s+\w+/\S+\s+\S+\s+# ) { $opt_f = 'squid-extended'; print STDERR "guessing... using '-f squid-extended'\n" if ($opt_v); last; } elsif ( $line =~ m#^[\w\-\.:]+\s+\S+\s+\S+\s+\[.+\]\s+\"\w+\s+\S+\s+\S+\"\s+\d+\s+\d+\s+\S+(\s+\[.*\]\s+\[.*\])?$# ) { print STDERR "$0: The first line of the input looks to me as if you switched 'emulate_httpd_log' to on. I can't parse that format. Please read the README on this.\n\n"; exit(1); } elsif ( $line =~ m/^\s*(#|$)/ ) { print STDERR "skipping: $line\n" if ($opt_v); next; } else { print STDERR "$0: I don't know this input format. Please check the input. If you\'re sure that the following line is NOT corrupt and the error also occurs with the recent version of Calamaris (see the README for pointers and known bugs) then report it with the following line to . Thank You.\n\n$line\n\n"; exit(1); } } else { last; } } if ( not defined $opt_f or $opt_f eq 'auto' ) { print "\nno requests found\n"; exit(0); } # IP Filter my %filter_ip; if ($opt_ipfilter_exclude or $opt_ipfilter_include) { my $to_split = ($opt_ipfilter_exclude) ? $opt_ipfilter_exclude : $opt_ipfilter_include; foreach ( split /:/, $to_split ) { $ip = new NetAddr::IP( (split /\//, $_) ); foreach ( $ip->split('32') ) { $filter_ip{$_->addr()} = 1; } } } print STDERR "print a hash-sign for each $opt_b lines:\n" if ($opt_b); $loop .= ' for ( ; $line; $line = <> ) {'; if ( $opt_f eq 'squid' ) { $loop .= ' $line =~ s#^\s+##; ( $log_date, $log_reqtime, $log_requester, $log_status, $log_size, $log_method, $log_url, $log_ident, $log_hier, $log_content, $foo ) = split ( /\s+/, $line ); if ( not defined $foo or not defined $log_content or $foo ne \'\' or $log_content eq \'\' or $log_reqtime < 0 or $log_date !~ m#^\d+\.\d{3}$# ) {'; } elsif ( $opt_f eq 'squid-extended' ) { $loop .= ' $line =~ s/ \[[^\[\]]*\]//g; ( $log_date, $log_reqtime, $log_requester, $log_status, $log_size, $log_method, $log_url, $log_ident, $log_hier, $log_content) = split ( /\s+/, $line, 10 ); chomp($log_content); if ( not defined $log_content or $log_content eq \'\' or $log_reqtime < 0 or $log_date !~ m#^\d+\.\d{3}$# ) {'; } elsif ( $opt_f eq 'its' ) { $loop .= ' ( $log_date, $log_reqtime, $log_requester, $log_status, $log_size, $log_method, $log_url, $log_ident, $log_hier, $log_content, $foo ) = split ( /\s+/, $line ); if ( not defined $foo or not defined $log_content or $foo ne \'\' or $log_content eq \'\' or $log_reqtime < 0 or $log_date !~ m#^\d+$# ) {'; } elsif ( $opt_f eq 'squid-old' ) { $loop .= ' ( $log_date, $log_reqtime, $log_requester, $log_status, $log_size, $log_method, $log_url, $log_ident, $log_hier, $foo ) = split ( /\s+/, $line ); unless ( not defined $foo or not defined $log_hier or $foo ne \'\' or $log_hier eq \'\' or $log_reqtime < 0 or $log_date !~ m#^\d+\.\d{3}$# ) {'; } elsif ( $opt_f eq 'nc' ) { $loop .= ' $line =~ s#\; c#\;_c#og; # Hack to handle buggy logfiles of NetCache V3.2.x ( $log_date, $log_reqtime, $log_requester, $log_status, $log_size, $log_method, $log_url, $log_ident, $log_hier, $log_content, $log_abort, $foo ) = split ( /\s+/, $line ); if ( not defined $foo or not defined $log_abort or $foo ne \'\' or $log_abort eq \'\' or $log_reqtime < 0 or $log_date !~ m#^\d+\.\d{3}$# ) {'; } elsif ( $opt_f eq 'elff' ) { @fields = split ( /\s+/, $line ); $loop .= ' use Time::Local; if ( $line =~ m#^'; foreach (@fields) { $tmpline1 .= '\s+' if ($tmpline1); if ( $_ eq 'date' ) { $tmpline1 .= '(\d+)-(\d+)-(\d+)'; $tmpline2 .= ' $log_year = $' . ++$offset . '; $log_month = $' . ++$offset . '; $log_day = $' . ++$offset . ';'; } elsif ( $_ eq 'time' ) { $tmpline1 .= '(\d+):(\d+):(\d+)'; $tmpline2 .= ' $log_hour = $' . ++$offset . '; $log_min = $' . ++$offset . '; $log_sec = $' . ++$offset . ';'; } elsif ( $_ eq 'x-timestamp' ) { $tmpline1 .= '(\d+\.\d+)'; $tmpline2 .= ' $log_date = $' . ++$offset . ';'; $log_date = 0; } elsif ( $_ eq 'c-ip' ) { $tmpline1 .= '([\w\-\.:]+)'; $tmpline2 .= ' $log_requester = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-authname' or $_ eq 'x-remote-id' or $_ eq 'x-username' or $_ eq 'cs-username' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_ident = $' . ++$offset . ';'; } elsif ( $_ eq 's-ip' or $_ eq 's-sitename' or $_ eq 'sc-filter-result' or $_ eq 'sc-filter-category' or $_ eq 'x-virus-id' ) { $tmpline1 .= '[\w\-\.]+'; } elsif ( $_ eq 'cs-method' ) { $tmpline1 .= '([\w\-]+)'; $tmpline2 .= ' $log_method = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-uri' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_url = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-uri-scheme' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_cs_uri_scheme = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-host' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_cs_host = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-uri-path' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_cs_uri_path = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-uri-stem' or $_ eq 'cs-uri-query' or $_ eq 'x-note' ) { $tmpline1 .= '\S+'; } elsif ( $_ eq 'c-version' ) { $tmpline1 .= '\w+/[\d\.]+'; } elsif ( $_ eq 'sc-status' ) { $tmpline1 .= '(\d+)'; $tmpline2 .= ' $log_code = $' . ++$offset . ';'; } elsif ( $_ eq 'sc-bytes' or $_ eq 'bytes' ) { $tmpline1 .= '(\d+)'; $tmpline2 .= ' $log_size = $' . ++$offset . ';'; } elsif ( $_ eq 'cs-bytes' ) { $tmpline1 .= '\d+'; } elsif ( $_ eq 'x-elapsed-milliseconds' ) { $tmpline1 .= '(\d+)'; $tmpline2 .= ' $log_reqtime = $' . ++$offset . ';'; } elsif ( $_ eq 'time-taken' ) { $tmpline1 .= '([\d\.]+)'; $tmpline2 .= ' $log_reqtime = $' . ++$offset . ' * 1000;'; } elsif ( $_ eq 'cs(User-Agent)' or $_ eq 'cs(Cookie)' or $_ eq 'cs(Referer)' or $_ eq 'sc(Referer)' or $_ eq 'cs(X-Forwarded-For)' or $_ eq 'x-hiername') { $tmpline1 .= '(\"[^\"]*\"|-)'; $tmpline2 .= ' ++$offset;'; } elsif ( $_ eq 'cs(Content-Type)' ) { $tmpline1 .= '(\"[^\"]*\"|-)'; $tmpline2 .= ' $log_content = $' . ++$offset . ';'; } elsif ( $_ eq 'cached' ) { $tmpline1 .= '(\d+)'; $tmpline2 .= ' $log_cached = $' . ++$offset . ';'; } elsif ( $_ eq 'x-transaction' ) { $tmpline1 .= '(\w+\/[\d\-]+)'; $tmpline2 .= ' $log_status = $' . ++$offset . ';'; $log_status = 0; } elsif ( $_ eq 'x-fill-proxy-ip' ) { $tmpline1 .= '([\w\-\.]+)'; $tmpline2 .= ' $log_proxy_ip = $' . ++$offset . ';'; } elsif ( $_ eq 'x-origin-ip' ) { $tmpline1 .= '([\w\-\.]+)'; $tmpline2 .= ' $log_origin_ip = $' . ++$offset . ';'; } elsif ( $_ eq 'x-hiercode' ) { $tmpline1 .= '([\w\-\.\/]+)'; $tmpline2 .= ' $log_hier = $' . ++$offset . ';'; $log_hier = 0; } elsif ( $_ eq 's-hierarchy' ) { $tmpline1 .= '([\w\-\.\/]+)'; $tmpline2 .= ' $log_hierarchy = $' . ++$offset . ';'; } elsif ( $_ eq 's-action' ) { $tmpline1 .= '([\w\-\.\/]+)'; $tmpline2 .= ' $log_s_action = $' . ++$offset . ';'; } elsif ( $_ eq 's-supplier-name' ) { $tmpline1 .= '([\w\-\.\/]+)'; $tmpline2 .= ' $log_supplier_name = $' . ++$offset . ';'; } elsif ( $_ eq 'rs(Content-Type)' ) { $tmpline1 .= '\"[^\"]*\"'; } else { print STDERR "$0: I don't know this input format. Please check the input. If you\'re sure that the following is NOT corrupt and the error also occurs with the recent version of Calamaris (see the README for pointers and known bugs) then report it with the following line to . Thank You.\n\n$_\n\n"; exit(1); } } foreach $pattern ( qw(date time c-ip cs-method cs-uri sc-status sc-bytes time-taken cached x-fill-proxy-ip x-origin-ip) ) { unless ( grep $pattern, @fields ) { print STDERR "$0: Your input file format is missing at least the field \'$pattern\'. I can\'t parse it. Sorry. If you think that this field isn't important to you, please report this error to . Thank You.\n\n"; exit(1); } } foreach $pattern (qw(cs-authname)) { unless ( grep $pattern, @fields ) { if ( $pattern eq 'cs-authname' ) { $tmpline2 .= ' $log_ident = "-";'; } } } $loop .= $tmpline1 . '.?$# ) {' . $tmpline2; $loop .= ' $log_date = timegm( $log_sec, $log_min, $log_hour, $log_day, $log_month - 1, $log_year - 1900 );' unless defined $log_date; $loop .= ' if ($log_s_action) { $log_status = "$log_s_action/$log_code"; } else { $log_status = "$log_cached/$log_code"; }' unless defined $log_status; $loop .= ' if ( $log_hierarchy and $log_supplier_name ) { $log_hier = "$log_hierarchy/$log_supplier_name"; } elsif ( $log_origin_ip ne \'-\' ) { $log_hier = "DIRECT/$log_origin_ip"; } elsif ( $log_proxy_ip ne \'-\' ) { if ( $log_cached eq \'0\' ) { $log_hier = "PARENT_MISS/$log_proxy_ip"; } else { $log_hier = "PARENT_HIT/$log_proxy_ip"; } } else { $log_hier = "NONE/-"; }' unless defined $log_hier; $loop .= ' } else {'; while ( defined( $line = <> ) ) { last unless $line =~ /^\s*#/; } } elsif ( $opt_f eq 'nse' ) { $line =~ s#^format=##og; @fields = split ( /\s+/, $line ); $loop .= ' use Time::Local; if ( $line =~ m#^'; foreach (@fields) { $tmpline1 .= '\s+' if ($tmpline1); if ( $_ eq '[%SYSDATE%]' ) { $tmpline1 .= '\[(\d+)/(\w+)/(\d+):(\d+):(\d+):(\d+)\s+\S+\]'; $tmpline2 .= ' $log_day = $' . ++$offset . '; $log_month = $' . ++$offset . '; $log_year = $' . ++$offset . '; $log_hour = $' . ++$offset . '; $log_min = $' . ++$offset . '; $log_sec = $' . ++$offset . ';'; } elsif ( $_ eq '%Ses->client.ip%' ) { $tmpline1 .= '([\w\-\.:]+)'; $tmpline2 .= ' $log_requester = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->vars.pauth-user%' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_ident = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->vars.remote-status%' or $_ eq '%Req->vars.r2p-cl%' or $_ eq '%Req->vars.cli-status%' or $_ eq '%Req->vars.svr-status%' or $_ eq '%Req->vars.cch-status%' ) { $tmpline1 .= '[\w\-\.]+'; } elsif ( $_ eq '"%Req->reqpb.proxy-request%"' ) { $tmpline1 .= '\"(\w+)\s+([^\"]+)\s*\S*\"'; $tmpline2 .= ' $log_method = $' . ++$offset . '; $log_url = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->srvhdrs.clf-status%' ) { $tmpline1 .= '([\d\-]+)'; $tmpline2 .= ' $log_code = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->vars.p2c-cl%' ) { $tmpline1 .= '([\d\-]+)'; $tmpline2 .= ' $log_size = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->headers.content-length%' or $_ eq '%Req->vars.p2r-cl%' or $_ eq '%Req->vars.c2p-hl%' or $_ eq '%Req->vars.p2c-hl%' or $_ eq '%Req->vars.p2r-hl%' or $_ eq '%Req->vars.r2p-hl%' ) { $tmpline1 .= '[\d\-]+'; } elsif ( $_ eq '%Req->vars.xfer-time%' ) { $tmpline1 .= '([\d\.]+)'; $tmpline2 .= ' $log_reqtime = $' . ++$offset . ' * 1000;'; } elsif ( $_ eq '%route%' ) { $tmpline1 .= '(\d+)'; $tmpline2 .= ' $log_cached = $' . ++$offset . ';'; } elsif ( $_ eq '%Req->vars.actual-route%' ) { $tmpline1 .= '(\S+)'; $tmpline2 .= ' $log_hier = $' . ++$offset . '; if ( $log_hier =~ m#[\(\)]# ) { $log_hier =~ s#^(\w+)(\((\S+)\))?$#$1/$3#; $log_status = \'TCP_MISS/-\'; } elsif ( $log_hier =~ m#-# ) { $log_hier = $log_hier . \'/-\'; $log_status = \'TCP_HIT/-\'; } else { $log_hier = $log_hier . \'/-\'; $log_status = \'TCP_MISS/-\'; }'; } elsif ( $_ eq '-' ) { $tmpline1 .= '-'; } else { print STDERR "$0: I don't know this input format. Please check the input. If you\'re sure that the following is NOT corrupt and the error also occurs with the recent version of Calamaris (see the README for pointers and known bugs) then report it with the following line to . Thank You.\n\n$_\n\n"; exit(1); } } foreach $pattern ( qw(%Ses->client.ip% [%SYSDATE%] %Req->reqpb.proxy-request% %Req->srvhdrs.clf-status% %Req->vars.p2c-cl% %Req->vars.xfer-time%) ) { unless ( grep $pattern, @fields ) { print STDERR "$0: Your input file format is missing at least the field \'$pattern\'. I can\'t parse it. Sorry. If you think that this field isn't important to you, please report this error to . Thank You.\n\n"; exit(1); } } foreach $pattern (qw(%Req->vars.pauth-user% %Req->vars.actual-route%)) { unless ( grep /$pattern/, @fields ) { if ( $pattern eq '%Req->vars.pauth-user%' ) { $tmpline2 .= ' $log_ident = "-";'; } elsif ( $pattern eq '%Req->vars.actual-route%' ) { $tmpline2 .= ' $log_hier = \'-/-\'; $log_status = \'-/-\';'; } } } $loop .= $tmpline1 . '.?$# ) {' . $tmpline2 . ' $monthcount = -1; foreach $month (@months) { $monthcount++; last if ( $month eq $log_month ); } $log_date = timegm( $log_sec, $log_min, $log_hour, $log_day, $monthcount, $log_year - 1900 ); } else {'; while ( defined( $line = <> ) ) { last unless $line =~ /^\s*#/; } } else { print STDERR "$0: unknown value at -f -option: \"$opt_f\"\n\n$USAGE\n\n"; exit 1; } $loop .= ' chomp($line);'; $loop .= ' warn(\'invalid line: "\' . $line . "\"\n");' if $opt_v; $loop .= ' $invalid++; next; }'; $loop .= ' if (($log_date < $interval_begin) or ($log_date > $interval_end)) { $skipped++; next; } ' if $opt_I; $loop .= ' if($filter_ip{$log_requester}) { $skipped++; next; } ' if $opt_ipfilter_exclude; $loop .= ' if(! $filter_ip{$log_requester}) { $skipped++; next; } ' if $opt_ipfilter_include; $loop .= ' $log_reqtime = .1 if $log_reqtime == 0; ( $log_hitfail, $log_code ) = split \'/\', $log_status; $log_size = 0 if ( $log_size eq \'-\' ); $log_url = "$log_cs_uri_scheme://$log_cs_host/$log_cs_uri_path" unless ($log_url); $log_url =~ s/\?.*$/?/; @url = split m#[/\\\]#o, $log_url; ( $urlprot, $urlhost, $urlext ) = (@url)[ 0, 2, $#url ]; $urlext = \'.\' if $#url <= 2; if ( $#url <= -1 ) { $urlext = \'.\'; $urlprot = $urlhost = \'\'; } $urlext = \'.\' if ( $urlext =~ m#[\?;&\$,!@=|%]#o or $log_method eq \'POST\' ); unless ( defined $urlhost ) { $urlhost = $urlprot;'; $loop .= ' $log_content = ' unless $opt_f eq 'squid-old' or $opt_f eq 'elff' or $opt_f eq 'nse'; $loop .= ' $urlprot = \'\'; $urlext = \'.\'; } $urlhost =~ s#^.*@##o; $urlhost =~ s#[:\?].*$##o; $urlhost =~ tr/A-Z/a-z/; @urlext = split \'\.\', $urlext; $urlext = (@urlext)[$#urlext]; $urlext = \'\' if $#urlext <= 0;'; $loop .= ' $urlext =~ tr/A-Z/a-z/;' if $opt_c; $loop .= ' if ( $urlhost =~ m#^(([0-9][0-9]{0,2}\.){3})[0-9][0-9]{0,2}$#o ) {'; $loop .= ' $urlhost = $1 . \'*\';' unless $opt_N == -1; $loop .= ' $urltld = \'\'; } elsif ( $urlhost =~ m#^(.*\.([^\.]+\.)?)?([^\.]+\.([^\.]+))\.?$#o ) { @list = split \'\.\', $urlhost; $urltld = pop @list;'; if ( $opt_N != -1 ) { $loop .= ' $urlhost = $urltld;'; for ( $i = $opt_N; $i != 1; $i-- ) { $loop .= ' $urlhost = pop (@list) . \'.\' . $urlhost if $#list >= 0;'; } $loop .= ' $urlhost = pop (@list) . \'.\' . $urlhost if ( $urltld =~ m#^(a[rtu]|br|c[no]|hk|i[dlm]|jp|kr|l[by]|m[oxy]|nz|p[elnry]|sg|t[hrw]|u[aks]|ve|yu|za)$#o and $#list >= 0 ); $urlhost = \'*.\' . $urlhost if $#list >= 0; $urltld = \'*.\' . $urltld;'; } $loop .= ' } elsif ( $urlhost =~ m#([!a-z0-9\.\-]|\.\.)#o ) { $urlhost = $urltld = $urlext = $urlprot = \'\'; } else { $urltld = $urlhost; }'; if ($opt_n) { $loop .= ' $requester = $log_requester;'; } else { $loop .= ' $requester = getfqdn($log_requester);'; } $loop .= ' $requester = $log_ident . \'@\' . $requester if $log_ident ne \'-\';' if $opt_u; $loop .= ' ( $log_hier_method, $log_hier_host ) = ( split \'/\', $log_hier )[ 0, 1 ];'; $loop .= ' $log_content = \'\' if $log_content eq \'-\'; $log_content =~ tr/A-Z/a-z/; $log_content =~ s#\s+.*##; $log_content = ' unless $opt_f eq 'squid-old' or $opt_f eq 'elff' or $opt_f eq 'nse'; $loop .= ' $urlhost = $urltld = $urlext = $urlprot = \'\' if ( $log_code =~ m#^[45]#o );'; $loop .= " print STDERR '#' if (0 == (\$counter % $opt_b));" if $opt_b; $loop .= ' $counter++; $size += $log_size; $time += $log_reqtime; $method{$log_method} = $method_size{$log_method} = $method_time{$log_method} = 0 unless defined $method{$log_method}; $method{$log_method}++; $method_size{$log_method} += $log_size; $method_time{$log_method} += $log_reqtime; $time_begin = $log_date if $log_date < $time_begin; $time_end = $log_date if $log_date > $time_end;'; if ( defined $opt_p ) { $loop .= ' if (@peak_all) { if ( $log_date < $peak_all[$#peak_all] ) { $peak_warn = \'Peak values are most likely wrong due to unsorted input!\'; undef(@peak_all); undef(@peak_udp); undef(@peak_tcp); $peak_all_min_pointer = $peak_all_sec_pointer = $peak_tcp_min_pointer = $peak_tcp_sec_pointer = $peak_udp_min_pointer = $peak_udp_sec_pointer = 0; chomp($line); warn( \'unsorted input: "\' . $line . "\"\n" ) if $opt_v; } }'; if ( $opt_p eq 'old' ) { $loop .= ' $peak_all_sec_pointer++; $peak_all_min_pointer++; unshift ( @peak_all, $log_date ); $peak_all_sec_pointer-- while $peak_all[ $peak_all_sec_pointer - 1 ] < ( $log_date - 1 ); $peak_all_min_pointer-- while $peak_all[ $peak_all_min_pointer - 1 ] < ( $log_date - 60 ); pop (@peak_all) while $peak_all[$#peak_all] < ( $log_date - 3600 ); if ( $peak_all_hour < @peak_all ) { $peak_all_hour = @peak_all; $peak_all_hour_time = $log_date - 3600; } if ( $peak_all_min < $peak_all_min_pointer ) { $peak_all_min = $peak_all_min_pointer; $peak_all_min_time = $log_date - 60; } if ( $peak_all_sec < $peak_all_sec_pointer ) { $peak_all_sec = $peak_all_sec_pointer; $peak_all_sec_time = $log_date - 1; }'; } elsif ( $opt_p eq 'new' ) { $loop .= ' $date_hour = int( ( $log_date - ( $log_reqtime / 1000 ) ) / 3600 ) * 3600; foreach $i ( ( $date_hour / 3600 ) .. int( $log_date / 3600 ) ) { $peak_all_hour{ $i * 3600 } = $peak_all_hour_size{ $i * 3600 } = 0 unless defined $peak_all_hour{ $i * 3600 }; $peak_all_hour{ $i * 3600 }++; $peak_all_hour_size{ $i * 3600 } += $log_size / int( $log_reqtime / 3600000 + 1 ); } $peak_all_sec_pointer++; unshift ( @peak_all, $log_date ); $peak_all_sec_pointer-- while $peak_all[ $peak_all_sec_pointer - 1 ] < ( $log_date - 1 ); pop (@peak_all) while $peak_all[$#peak_all] < ( $log_date - 60 ); if ( $peak_all_min < @peak_all ) { $peak_all_min = @peak_all; $peak_all_min_time = $log_date - 60; } if ( $peak_all_sec < $peak_all_sec_pointer ) { $peak_all_sec = $peak_all_sec_pointer; $peak_all_sec_time = $log_date - 1; }'; } else { print STDERR "$0: unknown value at -p -option: \"$opt_p\"\n\n$USAGE\n\n"; exit 1; } } $loop .= ' if ( ( $log_method =~ m#^ICP_#o ) or ( $log_status =~ m#^ICP#o ) ) { $udp++; $udp_size += $log_size; $udp_time += $log_reqtime;'; $loop .= ' $udp_reqtime{$log_reqtime} = $udp_hit_reqtime{$log_reqtime} = $udp_reqtime_size{$log_reqtime} = $udp_hit_reqtime_size{$log_reqtime} = 0 unless defined $udp_reqtime{$log_reqtime}; $udp_reqtime{$log_reqtime}++; $udp_reqtime_size{$log_reqtime} += $log_size;' if $opt_response_time; $loop .= ' $udp_code{$log_code} = $udp_code_time{$log_code} = $udp_code_size{$log_code} = $udp_hit_code{$log_code} = $udp_hit_code_size{$log_code} = 0 unless defined $udp_code{$log_code}; $udp_code{$log_code}++; $udp_code_time{$log_code} += $log_reqtime; $udp_code_size{$log_code} += $log_size;' if $opt_errorcode_distribution; $loop .= ' $udp_requester{$requester} = $udp_requester_size{$requester} = $udp_requester_time{$requester} = $udp_hit_requester{$requester} = $udp_hit_requester_size{$requester} = 0 unless defined $udp_requester{$requester}; $udp_requester{$requester}++; $udp_requester_size{$requester} += $log_size; $udp_requester_time{$requester} += $log_reqtime;' if ($opt_r); $loop .= ' $udp_requester_urlhost{$requester}{$urlhost} = $udp_requester_urlhost_size{$requester}{$urlhost} = $udp_requester_urlhost_time{$requester}{$urlhost} = $udp_hit_requester_urlhost{$requester}{$urlhost} = $udp_hit_requester_urlhost_size{$requester}{$urlhost} = 0 unless defined $udp_requester_urlhost{$requester}{$urlhost}; $udp_requester_urlhost{$requester}{$urlhost}++; $udp_requester_urlhost_size{$requester}{$urlhost} += $log_size; $udp_requester_urlhost_time{$requester}{$urlhost} += $log_reqtime;' if ($opt_R); if ( not defined $opt_p ) { } elsif ( $opt_p eq 'old' ) { $loop .= ' $peak_udp_sec_pointer++; $peak_udp_min_pointer++; unshift ( @peak_udp, $log_date ); $peak_udp_sec_pointer-- while $peak_udp[ $peak_udp_sec_pointer - 1 ] < ( $log_date - 1 ); $peak_udp_min_pointer-- while $peak_udp[ $peak_udp_min_pointer - 1 ] < ( $log_date - 60 ); pop @peak_udp while $peak_udp[$#peak_udp] < ( $log_date - 3600 ); if ( $peak_udp_hour < @peak_udp ) { $peak_udp_hour = @peak_udp; $peak_udp_hour_time = $log_date - 3600; } if ( $peak_udp_min < $peak_udp_min_pointer ) { $peak_udp_min = $peak_udp_min_pointer; $peak_udp_min_time = $log_date - 60; } if ( $peak_udp_sec < $peak_udp_sec_pointer ) { $peak_udp_sec = $peak_udp_sec_pointer; $peak_udp_sec_time = $log_date - 1; }'; } elsif ( $opt_p eq 'new' ) { $loop .= ' foreach $i ( ( $date_hour / 3600 ) .. int( $log_date / 3600 ) ) { $peak_udp_hour{ $i * 3600 } = $peak_udp_hour_size{ $i * 3600 } = 0 unless defined $peak_udp_hour{ $i * 3600 }; $peak_udp_hour{ $i * 3600 }++; $peak_udp_hour_size{ $i * 3600 } += $log_size / int( $log_reqtime / 3600000 + 1 ); } $peak_udp_sec_pointer++; unshift ( @peak_udp, $log_date ); $peak_udp_sec_pointer-- while $peak_udp[ $peak_udp_sec_pointer - 1 ] < ( $log_date - 1 ); pop @peak_udp while $peak_udp[$#peak_udp] < ( $log_date - 60 ); if ( $peak_udp_min < @peak_udp ) { $peak_udp_min = @peak_udp; $peak_udp_min_time = $log_date - 60; } if ( $peak_udp_sec < $peak_udp_sec_pointer ) { $peak_udp_sec = $peak_udp_sec_pointer; $peak_udp_sec_time = $log_date - 1; }'; } $loop .= ' if ( $log_hitfail =~ m#^(UDP|ICP)_HIT#o ) { $udp_hit++; $udp_hit_size += $log_size; $udp_hit_time += $log_reqtime;'; $loop .= ' $udp_hit_reqtime{$log_reqtime}++; $udp_hit_reqtime_size{$log_reqtime} += $log_size;' if $opt_response_time; $loop .= ' $udp_hit_code{$log_code}++; $udp_hit_code_size{$log_code} += $log_size;' if $opt_errorcode_distribution; $loop .= ' $udp_hit_requester{$requester}++; $udp_hit_requester_size{$requester} += $log_size;' if $opt_r; $loop .= ' $udp_hit_requester_urlhost{$requester}{$urlhost}++; $udp_hit_requester_urlhost_size{$requester}{$urlhost} += $log_size;' if ($opt_R); $loop .= ' $udp_hit{$log_hitfail} = $udp_hit_size{$log_hitfail} = $udp_hit_time{$log_hitfail} = 0 unless defined $udp_hit{$log_hitfail}; $udp_hit{$log_hitfail}++; $udp_hit_size{$log_hitfail} += $log_size; $udp_hit_time{$log_hitfail} += $log_reqtime;' if ($opt_s); $loop .= ' } else { $udp_miss++; $udp_miss_size += $log_size; $udp_miss_time += $log_reqtime;'; $loop .= ' $udp_miss{$log_hitfail} = $udp_miss_size{$log_hitfail} = $udp_miss_time{$log_hitfail} = 0 unless defined $udp_miss{$log_hitfail}; $udp_miss{$log_hitfail}++; $udp_miss_size{$log_hitfail} += $log_size; $udp_miss_time{$log_hitfail} += $log_reqtime;' if ($opt_s); $loop .= ' } } else { $tcp++; $tcp_size += $log_size; $tcp_time += $log_reqtime;'; $loop .= ' $tcp_reqtime{$log_reqtime} = $tcp_hit_reqtime{$log_reqtime} = $tcp_reqtime_size{$log_reqtime} = $tcp_hit_reqtime_size{$log_reqtime} = 0 unless defined $tcp_reqtime{$log_reqtime}; $tcp_reqtime{$log_reqtime}++; $tcp_reqtime_size{$log_reqtime} += $log_size;' if $opt_response_time; $loop .= ' $tcp_code{$log_code} = $tcp_code_time{$log_code} = $tcp_code_size{$log_code} = $tcp_hit_code_size{$log_code} = $tcp_hit_code{$log_code} = 0 unless defined $tcp_code{$log_code}; $tcp_code{$log_code}++; $tcp_code_time{$log_code} += $log_reqtime; $tcp_code_size{$log_code} += $log_size;' if $opt_errorcode_distribution; $loop .= ' $perf_date = ( int( ( $log_date + ' . "( $opt_T * 60 ) ) / ( 60 * $opt_P ) ) * 60 * $opt_P ) - ( $opt_T * 60 );" . ' unless ( defined $perf_counter{$perf_date} ) { $perf_counter{$perf_date} = $perf_size{$perf_date} = $perf_tcp_hit_size{$perf_date} = $perf_tcp_miss_size{$perf_date} = $perf_hier_direct_size{$perf_date} = $perf_tcp_hit{$perf_date} = $perf_hier_sibling_size{$perf_date} = $perf_hier_parent_size{$perf_date} = 0; $perf_time{$perf_date} = $perf_tcp_hit_time{$perf_date} = $perf_tcp_miss_time{$perf_date} = $perf_hier_direct_time{$perf_date} = $perf_hier_sibling_time{$perf_date} = $perf_hier_parent_time{$perf_date} = .0000000001; } $perf_counter{$perf_date}++; $perf_ip{$perf_date}{$log_requester} = 1; $perf_size{$perf_date} += $log_size; $perf_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $tcp_requester{$requester} = $tcp_requester_size{$requester} = $tcp_requester_time{$requester} = $tcp_hit_requester{$requester} = $tcp_hit_requester_size{$requester} = 0 unless defined $tcp_requester{$requester}; $tcp_requester{$requester}++; $tcp_requester_size{$requester} += $log_size; $tcp_requester_time{$requester} += $log_reqtime;' if ($opt_r); $loop .= ' $distribution = $log_size ? int( log($log_size) / log($opt_D) ) : -1; $tcp_distribution{$distribution} = $tcp_distribution_size{$distribution} = $tcp_distribution_time{$distribution} = $tcp_hit_distribution{$distribution} = $tcp_hit_distribution_size{$distribution} = 0 unless defined $tcp_distribution{$distribution}; $tcp_distribution{$distribution}++; $tcp_distribution_size{$distribution} += $log_size; $tcp_distribution_time{$distribution} += $log_reqtime;' if ($opt_D); $loop .= ' $tcp_requester_urlhost{$requester}{$urlhost} = $tcp_requester_urlhost_size{$requester}{$urlhost} = $tcp_requester_urlhost_time{$requester}{$urlhost} = $tcp_hit_requester_urlhost{$requester}{$urlhost} = $tcp_hit_requester_urlhost_size{$requester}{$urlhost} = 0 unless defined $tcp_requester_urlhost{$requester}{$urlhost}; $tcp_requester_urlhost{$requester}{$urlhost}++; $tcp_requester_urlhost_size{$requester}{$urlhost} += $log_size; $tcp_requester_urlhost_time{$requester}{$urlhost} += $log_reqtime;' if ($opt_R); $loop .= ' $tcp_urlhost{$urlhost} = $tcp_urlhost_size{$urlhost} = $tcp_urlhost_time{$urlhost} = $tcp_hit_urlhost{$urlhost} = $tcp_hit_urlhost_size{$urlhost} = 0 unless defined $tcp_urlhost{$urlhost}; $tcp_urlhost{$urlhost}++; $tcp_urlhost_size{$urlhost} += $log_size; $tcp_urlhost_time{$urlhost} += $log_reqtime; $tcp_urltld{$urltld} = $tcp_urltld_size{$urltld} = $tcp_urltld_time{$urltld} = $tcp_hit_urltld{$urltld} = $tcp_hit_urltld_size{$urltld} = 0 unless defined $tcp_urltld{$urltld}; $tcp_urltld{$urltld}++; $tcp_urltld_time{$urltld} += $log_reqtime; $tcp_urltld_size{$urltld} += $log_size;' if ($opt_d); $loop .= ' $tcp_urlprot{$urlprot} = $tcp_urlprot_size{$urlprot} = $tcp_hit_urlprot{$urlprot} = $tcp_hit_urlprot_size{$urlprot} = 0 unless defined $tcp_urlprot{$urlprot}; $tcp_urlprot{$urlprot}++; $tcp_urlprot_time{$urlprot} += $log_reqtime; $tcp_urlprot_size{$urlprot} += $log_size;' if ($opt_t); if ( not defined $opt_p ) { } elsif ( $opt_p eq 'old' ) { $loop .= ' $peak_tcp_sec_pointer++; $peak_tcp_min_pointer++; unshift ( @peak_tcp, $log_date ); $peak_tcp_sec_pointer-- while $peak_tcp[ $peak_tcp_sec_pointer - 1 ] < ( $log_date - 1 ); $peak_tcp_min_pointer-- while $peak_tcp[ $peak_tcp_min_pointer - 1 ] < ( $log_date - 60 ); pop (@peak_tcp) while $peak_tcp[$#peak_tcp] < ( $log_date - 3600 ); if ( $peak_tcp_hour < @peak_tcp ) { $peak_tcp_hour = @peak_tcp; $peak_tcp_hour_time = $log_date - 3600; } if ( $peak_tcp_min < $peak_tcp_min_pointer ) { $peak_tcp_min = $peak_tcp_min_pointer; $peak_tcp_min_time = $log_date - 60; } if ( $peak_tcp_sec < $peak_tcp_sec_pointer ) { $peak_tcp_sec = $peak_tcp_sec_pointer; $peak_tcp_sec_time = $log_date - 1; }'; } elsif ( $opt_p eq 'new' ) { $loop .= ' foreach $i ( $date_hour / 3600 .. int( $log_date / 3600 ) ) { $peak_tcp_hour{ $i * 3600 } = $peak_tcp_hour_size{ $i * 3600 } = 0 unless defined $peak_tcp_hour{ $i * 3600 }; $peak_tcp_hour{ $i * 3600 }++; $peak_tcp_hour_size{ $i * 3600 } += $log_size / int( $log_reqtime / 3600000 + 1 ); } $peak_tcp_sec_pointer++; unshift ( @peak_tcp, $log_date ); $peak_tcp_sec_pointer-- while $peak_tcp[ $peak_tcp_sec_pointer - 1 ] < ( $log_date - 1 ); pop (@peak_tcp) while $peak_tcp[$#peak_tcp] < ( $log_date - 60 ); if ( $peak_tcp_min < @peak_tcp ) { $peak_tcp_min = @peak_tcp; $peak_tcp_min_time = $log_date - 60; } if ( $peak_tcp_sec < $peak_tcp_sec_pointer ) { $peak_tcp_sec = $peak_tcp_sec_pointer; $peak_tcp_sec_time = $log_date - 1; }'; } $loop .= ' $tcp_content{$log_content} = $tcp_content_size{$log_content} = $tcp_content_time{$log_content} = $tcp_hit_content{$log_content} = $tcp_hit_content_size{$log_content} = 0 unless defined $tcp_content{$log_content}; $tcp_content{$log_content}++; $tcp_content_time{$log_content} += $log_reqtime; $tcp_content_size{$log_content} += $log_size;' unless $opt_f eq 'squid-old' or $opt_f eq 'elff' or $opt_f eq 'nse'; $loop .= ' $tcp_urlext{$urlext} = $tcp_urlext_size{$urlext} = $tcp_urlext_time{$urlext} = $tcp_hit_urlext{$urlext} = $tcp_hit_urlext_size{$urlext} = $tcp_urlext_fresh{$urlext} = $tcp_urlext_stale{$urlext} = $tcp_urlext_refresh{$urlext} = $tcp_urlext_mod{$urlext} = $tcp_urlext_unmod{$urlext} = 0 unless defined $tcp_urlext{$urlext}; $tcp_urlext{$urlext}++; $tcp_urlext_time{$urlext} += $log_reqtime; $tcp_urlext_size{$urlext} += $log_size;' if ($opt_t); $loop .= ' $tcp_urlext_fresh{$urlext}++ if grep { /^$log_hitfail$/ } @{$fresh_tags{$opt_f}}; $tcp_urlext_stale{$urlext}++ if grep { /^$log_hitfail$/ } @{$stale_tags{$opt_f}}; $tcp_urlext_refresh{$urlext}++ if grep { /^$log_hitfail$/ } @{$refresh_tags{$opt_f}}; $tcp_urlext_mod{$urlext}++ if grep { /^$log_hitfail$/ } @{$mod_tags{$opt_f}}; $tcp_urlext_unmod{$urlext}++ if grep { /^$log_hitfail$/ } @{$unmod_tags{$opt_f}};' if ($object_freshness_report and $opt_t); if ( $opt_f eq 'elff' ) { $loop .= ' if ( $log_hitfail eq \'1\' or $log_hitfail =~ m#^(TCP_HIT|HIT_)#o ) {'; } else { $loop .= ' if ( $log_hitfail =~ m#^TCP_(\w*HIT|REDIRECT|REFRESH_UNMODIFIED)#o ) {'; } $loop .= ' $tcp_hit++; $tcp_hit_size += $log_size; $tcp_hit_time += $log_reqtime;'; $loop .= ' $tcp_hit_reqtime{$log_reqtime}++; $tcp_hit_reqtime_size{$log_reqtime} += $log_size;' if $opt_response_time; $loop .= ' $tcp_hit_code{$log_code}++; $tcp_hit_code_size{$log_code} += $log_size;' if $opt_errorcode_distribution; $loop .= ' $perf_tcp_hit{$perf_date}++; $perf_tcp_hit_size{$perf_date} += $log_size; $perf_tcp_hit_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $tcp_hit{$log_hitfail} = $tcp_hit_size{$log_hitfail} = $tcp_hit_time{$log_hitfail} = 0 unless defined $tcp_hit{$log_hitfail}; $tcp_hit{$log_hitfail}++; $tcp_hit_size{$log_hitfail} += $log_size; $tcp_hit_time{$log_hitfail} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' $tcp_hit_requester{$requester}++; $tcp_hit_requester_size{$requester} += $log_size;' if ($opt_r); $loop .= ' $tcp_hit_requester_urlhost{$requester}{$urlhost}++; $tcp_hit_requester_urlhost_size{$requester}{$urlhost} += $log_size;' if ($opt_R); $loop .= ' $tcp_hit_distribution{$distribution}++; $tcp_hit_distribution_size{$distribution} += $log_size;' if ($opt_D); $loop .= ' $tcp_hit_urlhost{$urlhost}++; $tcp_hit_urlhost_size{$urlhost} += $log_size; $tcp_hit_urltld{$urltld}++; $tcp_hit_urltld_size{$urltld} += $log_size;' if ($opt_d); $loop .= ' $tcp_hit_content{$log_content}++; $tcp_hit_content_time{$log_content} += $log_reqtime; $tcp_hit_content_size{$log_content} += $log_size;' unless $opt_f eq 'squid-old' or $opt_f eq 'elff' or $opt_f eq 'nse'; $loop .= ' $tcp_hit_urlext{$urlext}++; $tcp_hit_urlext_size{$urlext} += $log_size; $tcp_hit_urlprot{$urlprot}++; $tcp_hit_urlprot_size{$urlprot} += $log_size;' if ($opt_t); $loop .= ' } elsif ( $log_hier_method =~ m#EMPTY|NONE|NULL|UNKNOWN|^\-$#o or $log_hitfail =~ m#^ERR_#o ) { $tcp_miss_none++; $tcp_miss_none_size += $log_size; $tcp_miss_none_time += $log_reqtime;' if $opt_f ne 'elff'; $loop .= ' $tcp_miss_none{$log_hitfail} = $tcp_miss_none_size{$log_hitfail} = $tcp_miss_none_time{$log_hitfail} = 0 unless defined $tcp_miss_none{$log_hitfail}; $tcp_miss_none{$log_hitfail}++; $tcp_miss_none_size{$log_hitfail} += $log_size; $tcp_miss_none_time{$log_hitfail} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' } else { $tcp_miss++; $tcp_miss_size += $log_size; $tcp_miss_time += $log_reqtime;'; $loop .= ' $perf_tcp_miss_size{$perf_date} += $log_size; $perf_tcp_miss_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $tcp_miss{$log_hitfail} = $tcp_miss_size{$log_hitfail} = $tcp_miss_time{$log_hitfail} = 0 unless defined $tcp_miss{$log_hitfail}; $tcp_miss{$log_hitfail}++; $tcp_miss_size{$log_hitfail} += $log_size; $tcp_miss_time{$log_hitfail} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' $tcp_miss_requester{$requester} = $tcp_miss_requester_size{$requester} = 0 unless defined $tcp_miss_requester{$requester}; $tcp_miss_requester{$requester}++; $tcp_miss_requester_size{$requester} += $log_size;' if ($opt_r); $loop .= ' } if ( $log_hier_method !~ m#EMPTY|NONE|NULL|UNKNOWN|^\-$#o ) { $hier++; $hier_size += $log_size; $hier_time += $log_reqtime; if ( $log_hier_method =~ m#DIRECT|ORIGINAL_DST|PINNED|SOURCE_FASTEST#o ) { $hier_direct++; $hier_direct_size += $log_size; $hier_direct_time += $log_reqtime;'; $loop .= ' $perf_hier_direct_size{$perf_date} += $log_size; $perf_hier_direct_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $hier_direct{$log_hier_method} = $hier_direct_size{$log_hier_method} = $hier_direct_time{$log_hier_method} = 0 unless defined $hier_direct{$log_hier_method}; $hier_direct{$log_hier_method}++; $hier_direct_size{$log_hier_method} += $log_size; $hier_direct_time{$log_hier_method} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' } elsif ( $log_hier_method =~ m#(CACHE_DIGEST|NEIGHBOR|PARENT|SIBLING)_\w*HIT|SIBLING#o ) { $hier_sibling++; $hier_sibling_size += $log_size; $hier_sibling_time += $log_reqtime;'; $loop .= ' $perf_hier_sibling_size{$perf_date} += $log_size; $perf_hier_sibling_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $hier_sibling{$log_hier_method} = $hier_sibling_size{$log_hier_method} = $hier_sibling_time{$log_hier_method} = 0 unless defined $hier_sibling{$log_hier_method}; $hier_sibling{$log_hier_method}++; $hier_sibling_size{$log_hier_method} += $log_size; $hier_sibling_time{$log_hier_method} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' $hier_neighbor{$log_hier_host} = $hier_neighbor_size{$log_hier_host} = $hier_neighbor_time{$log_hier_host} = 0 unless defined $hier_neighbor{$log_hier_host}; $hier_neighbor{$log_hier_host}++; $hier_neighbor_size{$log_hier_host} += $log_size; $hier_neighbor_time{$log_hier_host} += $log_reqtime;'; $loop .= ' $hier_neighbor_status{$log_hier_host}{$log_hier_method} = $hier_neighbor_status_size{$log_hier_host}{$log_hier_method} = $hier_neighbor_status_time{$log_hier_host}{$log_hier_method} = 0 unless defined $hier_neighbor_status{$log_hier_host}{$log_hier_method}; $hier_neighbor_status{$log_hier_host}{$log_hier_method}++; $hier_neighbor_status_size{$log_hier_host}{$log_hier_method} += $log_size; $hier_neighbor_status_time{$log_hier_host}{$log_hier_method} += $log_reqtime;' if ($opt_s); $loop .= ' } elsif ( $log_hier_method =~ m#(ANY|CLOSEST|DEFAULT|FIRST_UP|PASSTHROUGH|ROUNDROBIN|SINGLE)_PARENT|CARP|PARENT_MISS|PARENT|PROXY|STANDBY_POOL#o ) { $hier_parent++; $hier_parent_size += $log_size; $hier_parent_time += $log_reqtime;'; $loop .= ' $perf_hier_parent_size{$perf_date} += $log_size; $perf_hier_parent_time{$perf_date} += $log_reqtime;' if ($opt_P); $loop .= ' $hier_parent{$log_hier_method} = $hier_parent_size{$log_hier_method} = $hier_parent_time{$log_hier_method} = 0 unless defined $hier_parent{$log_hier_method}; $hier_parent{$log_hier_method}++; $hier_parent_size{$log_hier_method} += $log_size; $hier_parent_time{$log_hier_method} += $log_reqtime;' if ($opt_s) and $opt_f ne 'elff'; $loop .= ' $hier_neighbor{$log_hier_host} = $hier_neighbor_size{$log_hier_host} = $hier_neighbor_time{$log_hier_host} = 0 unless defined $hier_neighbor{$log_hier_host}; $hier_neighbor{$log_hier_host}++; $hier_neighbor_size{$log_hier_host} += $log_size; $hier_neighbor_time{$log_hier_host} += $log_reqtime;'; $loop .= ' $hier_neighbor_status{$log_hier_host}{$log_hier_method} = $hier_neighbor_status_size{$log_hier_host}{$log_hier_method} = $hier_neighbor_status_time{$log_hier_host}{$log_hier_method} = 0 unless defined $hier_neighbor_status{$log_hier_host}{$log_hier_method}; $hier_neighbor_status{$log_hier_host}{$log_hier_method}++; $hier_neighbor_status_size{$log_hier_host}{$log_hier_method} += $log_size; $hier_neighbor_status_time{$log_hier_host}{$log_hier_method} += $log_reqtime;' if ($opt_s); $loop .= ' } else { chomp($log_hier_method); unless ( defined $errormsg ) { print STDERR " Please check the following error(s). If you\'re sure that the offending line(s) are NOT corrupt and the error also occurs with the recent version of Calamaris (see the README for pointers and known bugs) then report them. Don\'t send me thousands of similar errors. use . Thank You. " unless $errormsg; $errormsg = 1; } warn( " unknown log_hier_method: \"$log_hier_method\" found in line $counter of input: $line" ); } } } }'; $time_run = time - $time_run; print STDERR "$loop\n" if $opt_L; eval $loop; die $@ if $@; $time_run = time - $time_run; } ### Yea! File read. Now for something completely different ;-) if ( $counter == 0 ) { print "\nno requests found\n"; exit(0); } $loginterval = convertdate($time_begin) . ' - ' . convertdate($time_end); $timestamp = convertdate($time_begin,1) . '-' . convertdate($time_end,1); if ($path) { $path =~ s#%t#$timestamp#g if $timestamp; $path =~ s#%h#$host_name#g if $host_name; $path =~ s#%%#%#g; } if ($filename) { $filename =~ s#%t#$timestamp#g if $timestamp; $filename =~ s#%h#$host_name#g if $host_name; $filename =~ s#%%#%#g; } if ($file_prefix) { $file_prefix =~ s#%t#$timestamp#g if $timestamp; $file_prefix =~ s#%h#$host_name#g if $host_name; $file_prefix =~ s#%%#%#g; } open( CACHE, ">$opt_o" ) or die ("$0: can't open $opt_o for writing: $!\n") if ($opt_o); # Summary $report_index = 0; @format = ( 53, 14, 10 ); writecache( $report_index, $time_begin, $time_end, $counter, $size, $time, $invalid, $time_run, $udp, $udp_size, $udp_time, $udp_hit, $udp_hit_size, $udp_hit_time, $udp_miss, $udp_miss_size, $udp_miss_time, $tcp, $tcp_size, $tcp_time, $tcp_hit, $tcp_hit_size, $tcp_hit_time, $tcp_miss, $tcp_miss_size, $tcp_miss_time, $tcp_miss_none, $tcp_miss_none_size, $tcp_miss_none_time, $hier, $hier_size, $hier_time, $hier_direct, $hier_direct_size, $hier_direct_time, $hier_sibling, $hier_sibling_size, $hier_sibling_time, $hier_parent, $hier_parent_size, $hier_parent_time ); outstart($report_index); outheader( $report_index, 'Calamaris statistics', '', '' ); outseperator($report_index); outline( $report_index, '', 'lines parsed:', 'lines', $counter ); outline( $report_index, '', 'invalid lines:', 'lines', $invalid ); outline( $report_index, '', 'skipped lines:', 'lines', $skipped ) if ($opt_I or $opt_ipfilter_exclude or $opt_ipfilter_include); outline( $report_index, '', 'parse time:', 'sec', $time_run ); outline( $report_index, '', 'parse speed:', 'lines/sec', $time_run ? ( $counter + $invalid + $skipped ) / $time_run : ( $counter + $invalid + $skipped ) ); outseperator($report_index); outheader( $report_index, 'Proxy statistics', '', '' ); outseperator($report_index); outline( $report_index, '', 'Total amount:', 'requests', $tcp + $udp); outline( $report_index, '', 'unique hosts/users:', 'hosts', scalar keys %tcp_requester ) if $opt_r; outline( $report_index, '', 'Total Bandwidth:', 'Byte', kilomegagigatera( $tcp_size + $udp_size, $format[2] ) ); @format = ( 53, 14, '10%' ); $peak_all_hour_size_time = ( sort { $peak_all_hour_size{$b} <=> $peak_all_hour_size{$a} } keys(%peak_all_hour_size) )[0] or $peak_all_hour_size_time = $peak_all_hour_size{0} = 0; outline( $report_index, '', 'Max. Bandwidth usage:', 'MBit/sec', $peak_all_hour_size{$peak_all_hour_size_time} * 8 / ( 1024**2 * 3600 ) ) if $opt_p; outline( $report_index, '', 'Proxy efficiency (HIT [kB/sec] / DIRECT [kB/sec]):', 'factor', ($tcp_hit_time and ($tcp_miss_size + $tcp_miss_none_size)) ? $tcp_hit_size/$tcp_hit_time * ($tcp_miss_none_time + $tcp_miss_time) / ($tcp_miss_size + $tcp_miss_none_size) : 0 ); outline( $report_index, '', 'Average speed increase:', '%', ($tcp_miss_size + $tcp_miss_none_size) ? 100 * ( -1 + $tcp_size/$tcp_time * ($tcp_miss_none_time + $tcp_miss_time) / ($tcp_miss_size + $tcp_miss_none_size)) : 0 ); @format = ( 53, 14, 10 ); if ($opt_response_time) { # average response time $reqtime_sum = $reqtime_num = $avg_udp_reqtime = $avg_tcp_reqtime = 0; my $skipped = 0; foreach $reqtime ( keys %udp_reqtime ) { if ($reqtime > $response_time_limit) { $skipped += $tcp_reqtime{$reqtime}; next; } $reqtime_sum += $reqtime * $udp_reqtime{$reqtime}; $reqtime_num += $tcp_reqtime{$reqtime} if $tcp_reqtime{$reqtime}; } $avg_udp_reqtime = ($reqtime_num) ? $reqtime_sum / $reqtime_num : '0'; my $time_skipped = ($response_time_limit == $response_time_report_interval[$#response_time_report_interval]) ? '' : " (requests > $response_time_limit msec skipped)"; my $skipped_percent = (($skipped+$reqtime_num) ? round(100*$reqtime_num/($skipped+$reqtime_num),2) : 100 ) . ' percent'; outline( $report_index, '', "UDP response time of $skipped% requests$time_skipped:", 'msec', kilomegagigatera( $avg_udp_reqtime, $format[2] ) ) if ($avg_udp_reqtime); $skipped = 0; $reqtime_sum = $reqtime_num = 0; foreach $reqtime ( keys %tcp_reqtime ) { if ($reqtime > $response_time_limit) { $skipped += $tcp_reqtime{$reqtime}; next; } $reqtime_sum += $reqtime * $tcp_reqtime{$reqtime}; $reqtime_num += $tcp_reqtime{$reqtime}; } $avg_tcp_reqtime = ($reqtime_num) ? $reqtime_sum / $reqtime_num : '0'; $skipped_percent = (($skipped+$reqtime_num) ? round(100*$reqtime_num/($skipped+$reqtime_num),2) : 100 ) . '%'; outline( $report_index, '', "TCP response time of $skipped_percent requests$time_skipped:", 'msec', kilomegagigatera( $avg_tcp_reqtime, $format[2] ) ) if ($avg_tcp_reqtime); } outseperator($report_index); outheader( $report_index, 'Cache statistics', '', ''); outseperator($report_index); outline( $report_index, '', 'Total amount cached:', 'requests', $tcp_hit + $udp_hit ); @format = ( 53, 14, '10%' ); outline( $report_index, '', 'Request hit rate:', '%', ($tcp + $udp) ? 100 * ($tcp_hit + $udp_hit) / ($tcp + $udp) : 0 ); @format = ( 53, 14, 10 ); outline( $report_index, '', 'Bandwidth savings:', 'Byte', kilomegagigatera( $tcp_hit_size + $udp_hit_size, $format[2] ) ); @format = ( 53, 14, '10%' ); outline( $report_index, '', 'Bandwidth savings in Percent (Byte hit rate):', '%', ($tcp_size + $udp_size) ? 100 * ($tcp_hit_size + $udp_hit_size) / ($tcp_size + $udp_size) : 0 ); @format = ( 53, 14, 10 ); if ($opt_D) { # Object sizes $cached_obj_size = $cached_obj_num = $obj_size = $obj_num = $avg_cached_obj_size = $avg_direct_obj_size = $avg_all_obj_size = 0; foreach $distribution ( sort { $a <=> $b } keys(%tcp_distribution) ) { $cached_obj_size += $tcp_hit_distribution_size{$distribution}; $cached_obj_num += $tcp_hit_distribution{$distribution}; $obj_size += $tcp_distribution_size{$distribution}; $obj_num += $tcp_distribution{$distribution}; } $avg_cached_obj_size = $cached_obj_size / $cached_obj_num if $cached_obj_num; $avg_direct_obj_size = ($obj_size - $cached_obj_size) / ($obj_num - $cached_obj_num) if $obj_num - $cached_obj_num; $avg_all_obj_size = $obj_size / $obj_num if $obj_num; outline( $report_index, '', 'Average cached object size:', 'Byte', kilomegagigatera( $avg_cached_obj_size, $format[2] ) ); outline( $report_index, '', 'Average direct object size:', 'Byte', kilomegagigatera( $avg_direct_obj_size, $format[2] ) ); outline( $report_index, '', 'Average object size:', 'Byte', kilomegagigatera( $avg_all_obj_size, $format[2] ) ); } $max_value[$report_index] = '- - -'; outseperator($report_index); outstop($report_index); # Incoming request peak per protocol $report_index = 1; @format = ( 3, 4, 18, 5, 18, 7, 18 ); if ( not defined $opt_p ) { } elsif ( $opt_p eq 'old' ) { writecache( $report_index, $peak_udp_sec, $peak_udp_sec_time, $peak_udp_min, $peak_udp_min_time, $peak_udp_hour, $peak_udp_hour_time, $peak_tcp_sec, $peak_tcp_sec_time, $peak_tcp_min, $peak_tcp_min_time, $peak_tcp_hour, $peak_tcp_hour_time, $peak_all_sec, $peak_all_sec_time, $peak_all_min, $peak_all_min_time, $peak_all_hour, $peak_all_hour_time ); outstart($report_index); outheader( $report_index, 'prt', ' sec', 'peak begins at', ' min', 'peak begins at', ' hour', 'peak begins at' ); outseperator($report_index); outline( $report_index, '', 'UDP', $peak_udp_sec, convertdate($peak_udp_sec_time), $peak_udp_min, convertdate($peak_udp_min_time), $peak_udp_hour, convertdate($peak_udp_hour_time) ); outline( $report_index, '', 'TCP', $peak_tcp_sec, convertdate($peak_tcp_sec_time), $peak_tcp_min, convertdate($peak_tcp_min_time), $peak_tcp_hour, convertdate($peak_tcp_hour_time) ); outseperator($report_index); outline( $report_index, '', 'ALL', $peak_all_sec, convertdate($peak_all_sec_time), $peak_all_min, convertdate($peak_all_min_time), $peak_all_hour, convertdate($peak_all_hour_time) ); $max_value[$report_index] = '- - -'; outstop($report_index); } elsif ( $opt_p eq 'new' ) { $peak_udp_hour_time = ( sort { $peak_udp_hour{$b} <=> $peak_udp_hour{$a} } keys(%peak_udp_hour) )[0] or $peak_udp_hour_time = $peak_udp_hour{0} = 0; $peak_udp_hour_size_time = ( sort { $peak_udp_hour_size{$b} <=> $peak_udp_hour_size{$a} } keys(%peak_udp_hour_size) )[0] or $peak_udp_hour_size_time = $peak_udp_hour_size{0} = 0; $peak_tcp_hour_time = ( sort { $peak_tcp_hour{$b} <=> $peak_tcp_hour{$a} } keys(%peak_tcp_hour) )[0] or $peak_tcp_hour_time = $peak_tcp_hour{0} = 0; $peak_tcp_hour_size_time = ( sort { $peak_tcp_hour_size{$b} <=> $peak_tcp_hour_size{$a} } keys(%peak_tcp_hour_size) )[0] or $peak_tcp_hour_size_time = $peak_tcp_hour_size{0} = 0; $peak_all_hour_time = ( sort { $peak_all_hour{$b} <=> $peak_all_hour{$a} } keys(%peak_all_hour) )[0] or $peak_all_hour_time = $peak_all_hour{0} = 0; $peak_all_hour_size_time = ( sort { $peak_all_hour_size{$b} <=> $peak_all_hour_size{$a} } keys(%peak_all_hour_size) )[0] or $peak_all_hour_size_time = $peak_all_hour_size{0} = 0; writecache( $report_index, $peak_udp_sec, $peak_udp_sec_time, $peak_udp_min, $peak_udp_min_time, $peak_udp_hour{$peak_udp_hour_time}, $peak_udp_hour_time, $peak_udp_hour_size{$peak_udp_hour_size_time}, $peak_udp_hour_size_time, $peak_tcp_sec, $peak_tcp_sec_time, $peak_tcp_min, $peak_tcp_min_time, $peak_tcp_hour{$peak_tcp_hour_time}, $peak_tcp_hour_time, $peak_tcp_hour_size{$peak_tcp_hour_size_time}, $peak_tcp_hour_size_time, $peak_all_sec, $peak_all_sec_time, $peak_all_min, $peak_all_min_time, $peak_all_hour{$peak_all_hour_time}, $peak_all_hour_time, $peak_all_hour_size{$peak_all_hour_size_time}, $peak_all_hour_size_time ); outstart($report_index); outheader( $report_index, 'prt', ' sec', 'peak begins at', ' min', 'peak begins at', ' hour', 'peak begins at' ); outseperator($report_index); outline( $report_index, '', 'UDP', $peak_udp_sec, convertdate($peak_udp_sec_time), $peak_udp_min, convertdate($peak_udp_min_time), $peak_udp_hour{$peak_udp_hour_time}, convertdate($peak_udp_hour_time) ); outline( $report_index, '', 'TCP', $peak_tcp_sec, convertdate($peak_tcp_sec_time), $peak_tcp_min, convertdate($peak_tcp_min_time), $peak_tcp_hour{$peak_tcp_hour_time}, convertdate($peak_tcp_hour_time) ); outseperator($report_index); outline( $report_index, '', 'ALL', $peak_all_sec, convertdate($peak_all_sec_time), $peak_all_min, convertdate($peak_all_min_time), $peak_all_hour{$peak_all_hour_time}, convertdate($peak_all_hour_time) ); $max_value[$report_index] = '- - -'; outstop($report_index); # Incoming transfer volume per protocol $report_index = 2; @format = ( 5, 8, 18 ); outstart($report_index); outheader( $report_index, 'proto', ' kB/hour', 'peak begins at' ); outseperator($report_index); outline( $report_index, '', 'UDP', $peak_udp_hour_size{$peak_udp_hour_size_time} / 1024, convertdate($peak_udp_hour_size_time) ); outline( $report_index, '', 'TCP', $peak_tcp_hour_size{$peak_tcp_hour_size_time} / 1024, convertdate($peak_tcp_hour_size_time) ); outseperator($report_index); outline( $report_index, '', 'ALL', $peak_all_hour_size{$peak_all_hour_size_time} / 1024, convertdate($peak_all_hour_size_time) ); $max_value[$report_index] = '- - -'; outstop($report_index); } # Incoming requests by method $report_index = 3; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, '%', 'spr', 8, '%', 'kbps' ); outstart($report_index); if ( $counter == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'method', ' request', '% ', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'auto' ); outseperator($report_index); foreach $method ( sort { ${"method$sortorder"}{$b} <=> ${"method$sortorder"}{$a} } keys(%method) ) { push @xaxis, $method; push @yaxis1, $method{$method}; push @yaxis2, $method_size{$method}; writecache( $report_index, $method, $method{$method}, $method_size{$method}, $method_time{$method} ); outline( $report_index, 'toggle', $method, $method{$method}, 100 * $method{$method} / $counter, $method_time{$method} / ( 1000 * $method{$method} ), kilomegagigatera( $method_size{$method}, $format[4] ), $size ? 100 * $method_size{$method} / $size : 0, $method_size{$method} / ( 1.024 * $method_time{$method} ) ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $counter, 100, $time / ( $counter * 1000 ), kilomegagigatera( $size, $format[4] ), 100, $size / ( 1.024 * $time ) ); outgraph($report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2) if ($outtype_graph and $xaxis[0]); $max_value[$report_index] = 'most requested method ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0] . ' Requests' ); } outstop($report_index); # Incoming UDP-requests by status $report_index = 4; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, '%', 'mspr', 8, '%', 'kbps' ); outstart($report_index); if ( $udp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'status', ' request', '% ', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'auto' ); outseperator($report_index); if ( $udp_hit == 0 ) { outline( $report_index, '', 'HIT', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'HIT'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'HIT'; push @yaxis1, $udp_hit; push @yaxis2, $udp_hit_size; outline( $report_index, '', 'HIT', $udp_hit, 100 * $udp_hit / $udp, $udp_hit_time / (1000 * $udp_hit), kilomegagigatera( $udp_hit_size, $format[4] ), $udp_size ? 100 * $udp_hit_size / $udp_size : 0, $udp_hit_size / ( 1.024 * $udp_hit_time ) ); foreach $hitfail ( sort { ${"udp_hit$sortorder"}{$b} <=> ${"udp_hit$sortorder"}{$a} } keys(%udp_hit) ) { writecache( "$report_index.1", $hitfail, $udp_hit{$hitfail}, $udp_hit_size{$hitfail}, $udp_hit_time{$hitfail} ); outline( $report_index, '', ' ' . $hitfail, $udp_hit{$hitfail}, 100 * $udp_hit{$hitfail} / $udp, $udp_hit_time{$hitfail} / (1000 * $udp_hit{$hitfail}), kilomegagigatera( $udp_hit_size{$hitfail}, $format[4] ), $udp_size ? 100 * $udp_hit_size{$hitfail} / $udp_size : 0, $udp_hit_size{$hitfail} / ( 1.024 * $udp_hit_time{$hitfail} ) ); } } if ( $udp_miss == 0 ) { outline( $report_index, '', 'MISS', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'MISS'; push @yaxis1, $udp_miss; push @yaxis2, $udp_miss_size; } else { push @xaxis, 'MISS'; push @yaxis1, $udp_miss; push @yaxis2, $udp_miss_size; outline( $report_index, '', 'MISS', $udp_miss, 100 * $udp_miss / $udp, $udp_miss_time / (1000 * $udp_miss), kilomegagigatera( $udp_miss_size, $format[4] ), $udp_size ? 100 * $udp_miss_size / $udp_size : 0, $udp_miss_size / ( 1.024 * $udp_miss_time ) ); foreach $hitfail ( sort { ${"udp_miss$sortorder"}{$b} <=> ${"udp_miss$sortorder"}{$a} } keys(%udp_miss) ) { writecache( "$report_index.2", $hitfail, $udp_miss{$hitfail}, $udp_miss_size{$hitfail}, $udp_miss_time{$hitfail} ); outline( $report_index, '', ' ' . $hitfail, $udp_miss{$hitfail}, 100 * $udp_miss{$hitfail} / $udp, $udp_miss_time{$hitfail} / (1000 * $udp_miss{$hitfail}), kilomegagigatera( $udp_miss_size{$hitfail}, $format[4] ), $udp_size ? 100 * $udp_miss_size{$hitfail} / $udp_size : 0, $udp_miss_size{$hitfail} / ( 1.024 * $udp_miss_time{$hitfail} ) ); } } outseperator($report_index); outline( $report_index, '2', 'Sum', $udp, 100, $udp_time / (1000 * $udp), kilomegagigatera( $udp_size, $format[4] ), 100, $udp_size / ( 1.024 * $udp_time ) ); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2) if ($outtype_graph and $xaxis[0]); # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most incoming request by status to ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[$maxi], 6) . ' Byte' : $yaxis1[$maxi] . ' Requests'); } } outstop($report_index); # Incoming TCP-requests by status $report_index = 5; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, '%', 'spr', 8, '%', 'kbps' ); outstart($report_index); if ( $tcp_hit + $tcp_miss + $tcp_miss_none == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'status', ' request', '% ', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'auto' ); outseperator($report_index); if ( $tcp_hit == 0 ) { outline( $report_index, '', 'HIT', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'HIT'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'HIT'; push @yaxis1, $tcp_hit; push @yaxis2, $tcp_hit_size; outline( $report_index, 'toggle', 'HIT', $tcp_hit, 100 * $tcp_hit / $tcp, $tcp_hit_time / ( 1000 * $tcp_hit ), kilomegagigatera( $tcp_hit_size, $format[4] ), $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_hit_size / ( 1.024 * $tcp_hit_time ) ); foreach $hitfail ( sort { ${"tcp_hit$sortorder"}{$b} <=> ${"tcp_hit$sortorder"}{$a} } keys(%tcp_hit) ) { writecache( "$report_index.1", $hitfail, $tcp_hit{$hitfail}, $tcp_hit_size{$hitfail}, $tcp_hit_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $tcp_hit{$hitfail}, 100 * $tcp_hit{$hitfail} / $tcp, $tcp_hit_time{$hitfail} / ( 1000 * $tcp_hit{$hitfail} ), kilomegagigatera( $tcp_hit_size{$hitfail}, $format[4] ), $tcp_size ? 100 * $tcp_hit_size{$hitfail} / $tcp_size : 0, $tcp_hit_size{$hitfail} / ( 1.024 * $tcp_hit_time{$hitfail} ) ); } } if ( $tcp_miss == 0 ) { outline( $report_index, '', 'MISS', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'MISS'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'MISS'; push @yaxis1, $tcp_miss; push @yaxis2, $tcp_miss_size; outline( $report_index, 'toggle', 'MISS', $tcp_miss, 100 * $tcp_miss / $tcp, $tcp_miss_time / ( 1000 * $tcp_miss ), kilomegagigatera( $tcp_miss_size, $format[4] ), $tcp_size ? 100 * $tcp_miss_size / $tcp_size : 0, $tcp_miss_size / ( 1.024 * $tcp_miss_time ) ); foreach $hitfail ( sort { ${"tcp_miss$sortorder"}{$b} <=> ${"tcp_miss$sortorder"}{$a} } keys(%tcp_miss) ) { writecache( "$report_index.2", $hitfail, $tcp_miss{$hitfail}, $tcp_miss_size{$hitfail}, $tcp_miss_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $tcp_miss{$hitfail}, 100 * $tcp_miss{$hitfail} / $tcp, $tcp_miss_time{$hitfail} / ( 1000 * $tcp_miss{$hitfail} ), kilomegagigatera( $tcp_miss_size{$hitfail}, $format[4] ), $tcp_size ? 100 * $tcp_miss_size{$hitfail} / $tcp_size : 0, $tcp_miss_size{$hitfail} / ( 1.024 * $tcp_miss_time{$hitfail} ) ); } } if ( $tcp_miss_none == 0 ) { outline( $report_index, '', 'ERROR', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'ERROR'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'ERROR'; push @yaxis1, $tcp_miss_none; push @yaxis2, $tcp_miss_none_size; outline( $report_index, 'toggle', 'ERROR', $tcp_miss_none, 100 * $tcp_miss_none / $tcp, $tcp_miss_none_time / ( 1000 * $tcp_miss_none ), kilomegagigatera( $tcp_miss_none_size, $format[4] ), $tcp_size ? 100 * $tcp_miss_none_size / $tcp_size : 0, $tcp_miss_none_size / ( 1.024 * $tcp_miss_none_time ) ); foreach $hitfail ( sort { ${"tcp_miss_none$sortorder"}{$b} <=> ${"tcp_miss_none$sortorder"}{$a} } keys(%tcp_miss_none) ) { writecache( "$report_index.3", $hitfail, $tcp_miss_none{$hitfail}, $tcp_miss_none_size{$hitfail}, $tcp_miss_none_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $tcp_miss_none{$hitfail}, 100 * $tcp_miss_none{$hitfail} / $tcp, $tcp_miss_none_time{$hitfail} / ( 1000 * $tcp_miss_none{$hitfail} ), kilomegagigatera( $tcp_miss_none_size{$hitfail}, $format[4] ), $tcp_size ? 100 * $tcp_miss_none_size{$hitfail} / $tcp_size : 0, $tcp_miss_none_size{$hitfail} / ( 1.024 * $tcp_miss_none_time{$hitfail} ) ); } } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, $tcp_time / ( 1000 * $tcp ), kilomegagigatera( $tcp_size, $format[4] ), 100, $tcp_size / ( 1.024 * $tcp_time ) ); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2) if ($outtype_graph and $xaxis[0]); # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most incoming request by status to ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[$maxi], 6) . " Byte" : $yaxis1[$maxi]. " Requests" ); } } outstop($report_index); # Outgoing requests by status $report_index = 6; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, '%', 'spr', 8, '%', 'kbps' ); outstart($report_index); if ( $hier == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'status', ' request', '% ', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'auto' ); outseperator($report_index); if ( $hier_direct == 0 ) { outline( $report_index, '', 'DIRECT', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'DIRECT'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'DIRECT Fetch from Source'; push @yaxis1, $hier_direct; push @yaxis2, $hier_direct_size; outline( $report_index, 'toggle', 'DIRECT Fetch from Source', $hier_direct, 100 * $hier_direct / $hier, $hier_direct_time / ( 1000 * $hier_direct ), kilomegagigatera( $hier_direct_size, $format[4] ), $hier_size ? 100 * $hier_direct_size / $hier_size : 0, $hier_direct_size / ( 1.024 * $hier_direct_time ) ); foreach $hitfail ( sort { ${"hier_direct$sortorder"}{$b} <=> ${"hier_direct$sortorder"}{$a} } keys(%hier_direct) ) { writecache( "$report_index.1", $hitfail, $hier_direct{$hitfail}, $hier_direct_size{$hitfail}, $hier_direct_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $hier_direct{$hitfail}, 100 * $hier_direct{$hitfail} / $hier, $hier_direct_time{$hitfail} / ( 1000 * $hier_direct{$hitfail} ), kilomegagigatera( $hier_direct_size{$hitfail}, $format[4] ), $hier_size ? 100 * $hier_direct_size{$hitfail} / $hier_size : 0, $hier_direct_size{$hitfail} / ( 1.024 * $hier_direct_time{$hitfail} ) ); } } if ( $hier_sibling == 0 ) { outline( $report_index, '', 'SIBLING', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'SIBLING'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'HIT on Sibling or Parent Cache'; push @yaxis1, $hier_sibling; push @yaxis2, $hier_sibling_size; outline( $report_index, 'toggle', 'HIT on Sibling or Parent Cache', $hier_sibling, 100 * $hier_sibling / $hier, $hier_sibling_time / ( 1000 * $hier_sibling ), kilomegagigatera( $hier_sibling_size, $format[4] ), $hier_size ? 100 * $hier_sibling_size / $hier_size : 0, $hier_sibling_size / ( 1.024 * $hier_sibling_time ) ); foreach $hitfail ( sort { ${"hier_sibling$sortorder"}{$b} <=> ${"hier_sibling$sortorder"}{$a} } keys(%hier_sibling) ) { writecache( "$report_index.2", $hitfail, $hier_sibling{$hitfail}, $hier_sibling_size{$hitfail}, $hier_sibling_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $hier_sibling{$hitfail}, 100 * $hier_sibling{$hitfail} / $hier, $hier_sibling_time{$hitfail} / ( 1000 * $hier_sibling{$hitfail} ), kilomegagigatera( $hier_sibling_size{$hitfail}, $format[4] ), $hier_size ? 100 * $hier_sibling_size{$hitfail} / $hier_size : 0, $hier_sibling_size{$hitfail} / ( 1.024 * $hier_sibling_time{$hitfail} ) ); } } if ( $hier_parent == 0 ) { outline( $report_index, '', 'PARENT', 0, 0, 0, 0, 0, 0 ); push @xaxis, 'PARENT'; push @yaxis1, 0; push @yaxis2, 0; } else { push @xaxis, 'FETCH from Parent Cache'; push @yaxis1, $hier_parent; push @yaxis2, $hier_parent_size; outline( $report_index, 'toggle', 'FETCH from Parent Cache', $hier_parent, 100 * $hier_parent / $hier, $hier_parent_time / ( 1000 * $hier_parent ), kilomegagigatera( $hier_parent_size, $format[4] ), $hier_size ? 100 * $hier_parent_size / $hier_size : 0, $hier_parent_size / ( 1.024 * $hier_parent_time ) ); foreach $hitfail ( sort { ${"hier_parent$sortorder"}{$b} <=> ${"hier_parent$sortorder"}{$a} } keys(%hier_parent) ) { writecache( "$report_index.3", $hitfail, $hier_parent{$hitfail}, $hier_parent_size{$hitfail}, $hier_parent_time{$hitfail} ); outline( $report_index, 'toggle', ' ' . $hitfail, $hier_parent{$hitfail}, 100 * $hier_parent{$hitfail} / $hier, $hier_parent_time{$hitfail} / ( 1000 * $hier_parent{$hitfail} ), kilomegagigatera( $hier_parent_size{$hitfail}, $format[4] ), $hier_size ? 100 * $hier_parent_size{$hitfail} / $hier_size : 0, $hier_parent_size{$hitfail} / ( 1.024 * $hier_parent_time{$hitfail} ) ); } } outseperator($report_index); outline( $report_index, '2', 'Sum', $hier, 100, $hier_time / ( 1000 * $hier ), kilomegagigatera( $hier_size, $format[4] ), 100, $hier_size / ( 1.024 * $hier_time ) ); outgraph($report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2) if ($outtype_graph and $xaxis[0]); # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most outgoing request to ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[$maxi], 6) . ' Byte' : $yaxis1[$maxi]. ' Requests' ); } } outstop($report_index); # Outgoing requests by destination $report_index = 7; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, '%', 'spr', 8, '%', 'kbps' ); outstart($report_index); if ( $hier == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'neighbor type', ' request', '% ', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'auto' ); outseperator($report_index); outline( $report_index, 'toggle', 'DIRECT', $hier_direct, 100 * $hier_direct / $hier, $hier_direct_time / ( 1000 * $hier_direct ), kilomegagigatera( $hier_direct_size, $format[4] ), $hier_size ? 100 * $hier_direct_size / $hier_size : 0, $hier_direct_size / ( 1.024 * $hier_direct_time ) ) unless $hier_direct == 0; push @xaxis, 'DIRECT' unless $hier_direct == 0; push @yaxis1, $hier_direct unless $hier_direct == 0; push @yaxis2, $hier_direct_size unless $hier_direct == 0; foreach $neighbor ( sort { ${"hier_neighbor$sortorder"}{$b} <=> ${"hier_neighbor$sortorder"}{$a} } keys(%hier_neighbor) ) { push @xaxis, $neighbor; push @yaxis1, $hier_neighbor{$neighbor}; push @yaxis2, $hier_neighbor_size{$neighbor}; writecache( "$report_index.1", $neighbor, $hier_neighbor{$neighbor}, $hier_neighbor_size{$neighbor}, $hier_neighbor_time{$neighbor} ); outline( $report_index, 'toggle', $neighbor, $hier_neighbor{$neighbor}, 100 * $hier_neighbor{$neighbor} / $hier, $hier_neighbor_time{$neighbor} / ( 1000 * $hier ), kilomegagigatera( $hier_neighbor_size{$neighbor}, $format[4] ), $hier_size ? 100 * $hier_neighbor_size{$neighbor} / $hier_size : 0, $hier_neighbor_size{$neighbor} / ( 1.024 * $hier_neighbor_time{$neighbor} ) ); foreach $status ( sort { ${"hier_neighbor_status$sortorder"}{$neighbor}{$b} <=> ${"hier_neighbor_status$sortorder"}{$neighbor}{$a} } keys(%{$hier_neighbor_status{$neighbor} } ) ) { writecache( "$report_index.2", $neighbor, $status, $hier_neighbor_status{$neighbor}{$status}, $hier_neighbor_status_size{$neighbor}{$status}, $hier_neighbor_status_time{$neighbor}{$status} ); outline( $report_index, 'toggle', ' ' . $status, $hier_neighbor_status{$neighbor}{$status}, 100 * $hier_neighbor_status{$neighbor}{$status} / $hier, $hier_neighbor_status_time{$neighbor}{$status} / ( 1000 * $hier_neighbor_status{$neighbor}{$status} ), kilomegagigatera( $hier_neighbor_status_size{$neighbor}{$status}, $format[4] ), $hier_size ? 100 * $hier_neighbor_status_size{$neighbor}{$status} / $hier_size : 0, $hier_neighbor_status_size{$neighbor}{$status} / ( 1.024 * $hier_neighbor_status_time{$neighbor}{$status} ) ); } } outseperator($report_index); outline( $report_index, '2', 'Sum', $hier, 100, $hier_time / ( 1000 * $hier ), kilomegagigatera( $hier_size, $format[4] ), 100, $hier_size / ( 1.024 * $hier_time ) ); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2) if ($outtype_graph and $xaxis[0]); # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most requested destination ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[$maxi], 6) . ' Byte' : $yaxis1[$maxi] . ' Requests'); } } outstop($report_index); # Request-destinations by ${N}-level-domain $report_index = 8; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 32, 9, '%', '%', 'off', 8, '%', '%', 'off' ); if ($opt_d) { outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); outstop($report_index); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_d < $x_scale and $opt_d != -1) ? $opt_d : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); @counter = keys %tcp_urlhost; $other_urlhost = $#counter + 1; $other = $tcp; $other_size = $tcp_size; $other_hit = $tcp_hit; $other_time = $tcp_time; $other_hit_size = $tcp_hit_size; $other_count = $opt_d; outheader( $report_index, 'destination', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); foreach $urlhost ( sort { ${"tcp_urlhost$sortorder"}{$b} <=> ${"tcp_urlhost$sortorder"}{$a} } keys(%tcp_urlhost) ) { next if $urlhost eq ''; $other_urlhost--; $other -= $tcp_urlhost{$urlhost}; $other_size -= $tcp_urlhost_size{$urlhost}; $other_time -= $tcp_urlhost_time{$urlhost}; $other_hit -= $tcp_hit_urlhost{$urlhost}; $other_hit_size -= $tcp_hit_urlhost_size{$urlhost}; $i++; push @xaxis, $urlhost if ($i < $max_x_data); push @yaxis1, $tcp_urlhost{$urlhost} if ($i < $max_x_data); push @yaxis2, $tcp_urlhost_size{$urlhost} if ($i < $max_x_data); push @yaxis3, $tcp_urlhost{$urlhost} ? $tcp_hit_urlhost{$urlhost} / $tcp_urlhost{$urlhost} : 0 if ($i < $max_x_data); push @yaxis4, $tcp_urlhost_size{$urlhost} ? $tcp_hit_urlhost_size{$urlhost} / $tcp_urlhost_size{$urlhost} : 0 if ($i < $max_x_data); writecache( $report_index, $urlhost, $tcp_urlhost{$urlhost}, $tcp_urlhost_size{$urlhost}, $tcp_hit_urlhost{$urlhost}, $tcp_hit_urlhost_size{$urlhost}, $tcp_urlhost_time{$urlhost} ); outline( $report_index, 'toggle', $urlhost, $tcp_urlhost{$urlhost}, 100 * $tcp_urlhost{$urlhost} / $tcp, 100 * $tcp_hit_urlhost{$urlhost} / $tcp_urlhost{$urlhost}, $tcp_urlhost_time{$urlhost} / (1000 * $tcp_urlhost{$urlhost}), kilomegagigatera( $tcp_urlhost_size{$urlhost}, $format[5] ), $tcp_size ? 100 * $tcp_urlhost_size{$urlhost} / $tcp_size : 0, $tcp_urlhost_size{$urlhost} ? 100 * $tcp_hit_urlhost_size{$urlhost} / $tcp_urlhost_size{$urlhost} : 0, $tcp_urlhost_time{$urlhost} ? $tcp_urlhost_size{$urlhost} / ( 1.024 * $tcp_urlhost_time{$urlhost} ) : 0 ); last if ( ( --$other_count == 0 and $other != 1 ) or ($tcp_urlhost{$urlhost} < $opt_domain_report_limit) ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ( $opt_d < $x_scale and $opt_d != -1 ) ? $opt_d + 1 : $x_scale + 1; writecache( $report_index, '', $other, $other_size, $other_hit, $other_hit_size, $other_time ); $other_urlhost = '' unless $show_other_tcp_urlhost; outline( $report_index, '', 'other: ' . $other_urlhost . " $N-level-domains", $other, 100 * $other / $tcp, 100 * $other_hit / $other, $other_time / (1000 * $other), kilomegagigatera( $other_size, $format[5] ), $tcp_size ? 100 * $other_size / $tcp_size : 0, $other_size ? 100 * $other_hit_size / $other_size : 0, $other_size ? $other_size/ (1.024 * $other_time ) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0 ); outgraph($report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); $max_value[$report_index] = "most requested $N-level-domain " . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0] . ' Requests'); test( $report_index, \%tcp_urlhost, \%tcp_urlhost_size, \%tcp_urlhost_time, 'tcp') if $test; outstop($report_index); # Request-destinations by toplevel-domain $report_index = 9; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 32, 9, '%', '%', 'off', 8, '%', '%', 'off' ); outstart($report_index); @xaxis = @yaxis1 = @yaxis2 = @yaxis3 = @yaxis4 = (); $max_x_data = ($opt_d < $x_scale and $opt_d != -1) ? $opt_d : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); outheader( $report_index, 'destination', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); @counter = keys %tcp_urltld; $other_tld = $#counter + 1; $other = $tcp; $other_size = $tcp_size; $other_hit = $tcp_hit; $other_time = $tcp_time; $other_hit_size = $tcp_hit_size; $other_count = $opt_d; foreach $urltld ( sort { ${"tcp_urltld$sortorder"}{$b} <=> ${"tcp_urltld$sortorder"}{$a} } keys(%tcp_urltld) ) { next if $urltld eq ''; $other_tld--; $other -= $tcp_urltld{$urltld}; $other_size -= $tcp_urltld_size{$urltld}; $other_time -= $tcp_urltld_time{$urltld}; $other_hit -= $tcp_hit_urltld{$urltld}; $other_hit_size -= $tcp_hit_urltld_size{$urltld}; $i++; push @xaxis, $urltld if ($i < $max_x_data); push @yaxis1, $tcp_urltld{$urltld} if ($i < $max_x_data); push @yaxis2, $tcp_urltld_size{$urltld} if ($i < $max_x_data); push @yaxis3, $tcp_urltld{$urltld} ? $tcp_hit_urltld{$urltld} / $tcp_urltld{$urltld} : 0 if ($i < $max_x_data); push @yaxis4, $tcp_urltld_size{$urltld} ? $tcp_hit_urltld_size{$urltld} / $tcp_urltld_size{$urltld} : 0 if ($i < $max_x_data); writecache( $report_index, $urltld, $tcp_urltld{$urltld}, $tcp_urltld_size{$urltld}, $tcp_hit_urltld{$urltld}, $tcp_hit_urltld_size{$urltld}, $tcp_urltld_time{$urltld} ); outline( $report_index, 'toggle', $urltld, $tcp_urltld{$urltld}, 100 * $tcp_urltld{$urltld} / $tcp, 100 * $tcp_hit_urltld{$urltld} / $tcp_urltld{$urltld}, $tcp_urltld_time{$urltld} / (1000 * $tcp_urltld{$urltld}), kilomegagigatera( $tcp_urltld_size{$urltld}, $format[5] ), $tcp_size ? 100 * $tcp_urltld_size{$urltld} / $tcp_size : 0, $tcp_urltld_size{$urltld} ? 100 * $tcp_hit_urltld_size{$urltld} / $tcp_urltld_size{$urltld} : 0, $tcp_urltld_time{$urltld} ? $tcp_urltld_size{$urltld} / ( 1.024 * $tcp_urltld_time{$urltld} ) : 0 ); last if ( ( --$other_count == 0 and $other != 1 ) or ($tcp_urltld{$urltld} < $opt_domain_report_limit) ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ( $opt_d < $x_scale and $opt_d != -1 ) ? $opt_d + 1 : $x_scale + 1; writecache( $report_index, '', $other, $other_size, $other_hit, $other_hit_size, $other_time ); $other_tld = '' unless $show_other_tcp_urltld; outline( $report_index, '', 'other: ' . $other_tld . ' top-level-domains', $other, 100 * $other / $tcp, 100 * $other_hit / $other, $other_time / (1000 * $other), kilomegagigatera( $other_size, $format[5] ), $tcp_size ? 100 * $other_size / $tcp_size : 0, $other_size ? 100 * $other_hit_size / $other_size : 0, $other_size ? $other_size/ (1.024 * $other_time ) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0 ); outgraph($report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); outstop($report_index); test( $report_index, \%tcp_urltld, \%tcp_urltld_size, \%tcp_urltld_time, 'tcp') if $test; $max_value[$report_index] = 'most requested toplevel-domain ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . " Byte" : $yaxis1[0]. " Requests"); } } # TCP-Request-protocol $report_index = 10; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 32, 9, '%', '%', 'off', 8, '%', '%', 'off' ); if ($opt_t) { outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_t < $x_scale and $opt_t != -1) ? $opt_t : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); outheader( $report_index, 'protocol', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); foreach $urlprot ( sort { ${"tcp_urlprot$sortorder"}{$b} <=> ${"tcp_urlprot$sortorder"}{$a} } keys(%tcp_urlprot) ) { push @xaxis, $urlprot; push @yaxis1, $tcp_urlprot{$urlprot}; push @yaxis2, $tcp_urlprot_size{$urlprot}; push @yaxis3, $tcp_urlprot{$urlprot} ? $tcp_hit_urlprot{$urlprot} / $tcp_urlprot{$urlprot} : 0; push @yaxis4, $tcp_urlprot_size{$urlprot} ? $tcp_hit_urlprot_size{$urlprot} / $tcp_urlprot_size{$urlprot} : 0; writecache( $report_index, $urlprot, $tcp_urlprot{$urlprot}, $tcp_urlprot_size{$urlprot}, $tcp_hit_urlprot{$urlprot}, $tcp_hit_urlprot_size{$urlprot}, $tcp_urlprot_time{$urlprot} ); outline( $report_index, 'toggle', $urlprot, $tcp_urlprot{$urlprot}, 100 * $tcp_urlprot{$urlprot} / $tcp, 100 * $tcp_hit_urlprot{$urlprot} / $tcp_urlprot{$urlprot}, $tcp_urlprot_time{$urlprot} / (1000 * $tcp_urlprot{$urlprot}), kilomegagigatera( $tcp_urlprot_size{$urlprot}, $format[5] ), $tcp_size ? 100 * $tcp_urlprot_size{$urlprot} / $tcp_size : 0, $tcp_urlprot_size{$urlprot} ? 100 * $tcp_hit_urlprot_size{$urlprot} / $tcp_urlprot_size{$urlprot} : 0, $tcp_urlprot_time{$urlprot} ? $tcp_urlprot_size{$urlprot} / ( 1.024 * $tcp_urlprot_time{$urlprot} ) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_size / $tcp_time ); outgraph($report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_urlprot, \%tcp_urlprot_size, \%tcp_urlprot_time, 'tcp') if $test; # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most requested protocol ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[$maxi], 6) . ' Byte' : $yaxis1[0] . ' Requests'); } } outstop($report_index); # Requested content-type $report_index = 11; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 32, 9, '%', '%', 'off', 8, '%', '%', 'off' ); if ( %tcp_content ) { outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_t < $x_scale and $opt_t != -1) ? $opt_t : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); @counter = keys %tcp_content; $other_content = $#counter + 1; $other = $tcp; $other_size = $tcp_size; $other_time = $tcp_time; $other_hit = $tcp_hit; $other_hit_size = $tcp_hit_size; $other_count = $opt_t; outheader( $report_index, 'content-type', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); foreach $content ( sort { ${"tcp_content$sortorder"}{$b} <=> ${"tcp_content$sortorder"}{$a} } keys(%tcp_content) ) { next if $content eq ''; $other_content--; $other -= $tcp_content{$content}; $other_size -= $tcp_content_size{$content}; $other_time -= $tcp_content_time{$content}; $other_hit -= $tcp_hit_content{$content}; $other_hit_size -= $tcp_hit_content_size{$content}; $i++; push @xaxis, $content if ($i < $max_x_data); push @yaxis1, $tcp_content{$content} if ($i < $max_x_data); push @yaxis2, $tcp_content_size{$content} if ($i < $max_x_data); push @yaxis3, $tcp_content{$content} ? $tcp_hit_content{$content} / $tcp_content{$content} : 0 if ($i < $max_x_data); push @yaxis4, $tcp_content_size{$content} ? $tcp_hit_content_size{$content} / $tcp_content_size{$content} : 0 if ($i < $max_x_data); writecache( $report_index, $content, $tcp_content{$content}, $tcp_content_size{$content}, $tcp_hit_content{$content}, $tcp_hit_content_size{$content}, $tcp_content_time{$content} ); outline( $report_index, 'toggle', $content, $tcp_content{$content}, 100 * $tcp_content{$content} / $tcp, 100 * $tcp_hit_content{$content} / $tcp_content{$content}, $tcp_content_time{$content} / (1000 * $tcp_content{$content}), kilomegagigatera( $tcp_content_size{$content}, $format[5] ), $tcp_size ? 100 * $tcp_content_size{$content} / $tcp_size : 0, $tcp_content_size{$content} ? 100 * $tcp_hit_content_size{$content} / $tcp_content_size{$content} : 0, $tcp_content_time{$content} ? $tcp_content_size{$content} / ( 1.024 * $tcp_content_time{$content} ) : 0 ); last if ( --$other_count == 0 and $other != 1 ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ($opt_t < $x_scale and $opt_t != -1) ? $opt_t + 1 : $x_scale + 1; writecache( $report_index, '', $other, $other_size, $other_hit, $other_hit_size, $other_time ); $other_content = '' unless $show_other_tcp_content; outline( $report_index, '', 'other: ' . $other_content . ' content-types', $other, 100 * $other / $tcp, 100 * $other_hit / $other, $other_time / (1000 * $other), kilomegagigatera( $other_size, $format[5] ), $tcp_size ? 100 * $other_size / $tcp_size : 0, $other_size ? 100 * $other_hit_size / $other_size : 0, $other_size ? $other_size/ (1.024 * $other_time ) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0 ); outgraph($report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_content, \%tcp_content_size, \%tcp_content_time, 'tcp') if $test; $max_value[$report_index] = 'most requested content-type ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0] . ' Requests'); } outstop($report_index); } # Requested extensions $report_index = 12; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 32, 9, '%', '%', 'off', 8, '%', '%', 'off', 'off', 'off' ); outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_t < $x_scale and $opt_t != -1) ? $opt_t : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); @counter = keys %tcp_urlext; $other_urlext = $#counter + 1; $other = $tcp; $other_size = $tcp_size; $other_time = $tcp_time; $other_hit = $tcp_hit; $other_hit_size = $tcp_hit_size; $other_count = $opt_t; $sum_tcp_urlext_fresh = 0; $sum_tcp_urlext_stale = 0; $sum_tcp_urlext_refresh = 0; $sum_tcp_urlext_mod = 0; $sum_tcp_urlext_unmod = 0; foreach $urlext ( sort {${"tcp_urlext$sortorder"}{$b} <=> ${"tcp_urlext$sortorder"}{$a} } keys(%tcp_urlext) ) { $sum_tcp_urlext_fresh += $tcp_urlext_fresh{$urlext}; $sum_tcp_urlext_stale += $tcp_urlext_stale{$urlext}; $sum_tcp_urlext_refresh += $tcp_urlext_refresh{$urlext}; $sum_tcp_urlext_mod += $tcp_urlext_mod{$urlext}; $sum_tcp_urlext_unmod += $tcp_urlext_unmod{$urlext}; } $other_fresh = $sum_tcp_urlext_fresh; $other_stale = $sum_tcp_urlext_stale; $other_mod = $sum_tcp_urlext_mod; $other_unmod = $sum_tcp_urlext_unmod; $other_refresh = $sum_tcp_urlext_refresh; outheader( $report_index, 'extensions', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto', 'fresh/stale', 'unmod/mod' ); outseperator($report_index); foreach $urlext ( sort {${"tcp_urlext$sortorder"}{$b} <=> ${"tcp_urlext$sortorder"}{$a} } keys(%tcp_urlext) ) { $sum_tcp_urlext_fresh += $tcp_urlext_fresh{$urlext}; $sum_tcp_urlext_stale += $tcp_urlext_stale{$urlext}; $sum_tcp_urlext_refresh += $tcp_urlext_refresh{$urlext}; $sum_tcp_urlext_mod += $tcp_urlext_mod{$urlext}; $sum_tcp_urlext_unmod += $tcp_urlext_unmod{$urlext}; } foreach $urlext ( sort {${"tcp_urlext$sortorder"}{$b} <=> ${"tcp_urlext$sortorder"}{$a} } keys(%tcp_urlext) ) { next if $urlext eq ''; $other_urlext--; $other -= $tcp_urlext{$urlext}; $other_size -= $tcp_urlext_size{$urlext}; $other_time -= $tcp_urlext_time{$urlext}; $other_hit -= $tcp_hit_urlext{$urlext}; $other_hit_size -= $tcp_hit_urlext_size{$urlext}; $other_fresh -= $tcp_urlext_fresh{$urlext}; $other_stale -= $tcp_urlext_stale{$urlext}; $other_mod -= $tcp_urlext_mod{$urlext}; $other_unmod -= $tcp_urlext_unmod{$urlext}; $other_refresh -= $tcp_urlext_refresh{$urlext}; $i++; push @xaxis, $urlext if ($i < $max_x_data); push @yaxis1, $tcp_urlext{$urlext} if ($i < $max_x_data); push @yaxis2, $tcp_urlext_size{$urlext} if ($i < $max_x_data); push @yaxis3, $tcp_urlext{$urlext} ? $tcp_hit_urlext{$urlext} / $tcp_urlext{$urlext} : 0 if ($i < $max_x_data); push @yaxis4, $tcp_urlext_size{$urlext} ? $tcp_hit_urlext_size{$urlext} / $tcp_urlext_size{$urlext} : 0 if ($i < $max_x_data); writecache( $report_index, $urlext, $tcp_urlext{$urlext}, $tcp_urlext_size{$urlext}, $tcp_hit_urlext{$urlext}, $tcp_hit_urlext_size{$urlext}, $tcp_urlext_time{$urlext}, $tcp_urlext_fresh{$urlext}, $tcp_urlext_stale{$urlext}, $tcp_urlext_refresh{$urlext}, $tcp_urlext_mod{$urlext}, $tcp_urlext_unmod{$urlext} ); outline( $report_index, 'toggle', $urlext, $tcp_urlext{$urlext}, 100 * $tcp_urlext{$urlext} / $tcp, 100 * $tcp_hit_urlext{$urlext} / $tcp_urlext{$urlext}, $tcp_urlext_time{$urlext} / ( 1000 * $tcp_urlext{$urlext} ), kilomegagigatera( $tcp_urlext_size{$urlext}, $format[5] ), $tcp_size ? 100 * $tcp_urlext_size{$urlext} / $tcp_size : 0, $tcp_urlext_size{$urlext} ? 100 * $tcp_hit_urlext_size{$urlext} / $tcp_urlext_size{$urlext} : 0, $tcp_urlext_time{$urlext} ? $tcp_urlext_size{$urlext} / ( 1.024 * $tcp_urlext_time{$urlext} ) : 0, join ('/', gcd($tcp_urlext_fresh{$urlext}, $tcp_urlext_stale{$urlext})), join ('/', gcd($tcp_urlext_unmod{$urlext}, $tcp_urlext_mod{$urlext})) ); last if ( --$other_count == 0 and $other != 1 ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ( $opt_t < $x_scale and $opt_t != -1 ) ? $opt_t + 1 : $x_scale + 1; writecache( $report_index, '', $other, $other_size, $other_hit, $other_hit_size, $other_time, $other_fresh, $other_stale, $other_refresh, $other_mod, $other_unmod ); $other_urlext = '' unless $show_other_tcp_urlext; outline( $report_index, '', 'other: ' . $other_urlext . ' extensions', $other, 100 * $other / $tcp, 100 * $other_hit / $other, $other_time / (1000 * $other), kilomegagigatera( $other_size, $format[5] ), $tcp_size ? 100 * $other_size / $tcp_size : 0, $other_size ? 100 * $other_hit_size / $other_size : 0, $other_size ? $other_size/ (1.024 * $other_time ) : 0, join ('/', gcd($other_fresh, $other_stale)), join ('/', gcd($other_unmod, $other_mod)) ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0, join ('/', gcd($sum_tcp_urlext_fresh, $sum_tcp_urlext_stale)), join ('/', gcd($sum_tcp_urlext_mod, $sum_tcp_urlext_unmod)) ); outgraph($report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_urlext, \%tcp_urlext_size, \%tcp_urlext_time, 'tcp') if $test; $max_value[$report_index] = 'most requested extension ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0]. ' Requests'); } outstop($report_index); } if ($opt_r) { # Incoming UDP-requests by host $report_index = 13; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 38, 9, 'off', '%', 'off', 8, 'off', '%', 'kbps' ); outstart($report_index); if ( $udp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_t < $x_scale and $opt_t != -1) ? $opt_t : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); if ($opt_R) { outheader( $report_index, 'host / target', ' request', '%', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '%', 'hit-%', 'auto' ); } else { outheader( $report_index, 'host', ' request', '%', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '%', 'hit-%', 'auto' ); } outseperator($report_index); @counter = keys %udp_requester; $other_requester = $#counter + 1; $other = $udp; $other_size = $udp_size; $other_time = $udp_time; $other_hit = $udp_hit; $other_hit_size = $udp_hit_size; $other_count = $opt_r; foreach $requester ( sort { ${"udp_requester$sortorder"}{$b} <=> ${"udp_requester$sortorder"}{$a} } keys(%udp_requester) ) { next if $requester eq ''; $other_requester--; $other -= $udp_requester{$requester}; $other_size -= $udp_requester_size{$requester}; $other_time -= $udp_requester_time{$requester}; $other_hit -= $udp_hit_requester{$requester}; $other_hit_size -= $udp_hit_requester_size{$requester}; $i++; push @xaxis, $requester if ($i < $max_x_data); push @yaxis1, $udp_requester{$requester} if ($i < $max_x_data); push @yaxis2, $udp_requester_size{$requester} if ($i < $max_x_data); push @yaxis3, $udp_requester{$requester} ? $udp_hit_requester{$requester} / $udp_requester{$requester} : 0 if ($i < $max_x_data); push @yaxis4, $udp_requester_size{$requester} ? $udp_hit_requester_size{$requester} / $udp_requester_size{$requester} : 0 if ($i < $max_x_data); writecache( "$report_index.1", $requester, $udp_requester{$requester}, $udp_requester_size{$requester}, $udp_requester_time{$requester}, $udp_hit_requester{$requester}, $udp_hit_requester_size{$requester} ); outline( $report_index, '', $requester, $udp_requester{$requester}, $udp ? 100 * $udp_requester{$requester} / $udp : 0, 100 * $udp_hit_requester{$requester} / $udp_requester{$requester}, $udp_requester{$requester} ? $udp_requester_time{$requester} / ( 1000 * $udp_requester{$requester} ) : 0, kilomegagigatera( $udp_requester_size{$requester}, $format[5] ), $udp_size ? 100 * $udp_requester_size{$requester} / $udp_size : 0, $udp_requester_size{$requester} ? 100 * $udp_hit_requester_size{$requester} / $udp_requester_size{$requester} : 0, $udp_requester_size{$requester} / ( 1.024 * $udp_requester_time{$requester} ) ); if ($opt_R) { @counter2 = keys( %{ $udp_requester_urlhost{$requester} } ); $other2_requester_urlhost = $#counter2 + 1; $other2 = $udp_requester{$requester}; $other2_size = $udp_requester_size{$requester}; $other2_time = $udp_requester_time{$requester}; $other2_hit = $udp_hit_requester{$requester}; $other2_hit_size = $udp_hit_requester_size{$requester}; $other2_count = $opt_R; foreach $urlhost ( sort { ${"udp_requester_urlhost$sortorder"}{$requester}{$b} <=> ${"udp_requester_urlhost$sortorder"}{$requester}{$a} } keys( %{ $udp_requester_urlhost{$requester} } ) ) { next if $urlhost eq ''; $other2_requester_urlhost--; $other2 -= $udp_requester_urlhost{$requester}{$urlhost}; $other2_size -= $udp_requester_urlhost_size{$requester}{$urlhost}; $other2_time -= $udp_requester_urlhost_time{$requester}{$urlhost}; $other2_hit -= $udp_hit_requester_urlhost{$requester}{$urlhost}; $other2_hit_size -= $udp_hit_requester_urlhost_size{$requester}{$urlhost}; writecache( "$report_index.2", $requester, $urlhost, $udp_requester_urlhost{$requester}{$urlhost}, $udp_requester_urlhost_size{$requester}{$urlhost}, $udp_requester_urlhost_time{$requester}{$urlhost}, $udp_hit_requester_urlhost{$requester}{$urlhost}, $udp_hit_requester_urlhost_size{$requester}{$urlhost} ); outline( $report_index, 'toggle', ' ' . $urlhost, $udp_requester_urlhost{$requester}{$urlhost}, '', 100 * $udp_hit_requester_urlhost{$requester}{$urlhost} / $udp_requester_urlhost{$requester}{$urlhost}, $udp_requester_urlhost_time{$requester}{$urlhost} / (1000 * $udp_requester_urlhost{$requester}{$urlhost}), kilomegagigatera( $udp_requester_urlhost_size{$requester}{$urlhost}, $format[5] ), '', $udp_requester_urlhost_size{$requester}{$urlhost} ? 100 * $udp_hit_requester_urlhost_size{$requester}{$urlhost} / $udp_requester_urlhost_size{$requester}{$urlhost} : 0, $udp_requester_urlhost_size{$requester}{$urlhost} / ( 1.024 * $udp_requester_urlhost_time{$requester}{$urlhost} ) ); last if ( --$other2_count == 0 and $other2 != 1 ); } if ($other2) { writecache( "$report_index.2", $requester, '', $other2, $other2_size, $other2_time, $other2_hit, $other2_hit_size ); outline( $report_index, '', ' other: ' . $other2_requester_urlhost . ' requested urlhosts', $other2, '', 100 * $other2_hit / $other2, $other2_time / ( 1000 * $other2_requester_urlhost ), kilomegagigatera( $other2_size, $format[5] ), '', $other2_size ? 100 * $other2_hit_size / $other2_size : 0, $other2_size / ( 1.024 * $other2_time ) ); } } last if ( --$other_count == 0 and $other != 1 ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ( $opt_r < $x_scale and $opt_r != -1 ) ? $opt_r + 1 : $x_scale + 1; writecache( "$report_index.1", '', $other, $other_size, $other_time, $other_hit, $other_hit_size ); $other_requester = '' unless $show_other_udp_requester; outline( $report_index, '', 'other: ' . $other_requester . ' requesting hosts', $other, '', 100 * $other_hit / $other, $other_time / ( 1000 * $udp ), kilomegagigatera( $other_size, $format[5] ), '', 100 * $other_hit_size / $other_size, $other_size / ( 1.024 * $udp_time ) ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $udp, 100, 100 * $udp_hit / $udp, $udp_time / (1000 * $udp), kilomegagigatera( $udp_size, $format[5] ), 100, $udp_size ? 100 * $udp_hit_size / $udp_size : 0, $udp_time ? $udp_size / ( 1.024 * $udp_time ) : 0 ); outgraph( $report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%udp_requester, \%udp_requester_size, \%udp_requester_time, 'udp') if $test; $max_value[$report_index] = 'most active host ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0] . ' Requests'); } outstop($report_index); # Incoming TCP-requests by host $report_index = 14; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, 'off', '%', 'spr', 8, 'off', '%', 'kbps' ); outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); $max_x_data = ($opt_r < $x_scale and $opt_r != -1) ? $opt_r : $x_scale; $i = 0; outimg($report_index) if ($outtype_graph); if ($opt_R) { outheader( $report_index, 'host / target', ' request', '%', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '%', 'hit-%', 'auto' ); } else { outheader( $report_index, 'host', ' request', '%', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '%', 'hit-%', 'auto' ); } outseperator($report_index); @counter = keys %tcp_requester; $other_requester = $#counter + 1; $other = $tcp; $other_size = $tcp_size; $other_time = $tcp_time; $other_hit = $tcp_hit; $other_hit_size = $tcp_hit_size; $other_count = $opt_r; foreach $requester ( sort { ${"tcp_requester$sortorder"}{$b} <=> ${"tcp_requester$sortorder"}{$a} } keys(%tcp_requester) ) { next if $requester eq ''; $other_requester--; $other -= $tcp_requester{$requester}; $other_size -= $tcp_requester_size{$requester}; $other_time -= $tcp_requester_time{$requester}; $other_hit -= $tcp_hit_requester{$requester}; $other_hit_size -= $tcp_hit_requester_size{$requester}; $i++; push @xaxis, $requester if ($i < $max_x_data); push @yaxis1, $tcp_requester{$requester} if ($i < $max_x_data); push @yaxis2, $tcp_requester_size{$requester} if ($i < $max_x_data); push @yaxis3, $tcp_requester{$requester} ? $tcp_hit_requester{$requester} / $tcp_requester{$requester} : 0 if ($i < $max_x_data); push @yaxis4, $tcp_requester_size{$requester} ? $tcp_hit_requester_size{$requester} / $tcp_requester_size{$requester} : 0 if ($i < $max_x_data); writecache( "$report_index.1", $requester, $tcp_requester{$requester}, $tcp_requester_size{$requester}, $tcp_requester_time{$requester}, $tcp_hit_requester{$requester}, $tcp_hit_requester_size{$requester} ); outline( $report_index, 'toggle', uri_unescape($requester), $tcp_requester{$requester}, $tcp ? 100 * $tcp_requester{$requester} / $tcp : 0, 100 * $tcp_hit_requester{$requester} / $tcp_requester{$requester}, $tcp_requester_time{$requester} / ( 1000 * $tcp_requester{$requester} ), kilomegagigatera( $tcp_requester_size{$requester}, $format[5] ), $tcp_size ? 100 * $tcp_requester_size{$requester} / $tcp_size : 0, $tcp_requester_size{$requester} ? 100 * $tcp_hit_requester_size{$requester} / $tcp_requester_size{$requester} : 0, $tcp_requester_size{$requester} / ( 1.024 * $tcp_requester_time{$requester} ) ); if ($opt_R) { @counter2 = keys( %{ $tcp_requester_urlhost{$requester} } ); $other2_requester_urlhost = $#counter2 + 1; $other2 = $tcp_requester{$requester}; $other2_size = $tcp_requester_size{$requester}; $other2_time = $tcp_requester_time{$requester}; $other2_hit = $tcp_hit_requester{$requester}; $other2_hit_size = $tcp_hit_requester_size{$requester}; $other2_count = $opt_R; foreach $urlhost ( sort { ${"tcp_requester_urlhost$sortorder"}{$requester}{$b} <=> ${"tcp_requester_urlhost$sortorder"}{$requester}{$a} } keys( %{ $tcp_requester_urlhost{$requester} } ) ) { next if $urlhost eq ''; $other2_requester_urlhost--; $other2 -= $tcp_requester_urlhost{$requester}{$urlhost}; $other2_size -= $tcp_requester_urlhost_size{$requester}{$urlhost}; $other2_time -= $tcp_requester_urlhost_time{$requester}{$urlhost}; $other2_hit -= $tcp_hit_requester_urlhost{$requester}{$urlhost}; $other2_hit_size -= $tcp_hit_requester_urlhost_size{$requester}{$urlhost}; writecache( "$report_index.2", $requester, $urlhost, $tcp_requester_urlhost{$requester}{$urlhost}, $tcp_requester_urlhost_size{$requester}{$urlhost}, $tcp_requester_urlhost_time{$requester}{$urlhost}, $tcp_hit_requester_urlhost{$requester}{$urlhost}, $tcp_hit_requester_urlhost_size{$requester}{$urlhost} ); outline( $report_index, 'toggle', ' ' . $urlhost, $tcp_requester_urlhost{$requester}{$urlhost}, '', 100 * $tcp_hit_requester_urlhost{$requester}{$urlhost} / $tcp_requester_urlhost{$requester}{$urlhost}, $tcp_requester_urlhost_time{$requester}{$urlhost} / ( 1000 * $tcp_requester_urlhost{$requester}{$urlhost} ), kilomegagigatera( $tcp_requester_urlhost_size{$requester}{$urlhost}, $format[5] ), '', $tcp_requester_urlhost_size{$requester}{$urlhost} ? 100 * $tcp_hit_requester_urlhost_size{$requester}{$urlhost} / $tcp_requester_urlhost_size{$requester}{$urlhost} : 0, $tcp_requester_urlhost_size{$requester}{$urlhost} / ( 1.024 * $tcp_requester_urlhost_time{$requester}{$urlhost} ) ); last if ( --$other2_count == 0 and $other2 != 1 ); } if ($other2) { writecache( "$report_index.2", $requester, '', $other2, $other2_size, $other2_time, $other2_hit, $other2_hit_size ); outline( $report_index, '', ' other: ' . $other2_requester_urlhost . ' requested urlhosts', $other2, '', 100 * $other2_hit / $other2, $other2_time / ( 1000 * $other2_requester_urlhost ), kilomegagigatera( $other2_size, $format[5] ), '', $other2_size ? 100 * $other2_hit_size / $other2_size : 0, $other2_size / ( 1.024 * $other2_time ) ); } } last if ( --$other_count == 0 and $other != 1 ); } if ($other) { push @xaxis, ''; push @yaxis1, $other; push @yaxis2, $other_size; push @yaxis3, $other ? $other_hit / $other : 0; push @yaxis4, $other_size ? $other_hit_size / $other_size : 0; $max_x_data = ( $opt_r < $x_scale and $opt_r != -1 ) ? $opt_r + 1 : $x_scale + 1; writecache( "$report_index.1", '', $other, $other_size, $other_time, $other_hit, $other_hit_size ); $other_requester = '' unless $show_other_tcp_requester; outline( $report_index, '', 'other: ' . $other_requester . ' requesting hosts', $other, '', 100 * $other_hit / $other, $other_time / ( 1000 * $tcp ), kilomegagigatera( $other_size, $format[5] ), '', $other_size ? 100 * $other_hit_size / $other_size : 0, $other_size / ( 1.024 * $tcp_time ) ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0 ); outgraph( $report_index, \@graph_legend, $max_x_data, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_requester, \%tcp_requester_size, \%tcp_requester_time, 'tcp') if $test; $max_value[$report_index] = 'most active host ' . htmlescape($xaxis[0]) . ' ' . ($opt_O ? kilomegagigatera($yaxis2[0], 6) . ' Byte' : $yaxis1[0] . ' Requests'); } outstop($report_index); } # Size Distribution Diagram $report_index = 15; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 30, 9, 'off', '%', 'spr', 8, 'off', '%', 'kbps' ); if ($opt_D) { outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'object-size (bytes)', ' request', '%', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '%', 'hit-%', 'auto' ); outseperator($report_index); foreach $distribution ( sort { $a <=> $b } keys(%tcp_distribution) ) { push @xaxis, int( $opt_D**$distribution ) . '-' . int( $opt_D**( $distribution + 1 ) - 1 ); push @yaxis1, $tcp_distribution{$distribution}; push @yaxis2, $tcp_distribution_size{$distribution}; push @yaxis3, $tcp_distribution{$distribution} ? $tcp_hit_distribution{$distribution} / $tcp_distribution{$distribution} : 0; push @yaxis4, $tcp_distribution_size{$distribution} ? $tcp_hit_distribution_size{$distribution} / $tcp_distribution_size{$distribution} : 0; writecache( $report_index, $distribution, $tcp_distribution{$distribution}, $tcp_distribution_size{$distribution}, $tcp_distribution_time{$distribution}, $tcp_hit_distribution{$distribution}, $tcp_hit_distribution_size{$distribution} ); outline( $report_index, '', int( $opt_D**$distribution ) . '-' . int( $opt_D**( $distribution + 1 ) - 1 ), $tcp_distribution{$distribution}, 100 * $tcp_distribution{$distribution} / $tcp, 100 * $tcp_hit_distribution{$distribution} / $tcp_distribution{$distribution}, $tcp_distribution_time{$distribution} / ( 1000 * $tcp_distribution{$distribution} ), kilomegagigatera( $tcp_distribution_size{$distribution}, $format[5] ), $tcp_size ? 100 * $tcp_distribution_size{$distribution} / $tcp_size : 0, $tcp_distribution_size{$distribution} ? 100 * $tcp_hit_distribution_size{$distribution} / $tcp_distribution_size{$distribution} : 0, $tcp_distribution_size{$distribution} / ( 1.024 * $tcp_distribution_time{$distribution} ) ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0 ); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); # find max value my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most requested object_size ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($max, 6) . ' Byte' : $max . ' Requests'); } test( $report_index, \%tcp_distribution, \%tcp_distribution_size, \%tcp_distribution_time, 'tcp') if $test; } outstop($report_index); } # Performance in $P steps $report_index = 16; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 15, 9, 'off', 5, 'off', 'off', 'kbps', 'kbps', 'kbps', 'kbps', 'kbps', 'kbps' ); if ($opt_P) { outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, '', '', '', '', '', '', 'incomin', ' hit', ' miss', ' direct', 'sibling', ' fetch' ); outheader( $report_index, 'date', ' request', 'hit-%', ' Byte', 'hit-%', 'IPs', 'auto', 'auto', 'auto', 'auto', 'auto', 'auto'); outseperator($report_index); foreach $perf_date ( sort { $a <=> $b } keys(%perf_counter) ) { $perf_requester{$perf_date} = scalar keys %{$perf_ip{$perf_date}}; push @xaxis, substr( convertdate($perf_date), 0, 15 ); push @yaxis1, $perf_counter{$perf_date}; push @yaxis2, $perf_size{$perf_date}; push @yaxis3, $perf_counter{$perf_date} ? $perf_tcp_hit{$perf_date} / $perf_counter{$perf_date} : 0; push @yaxis4, $perf_size{$perf_date} ? $perf_tcp_hit_size{$perf_date} / $perf_size{$perf_date} : 0; writecache( $report_index, $perf_date, $perf_counter{$perf_date}, $perf_size{$perf_date}, $perf_time{$perf_date}, $perf_tcp_hit_size{$perf_date}, $perf_tcp_hit_time{$perf_date}, $perf_tcp_miss_size{$perf_date}, $perf_tcp_miss_time{$perf_date}, $perf_hier_direct_size{$perf_date}, $perf_hier_direct_time{$perf_date}, $perf_hier_sibling_size{$perf_date}, $perf_hier_sibling_time{$perf_date}, $perf_hier_parent_size{$perf_date}, $perf_hier_parent_time{$perf_date}, $perf_requester{$perf_date}, $perf_tcp_hit{$perf_date} ); outline( $report_index, 'toggle', substr( convertdate($perf_date), 0, 15 ), $perf_counter{$perf_date}, $perf_counter{$perf_date} ? 100 * $perf_tcp_hit{$perf_date} / $perf_counter{$perf_date} : 0, kilomegagigatera( $perf_size{$perf_date}, $format[3] ), $perf_size{$perf_date} ? 100 * $perf_tcp_hit_size{$perf_date} / $perf_size{$perf_date} : 0, $perf_requester{$perf_date}, removezerotimes( $perf_size{$perf_date}, $perf_time{$perf_date} ), removezerotimes( $perf_tcp_hit_size{$perf_date}, $perf_tcp_hit_time{$perf_date} ), removezerotimes( $perf_tcp_miss_size{$perf_date}, $perf_tcp_miss_time{$perf_date} ), removezerotimes( $perf_hier_direct_size{$perf_date}, $perf_hier_direct_time{$perf_date} ), removezerotimes( $perf_hier_sibling_size{$perf_date}, $perf_hier_sibling_time{$perf_date} ), removezerotimes( $perf_hier_parent_size{$perf_date}, $perf_hier_parent_time{$perf_date} ) ); } outseperator($report_index); outline( $report_index, '2', 'overall', $tcp, 100 * $tcp_hit / $tcp, kilomegagigatera( $tcp_size, $format[3] ), $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, scalar keys %tcp_requester, removezerotimes( $tcp_size, $tcp_time ), removezerotimes( $tcp_hit_size, $tcp_hit_time ), removezerotimes( $tcp_miss_size, $tcp_miss_time ), removezerotimes( $hier_direct_size, $hier_direct_time ), removezerotimes( $hier_sibling_size, $hier_sibling_time ), removezerotimes( $hier_parent_size, $hier_parent_time ) ); outgraph( $report_index, \@graph_legend, 31, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%perf_counter, \%perf_size, \%perf_time, 'tcp') if $test; my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most active day ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($max, 6) . ' Byte' : $max . ' Requests'); } } outstop($report_index); } # UDP-Request duration distribution in msec $report_index = 17; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ); if ($opt_response_time) { outstart($report_index); if ( $udp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my $max = 0; my $max_interval = 0; foreach $reqtime ( keys %udp_reqtime ) { for ($i = 0; $i <= $#response_time_report_interval; $i++) { if ($reqtime <= $response_time_report_interval[$i]) { if (${"udp_reqtime$sortorder"}{$reqtime} > $max) { $max = ${"udp_reqtime$sortorder"}{$reqtime}; $max_interval = "<= $response_time_report_interval[$i]"; } $ordered_udp_req_time_time{"<= $response_time_report_interval[$i]"} += $reqtime * $udp_reqtime{$reqtime}; $ordered_udp_req_time{"<= $response_time_report_interval[$i]"} += $udp_reqtime{$reqtime}; $ordered_udp_req_time_size{"<= $response_time_report_interval[$i]"} += $udp_reqtime_size{$reqtime}; $ordered_udp_hit_req_time{"<= $response_time_report_interval[$i]"} += $udp_hit_reqtime{$reqtime}; $ordered_udp_hit_req_time_size{"<= $response_time_report_interval[$i]"} += $udp_hit_reqtime_size{$reqtime}; if ( ${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i]"} - (($i == 0 or !defined(${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"})) ? 0 : ${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"}) > $max) { $max = ${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i]"} - (($i == 0 or !defined(${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"})) ? 0 : ${"ordered_udp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"}); $max_interval = "<= $response_time_report_interval[$i]"; } } } } my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'time', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto'); outseperator($report_index); writecache( $report_index, $ordered_udp_req_time_max_interval, $ordered_udp_req_time_max ); foreach $time_interval ( sort { $a =~ m/^(>|<=)\s*(\S+)$/; my $a1 = $2; $b =~ m/^(>|<=)\s*(\S+)$/; my $b1 = $2; return $a1 <=> $b1 } keys(%ordered_udp_req_time) ) { push @xaxis, $time_interval; push @yaxis1, $ordered_udp_req_time{$time_interval}; push @yaxis2, $ordered_udp_req_time_size{$time_interval}; push @yaxis3, $ordered_udp_req_time{$time_interval} ? $ordered_udp_hit_req_time{$time_interval} / $ordered_udp_req_time{$time_interval} : 0; push @yaxis4, $ordered_udp_req_time_size{$time_interval} ? $ordered_udp_hit_req_time_size{$time_interval} / $ordered_udp_req_time_size{$time_interval} : 0; writecache( $report_index, $time_interval, $ordered_udp_req_time{$time_interval}, $ordered_udp_req_time_size{$time_interval}, $ordered_udp_hit_req_time{$time_interval}, $ordered_udp_hit_req_time_size{$time_interval}, $ordered_udp_req_time_time{$time_interval}); outline( $report_index, 'toggle', $time_interval, $ordered_udp_req_time{$time_interval}, 100 * $ordered_udp_req_time{$time_interval} / $udp, 100 * $ordered_udp_hit_req_time{$time_interval} / $ordered_udp_req_time{$time_interval}, $ordered_udp_req_time{$time_interval} ? $ordered_udp_req_time_time{$time_interval} / (1000 * $ordered_udp_req_time{$time_interval}) : 0, kilomegagigatera( $ordered_udp_req_time_size{$time_interval}, $format[5] ), $udp_size ? 100 * $ordered_udp_req_time_size{$time_interval} / $udp_size : 0, $ordered_udp_req_time_size{$time_interval} ? 100 * $ordered_udp_hit_req_time_size{$time_interval} / $ordered_udp_req_time_size{$time_interval} : 0, $ordered_udp_req_time_time{$time_interval} ? $ordered_udp_req_time_size{$time_interval} / (1.024 * $ordered_udp_req_time_time{$time_interval}) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $udp, 100, 100 * $udp_hit / $udp, $udp_time / (1000 * $udp), kilomegagigatera( $udp_size, $format[5] ), 100, $udp_size ? 100 * $udp_hit_size / $udp_size : 0, $udp_time ? $udp_size / ( 1.024 * $udp_time ) : 0); outgraph( $report_index, \@graph_legend, scalar(@response_time_report_interval), \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%udp_reqtime, \%udp_reqtime_size, 0, 'udp') if $test; $max_value[$report_index] = 'most frequent response time ' . htmlescape($max_interval) . ' ' . ($opt_O ? kilomegagigatera($max, 6) . ' Byte' : $max . ' Requests'); } outstop($report_index); # TCP-Request duration distribution in msec $report_index = 18; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ); outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { foreach $reqtime ( keys %tcp_reqtime ) { for ( $i = 0; $i <= $#response_time_report_interval; $i++ ) { if ($reqtime <= $response_time_report_interval[$i]) { $ordered_tcp_req_time_time{"<= $response_time_report_interval[$i]"} += $reqtime * $tcp_reqtime{$reqtime}; $ordered_tcp_req_time{"<= $response_time_report_interval[$i]"} += $tcp_reqtime{$reqtime}; $ordered_tcp_req_time_size{"<= $response_time_report_interval[$i]"} += $tcp_reqtime_size{$reqtime}; $ordered_tcp_hit_req_time{"<= $response_time_report_interval[$i]"} += $tcp_hit_reqtime{$reqtime}; $ordered_tcp_hit_req_time_size{"<= $response_time_report_interval[$i]"} += $tcp_hit_reqtime_size{$reqtime}; if ( ${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i]"} - (( $i == 0 or !defined(${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"})) ? 0 : ${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"}) > $ordered_tcp_req_time_max) { $ordered_tcp_req_time_max = ${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i]"} - (( $i == 0 or !defined(${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"})) ? 0 : ${"ordered_tcp_req_time$sortorder"}{"<= $response_time_report_interval[$i-1]"}); $ordered_tcp_req_time_max_interval = "<= $response_time_report_interval[$i]"; } } } } my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'time', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto'); outseperator($report_index); writecache( $report_index, $ordered_tcp_req_time_max_interval, $ordered_tcp_req_time_max ); foreach $time_interval ( sort { $a =~ m/^(>|<=)\s*(\S+)$/; my $a1 = $2; $b =~ m/^(>|<=)\s*(\S+)$/; my $b1 = $2; return $a1 <=> $b1 } keys(%ordered_tcp_req_time) ) { push @xaxis, $time_interval; push @yaxis1, $ordered_tcp_req_time{$time_interval}; push @yaxis2, $ordered_tcp_req_time_size{$time_interval}; push @yaxis3, $ordered_tcp_req_time{$time_interval} ? $ordered_tcp_hit_req_time{$time_interval} / $ordered_tcp_req_time{$time_interval} : 0; push @yaxis4, $ordered_tcp_req_time_size{$time_interval} ? $ordered_tcp_hit_req_time_size{$time_interval} / $ordered_tcp_req_time_size{$time_interval} : 0; writecache( $report_index, $time_interval, $ordered_tcp_req_time{$time_interval}, $ordered_tcp_req_time_size{$time_interval}, $ordered_tcp_hit_req_time{$time_interval}, $ordered_tcp_hit_req_time_size{$time_interval}, $ordered_tcp_req_time_time{$time_interval}); outline( $report_index, 'toggle', $time_interval, $ordered_tcp_req_time{$time_interval}, 100 * $ordered_tcp_req_time{$time_interval} / $tcp, 100 * $ordered_tcp_hit_req_time{$time_interval} / $ordered_tcp_req_time{$time_interval}, $ordered_tcp_req_time{$time_interval} ? $ordered_tcp_req_time_time{$time_interval} / (1000 * $ordered_tcp_req_time{$time_interval}) : 0, kilomegagigatera( $ordered_tcp_req_time_size{$time_interval}, $format[5] ), $tcp_size ? 100 * $ordered_tcp_req_time_size{$time_interval} / $tcp_size : 0, $ordered_tcp_req_time_size{$time_interval} ? 100 * $ordered_tcp_hit_req_time_size{$time_interval} / $ordered_tcp_req_time_size{$time_interval} : 0, $ordered_tcp_req_time_time{$time_interval} ? $ordered_tcp_req_time_size{$time_interval} / (1.024 * $ordered_tcp_req_time_time{$time_interval}) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0); outgraph( $report_index, \@graph_legend, scalar(@response_time_report_interval), \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_reqtime, \%tcp_reqtime_size, 0, 'tcp') if $test; $max_value[$report_index] = 'most frequent response time ' . htmlescape($ordered_tcp_req_time_max_interval) . ' ' . ($opt_O ? kilomegagigatera($ordered_tcp_req_time_max, 6) . ' Byte' : $ordered_tcp_req_time_max . ' Requests'); } outstop($report_index); } # UDP Response code distribution $report_index = 19; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 46, 9, '%', 'off', 'off', 8, '%', 'off', 'off' ); if ($opt_errorcode_distribution) { %err_code = geterrcode(); outstart($report_index); if ( $udp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'status-code', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); foreach $code ( sort { $a cmp $b } keys %udp_code ) { push @xaxis, $code; push @yaxis1, $udp_code{$code}; push @yaxis2, $udp_code_size{$code}; push @yaxis3, $udp_code{$code} ? $udp_hit_code{$code} / $udp_code{$code} : 0; push @yaxis4, $udp_code_size{$code} ? $udp_hit_code_size{$code} / $udp_code_size{$code} : 0; writecache( $report_index, $code, $udp_code{$code}, $udp_code_size{$code}, $udp_hit_code{$code}, $udp_hit_code_size{$code}, $udp_code_time{$code}); outline( $report_index, 'toggle', defined($err_code{$code}) ? "$code ($err_code{$code})" : "$code (unknown)", $udp_code{$code}, $udp ? 100 * $udp_code{$code} / $udp : 0, $udp_code{$code} ? 100 * $udp_hit_code{$code} / $udp_code{$code} : 0, $udp_code{$code} ? $udp_code_time{$code} / (1000 * $udp_code{$code}) : 0, kilomegagigatera( $udp_code_size{$code}, $format[5] ), $udp_size ? 100 * $udp_code_size{$code} / $udp_size : 0, $udp_code_size{$code} ? 100 * $udp_hit_code_size{$code} / $udp_code_size{$code} : 0, $udp_code_time{$code} ? $udp_hit_code_size{$code} / (1.024 * $udp_code_time{$code}) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $udp, 100, 100 * $udp_hit / $udp, $udp_time / (1000 * $udp), kilomegagigatera( $udp_size, $format[5] ), 100, $udp_size ? 100 * $udp_hit_size / $udp_size : 0, $udp_time ? $udp_size / ( 1.024 * $udp_time ) : 0); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4 ) if ($outtype_graph and $xaxis[0]); test( $report_index, \%udp_code, \%udp_code_size, \%udp_code_time, 'udp') if $test; my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most frequent response code ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($max, 6) . ' Byte' : $max . ' Requests' ); } } outstop($report_index); # TCP Response code distribution $report_index = 20; @format = ref($formats[$report_index]) ? @{$formats[$report_index]} : ( 46, 9, '%', 'off', 'off', 8, '%', 'off', 'off' ); outstart($report_index); if ( $tcp == 0 ) { outline( $report_index, '', 'no matching requests' ); } else { my (@xaxis, @yaxis1, @yaxis2, @yaxis3, @yaxis4); outimg($report_index) if ($outtype_graph); outheader( $report_index, 'status-code', ' request', '% ', 'hit-%', 'auto', $outtype_unformatted ? " ${opt_U}Byte" : ' Byte', '% ', 'hit-%', 'auto' ); outseperator($report_index); foreach $code ( sort { $a cmp $b } keys %tcp_code ) { push @xaxis, $code; push @yaxis1, $tcp_code{$code}; push @yaxis2, $tcp_code_size{$code}; push @yaxis3, $tcp_code{$code} ? $tcp_hit_code{$code} / $tcp_code{$code} : 0; push @yaxis4, $tcp_code_size{$code} ? $tcp_hit_code_size{$code} / $tcp_code_size{$code} : 0; writecache( $report_index, $code, $tcp_code{$code}, $tcp_code_size{$code}, $tcp_hit_code{$code}, $tcp_hit_code_size{$code}, $tcp_code_time{$code}); outline( $report_index, 'toggle', defined($err_code{$code}) ? "$code ($err_code{$code})" : "$code (unknown)", $tcp_code{$code}, $tcp ? 100 * $tcp_code{$code} / $tcp : 0, $tcp_code{$code} ? 100 * $tcp_hit_code{$code} / $tcp_code{$code} : 0, $tcp_code{$code} ? $tcp_code_time{$code} / (1000 * $tcp_code{$code}) : 0, kilomegagigatera( $tcp_code_size{$code}, $format[5] ), $tcp_size ? 100 * $tcp_code_size{$code} / $tcp_size : 0, $tcp_code_size{$code} ? 100 * $tcp_hit_code_size{$code} / $tcp_code_size{$code} : 0, $tcp_code_time{$code} ? $tcp_hit_code_size{$code} / (1.024 * $tcp_code_time{$code}) : 0 ); } outseperator($report_index); outline( $report_index, '2', 'Sum', $tcp, 100, 100 * $tcp_hit / $tcp, $tcp_time / (1000 * $tcp), kilomegagigatera( $tcp_size, $format[5] ), 100, $tcp_size ? 100 * $tcp_hit_size / $tcp_size : 0, $tcp_time ? $tcp_size / ( 1.024 * $tcp_time ) : 0); outgraph( $report_index, \@graph_legend, $x_scale, \@xaxis, \@yaxis1, \@yaxis2, \@yaxis3, \@yaxis4) if ($outtype_graph and $xaxis[0]); test( $report_index, \%tcp_code, \%tcp_code_size, \%tcp_code_time, 'tcp') if $test; my ($max, $maxi) = ($opt_O) ? maxi(@yaxis2) : maxi(@yaxis1); if (defined($maxi) and defined($xaxis[$maxi])) { $max_value[$report_index] = 'most frequent response code ' . htmlescape($xaxis[$maxi]) . ' ' . ($opt_O ? kilomegagigatera($max, 6) . ' Byte' : $max . ' Requests'); } } outstop($report_index); } close(CACHE); ################################################## # now print it out. $generated = convertdate(time); $out_head = ''; $out_head .= "MIME-Version: 1.0\nContent-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit\n" if ( $outtype_mail and $outtype_html ); $out_head .= 'Subject: ' . ( $host_name ? "$host_name " : '') . "Proxy Report ($loginterval)\n\n" if ($outtype_mail); if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $out_head .= ' ' . ( $host_name ? "$host_name " : '') . 'Proxy Report (' . $loginterval . ') ' . ( $opt_M ? " $opt_M\n" : '' ) . ' ' if ($outtype_html or $outtype_htmlframe); $out_index_head .= ' ' if ($outtype_html or $outtype_htmlembed or $outtype_htmlframe); if ($opt_l) { $out_index_head .= ' '; } $out_index_head .= '
' . $opt_l . '

Proxy Report

' . $host_name . '
Report period: ' . $loginterval . '
Generated at: ' . $generated . '

' if ($outtype_html or $outtype_htmlembed or $outtype_htmlframe); } else { $out_index_head .= "\n${host_name} Proxy-Report\n Report period: $loginterval\nGenerated at: $generated\n"; } @format = (60); if ( ( $invalid / $counter ) > .05 and $counter > 1000 ) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', 'More than 5% discarded logfile-lines.' ); outline( 'E', '', 'Please check your logfile with calamaris -v' ) unless ($opt_v); outstop('E'); } if ( defined($peak_warn) ) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', "$peak_warn" ); outline( 'E', '', 'Please read the README on unsorted input' ); outline( 'E', '', 'To find out which line caused this, try calamaris -v' ) unless ($opt_v); outstop('E'); } if ( defined($cache_warn) ) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', 'with Calamaris V3.x the Cache-File-Format is completely' ); outline( 'E', '', 'changed.' ); outline( 'E', '', '' ); outline( 'E', '', 'To re-use your old Cachefiles you\'ll first have to' ); outline( 'E', '', 'convert them with' ); outline( 'E', '', 'calamaris-cache-convert old.cache new.cache' ); outstop('E'); } if ( $opt_I and $opt_i ) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', 'You have run Calamaris with the -I (Interval) and the -i' ); outline( 'E', '', '(input cache) option. This is normally not useful,' ); outline( 'E', '', 'because the time-interval cannot be applied to' ); outline( 'E', '', 'cache-files.' ); outstop('E'); } if ($opt_ipfilter_exclude) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', 'The following IP addresses have been ignored:' ); foreach ( split ( ':', $opt_ipfilter_exclude ) ) { outline( 'E', '', " $_" ); } outstop('E'); } if ($opt_ipfilter_include) { outstart('E'); outline( 'E', '', '' ); outline( 'E', '', 'Only the following IP addresses have been recognized:' ); foreach ( split ( ':', $opt_ipfilter_include ) ) { outline( 'E', '', " $_" ); } outstop('E'); } if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $out_index_body .= ' '; @reportlist = ($opt_S) ? ( split ( ",", $opt_S ) ) : (0 .. $#reports); foreach ( @reportlist ) { outref($_) if $outref{$_}; } $out_index_body .= '
Table of Content / Overview
'; } if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { my $year = (localtime)[5] + 1900; $out_tail = "
$HTMLCOPYRIGHT"; $out_tail .= ' ' if ($outtype_html or $outtype_htmlframe); } else { $out_tail .= "\n\n"; $out_tail .= "-- \n" if ($outtype_mail); $out_tail .= "Calamaris $VERSION\n$COPYRIGHT\n$LICENSE\n$HOMEPAGE\n"; } my $fh = *STDOUT; if ($opt_output_path or $opt_output_file or $opt_output_file_prefix) { print STDERR "writing output to $path/$file_prefix$filename\n" if $opt_v; if ($outtype_htmlframe) { open( OUT, ">$path/${file_prefix}overview.html" ) or die ("$0: can't open $path/${file_prefix}overview.html for writing: $!\n"); } else { open( OUT, ">$path/$file_prefix$filename" ) or die ("$0: can't open $path/$file_prefix$filename for writing: $!\n"); } $fh = *OUT; } print $fh $out_head; print $fh $out_index_head if $out_index_head; print $fh $out_index_body if $out_index_body; print $fh $out_tail if $outtype_htmlframe; if ($opt_output_path and $outtype_htmlframe) { # print frameset open( FRAME, ">$path/${file_prefix}framehead.html" ) or die ("$0: can't open $path/${file_prefix}framehead.html for writing: $!\n"); $frame = *FRAME; print $frame $out_head; print $frame $out_index_head; print $frame ' '; close($frame); open( FRAME, ">$path/$file_prefix$filename" ) or die ("$0: can't open $path/$file_prefix$filename for writing: $!\n"); $frame = *FRAME; print $frame ' ' . ($host_name ? "$host_name " : '') . 'Proxy Report (' . $loginterval . ') ' . ( $opt_M ? " $opt_M\n" : '' ) . ' <body> <p> Your browser is not able to view frames! Please follow this <a href="' . $file_prefix . 'toc.html">link</a> to get noframes. </p> <hr /> ' . $HTMLCOPYRIGHT . ' </body> '; close($frame); # print table of content open( TOC, ">$path/${file_prefix}toc.html" ) or die ("$0: can't open $path/${file_prefix}toc.html for writing: $!\n"); my $toc = *TOC; print $toc $out_head; outtoc(); print $toc $out_toc; print $toc ' '; close($toc); } @reportlist = ($opt_S) ? ( split ( ",", $opt_S ) ) : (0 .. $#reports); foreach $index ( 'E', @reportlist ) { if ( $outtype_htmlframe ) { open( OUT, ">$path/${file_prefix}$index.html" ) or die ("$0: can't open $path/${file_prefix}$index.html for writing: $!\n"); $fh = *OUT; print $fh $out_head; } if ($outref{$index}) { if ( not defined( $out_body{$index} ) and $index ne 'E' ) { outstart($index); outline( $index, 'no matching requests' ); outstop($index); } print $fh $out_body{$index} if defined( $out_body{$index} ); } if ($outtype_htmlframe) { print $fh $out_tail; close($fh); } } print $fh $out_tail unless $outtype_htmlframe; close($fh); print "$test_string\n" if $test; if ( $opt_generate_index and $opt_output_path and $opt_output_file_prefix) { opendir DIR, $opt_output_path or die("$0: can't opendir $opt_output_path: $!\n"); $pattern = $opt_output_file_prefix . $filename; $pattern =~ s#%h#(\\S+)#; $pattern =~ s#%t#(\\d{14}-\\d{14})#; $pattern =~ s#%%#%#; @files = grep { m#^$pattern# && -f "$opt_output_path/$_" } readdir(DIR); closedir DIR; $filename = 'index.html' unless $opt_output_file; open (INDEX, ">$opt_output_path/$filename") or die ("$0: can't open $opt_output_path/$filename for writing: $!\n"); print INDEX ' Proxy Report Index ' . ( $opt_M ? " $opt_M\n" : '' ) . '

Proxy Report Index

'; foreach (@files) { m#^$pattern#; if ($1 =~ m#\d{14}-\d{14}#) { $timestamp = $1; $host = $2; } else { $host = $1; $timestamp = $2; } ($startdate, $enddate) = split ('-', $timestamp) if $timestamp; print INDEX " \n"; } print INDEX '
Hostname Startdate Enddate
$host $startdate $enddate

' . $HTMLCOPYRIGHT . ' '; close(INDEX); } sub kilomegagigatera { my ($value) = shift (@_); my ($length) = $outtype_unformatted ? 999 : shift (@_); if ( $value > 10**( $length + 8 ) or $opt_U eq 'T' ) { return sprintf( '%d%s', int( ( $value / 1024**4 ) + .5 ), $outtype_unformatted ? '' : 'T' ); } elsif ( $value > 10**( $length + 5 ) or $opt_U eq 'G' ) { return sprintf( '%d%s', int( ( $value / 1024**3 ) + .5 ), $outtype_unformatted ? '' : 'G' ); } elsif ( $value > 10**( $length + 2 ) or $opt_U eq 'M' ) { return sprintf( '%d%s', int( ( $value / 1024**2 ) + .5 ), $outtype_unformatted ? '' : 'M' ); } elsif ( $value > 10**($length) or $opt_U eq 'K' ) { return sprintf( '%d%s', int( ( $value / 1024 ) + .5 ), $outtype_unformatted ? '' : 'K' ); } else { return $value; } } sub removezerotimes { my ($size) = shift (@_); my ($time) = shift (@_); if ( $size == 0 or $time == 0 ) { return '-'; } else { return $size / ( 1.024 * $time ); } } sub getfqdn { my ($host) = @_; unless ($hostcache{$host}) { my $sockaddr; if ( $host =~ m#^(::ffff:)?(([0-9][0-9]{0,2}\.){3}[0-9][0-9]{0,2})$#io ) { $sockaddr = sockaddr_in(0 , inet_pton(AF_INET, $2)); } elsif ( $host =~ m#^([0-9a-f:]+)$#io ) { $sockaddr = sockaddr_in6(0, inet_pton(AF_INET6, $1)); } if ( $sockaddr ) { $hostcache{$host} = (getnameinfo($sockaddr, 0, 0))[1]; $hostcache{$host} = $host unless $hostcache{$host}; } else { $hostcache{$host} = $host; } } return $hostcache{$host}; } sub addtonam { my ($address) = shift (@_); my (@octets); my ( $host_name, $aliases, $type, $len, $addr ); my ($ip_number); @octets = split '\.', $address; if ( $#octets != 3 ) { undef; } $ip = pack( "CCCC", @octets[ 0 .. 3 ] ); ( $host_name, $aliases, $type, $len, $addr ) = gethostbyaddr( $ip, 2 ); if ($host_name) { $host_name; } else { $address; } } sub convertdate { my $date = shift (@_); my $type = shift (@_); if ($date) { my ( $sec, $min, $hour, $mday, $mon, $year ) = ( localtime($date) )[ 0, 1, 2, 3, 4, 5, 6 ]; my $month = $months[$mon]; $year += 1900; my $retdate = $type ? sprintf( "%04d%02d%02d%02d%02d%02d\n", $year, $mon+1, $mday, $hour, $min, $sec ) : sprintf( "%02d.%s %02d %02d:%02d:%02d\n", $mday, $month, substr( $year, -2 ), $hour, $min, $sec ); chomp($retdate); return $retdate; } else { return ' '; } } sub outtoc { $out_toc .= " "; @reportlist = ($opt_S) ? ( split ( ",", $opt_S ) ) : (0 .. $#reports); foreach ( @reportlist ) { $out_toc .= " "; } $out_toc .= '

Table of Content

Overview
Warnings
$reports[$_]
'; } sub outref { my $name = shift (@_); $link = ( $outtype_htmlframe ) ? "${file_prefix}${name}.html" : "#${name}"; if (defined($max_value[$name])) { $out_index_body .= " $reports[$name] $max_value[$name] "; } else { $out_index_body .= " $reports[$name] - - no requests found "; } } sub outstart { my $index = shift (@_); if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $out_body{$index} .= '
'; if ( $index eq 'E' ) { $out_body{$index} .= ' '; } else { $out_body{$index} .= '
'; } } else { $out_body{$index} .= "\n# $reports[$index]\n" unless ( $index eq 'E' ); } } sub outheader { my $index = shift (@_); my $print; my $no = 0; $out_body{$index} .= "\n " if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ); foreach (@_) { $p = $_; $p = 'kB/sec' if ($format[$no] eq 'kbps' and $p eq 'auto'); $p = 'sec/kB' if ($format[$no] eq 'spkb' and $p eq 'auto'); $p = 'req/sec' if ($format[$no] eq 'rps' and $p eq 'auto'); $p = 'sec/req' if ($format[$no] eq 'spr' and $p eq 'auto'); $p = 'Byte/sec' if ($format[$no] eq 'bps' and $p eq 'auto'); $p = 'sec/Byte' if ($format[$no] eq 'spb' and $p eq 'auto'); $p = 'req/msec' if ($format[$no] eq 'rpms' and $p eq 'auto'); $p = 'msec/req' if ($format[$no] eq 'mspr' and $p eq 'auto'); if ($format[$no] eq 'off') { # do nothing } elsif ($outtype_unformatted) { $out_body{$index} .= "$p "; } elsif ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $p =~ s# +# #go; $p =~ s#(^ | $)##go; $p = ' ' if ( $p eq '' ); $out_body{$index} .= " "; } elsif ( $format[$no] eq '%' ) { $out_body{$index} .= ' ' x ( ( (6 - length($p)) > 0 ) ? (6 - length($p)) : 0 ) . substr( $p, 0, 6 ) . ' '; } elsif ( $format[$no] =~ m/[bps|spb|spkb|rps|rpms|spr]$/ ) { $out_body{$index} .= substr( $p, 0, 7 ) . ' ' x ( ( (7 - length($p)) > 0) ? (7 - length($p)) : 0 ) . ' '; } else { $out_body{$index} .= substr( $p, 0, $format[$no] ) . ' ' x ( ( ($format[$no] - length($p)) > 0) ? ($format[$no] - length($p)) : 0 ) . ' '; } $no++; } $out_body{$index} .= "\n"; $out_body{$index} .= ' ' if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ); } sub outimg { my $index = shift; $out_body{$index} .= " "; } sub outgraph { my $index = shift; my $legend_ref = shift; my $max_x_data = shift; my $xaxis_ref = shift; my $yaxis1_ref = shift; my $yaxis2_ref = shift; my $yaxis3_ref = shift; my $yaxis4_ref = shift; my ($factor0, $factor1, $unit0, $unit1, $min_x, $max_x); if ($max_x_data < 0) { # show last $max_x_data Values $min_x = ($#{$xaxis_ref} + $max_x_data < 0) ? 0 : $#{$xaxis_ref} + $max_x_data + 1; $max_x = $#{$xaxis_ref}; } else { # show first $max_x_data Values $min_x = 0; $max_x = ($#{$xaxis_ref} > $max_x_data) ? $max_x_data : $#{$xaxis_ref}; } my $graph = calamaris::calBars3d->new($width, int($width/3*2)); # check image-type if (! $verified) { @img_format = $graph->export_format; foreach ( @img_format ) { $format{$_} = 1; } if ( ! defined($format{$opt_image_type}) ) { # Image type not supported print STDERR "$0: $opt_image_type is not supported by GD::Graph!\n Please use one of the supported image types: @img_format \n\n"; exit(1); } $verified = 1; # don't do it on every 'sub outgraph' call } # 1 axis graph my @data = ([@$xaxis_ref[$min_x..$max_x]], [@$yaxis1_ref[$min_x..$max_x]]); ($factor0, $unit0) = getfactor(max(@$yaxis1_ref[$min_x..$max_x]),9); $yaxis1_ref = reformatarray($factor0, $yaxis1_ref) if ($factor0 > 1); my %graph_label = (x_label => '', y_label => "$unit0 ${$legend_ref}[0]", title => '', two_axes => '0', x_labels_vertical => '1', y_long_ticks => '1', y_tick_number => '5', x_ticks => '0', box_axis => '0', show_values => '0', values_vertical => '0', bar_spacing => '6', set_spacing => '0', shadowclr => 'lgray', shadow_depth => '0', boxclr => "$bg_color", fgclr => "$text_color", labelclr => "$text_color", axislabelclr => "$text_color", legendclr => "$text_color", valuesclr => "$text_color", textclr => "$text_color" ); $graph->set(%graph_label) or die $graph->error; # 2 axis graph if (scalar(@$legend_ref) > 1) { ($factor1, $unit1) = getfactor(max(@$yaxis2_ref[$min_x..$max_x]),5); $yaxis2_ref = reformatarray($factor1, $yaxis2_ref) if ($factor1 > 1); push @data, [@$yaxis2_ref[$min_x..$max_x]]; push @data, [@$yaxis3_ref[$min_x..$max_x]] if ref($yaxis3_ref); push @data, [@$yaxis4_ref[$min_x..$max_x]] if ref($yaxis4_ref); %graph_label = ( y1_label => "$unit0 ${$legend_ref}[0]", y2_label => "$unit1 ${$legend_ref}[1]", two_axes => '1', bar_spacing => '0', set_spacing => '6', ); } $graph->set(%graph_label) or die $graph->error; $graph->set_text_clr("$text_color"); $graph->set_legend(@$legend_ref); $graph->set( dclrs => [$column2_color, $column1_color] ); open(IMG, ">$path/${file_prefix}${index}.${opt_image_type}") or die ("$0: can't open $path/${file_prefix}${index}.${opt_image_type} for writing: $!\n"); binmode IMG; print IMG $graph->plot(\@data)->$opt_image_type; close(IMG); } sub maxi { my $max = -10e10; # an absolute small number my @array = @_; for ( $i = 0; $i <= $#array; $i++ ) { if ($array[$i] > $max ) { $max = $array[$i]; $maxi = $i; } } return $max, $maxi; } sub max { my $max = -10e10; # an absolute small number foreach (@_) { $max = $_ if $_ > $max } return $max; } sub reformatarray { my $factor = shift; my $array_ref = shift; my @array; foreach ( @$array_ref ) { push @array, $_/$factor } return \@array; } sub getfactor { my ($value) = shift (@_); my ($length) = $outtype_unformatted ? 999 : shift (@_); my ($factor, $unit); if ( $value > 10**( $length + 8 ) or $opt_U eq 'T' ) { $factor = 1024**4; $unit = 'Tera'; } elsif ( $value > 10**( $length + 5 ) or $opt_U eq 'G' ) { $factor = 1024**3; $unit = 'Giga'; } elsif ( $value > 10**( $length + 2 ) or $opt_U eq 'M' ) { $factor = 1024**2; $unit = 'Mega'; } elsif ( $value > 10**($length) or $opt_U eq 'K' ) { $factor = 1024; $unit = 'Kilo'; } else { $factor = 1; $unit = ''; } return $factor, $unit; } sub outline { my $index = shift (@_); my $linecolor = shift (@_); my $print; my $no = 0; $out_body{$index} .= "\n " if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ); $color = 0 unless $linecolor; if ($linecolor eq 'toggle') { $color = $color ? 0 : 1; } elsif ($linecolor) { $color = $linecolor; } foreach (@_) { $print = $_; if ($format[$no] eq 'off') { # do nothing } elsif ($outtype_unformatted) { $out_body{$index} .= "$print "; } elsif ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $print =~ s# +# #go; $print =~ s# $##go; $print =~ s#<#\<\;#go; $print =~ s#>#\>\;#go; if ( $no == 0 ) { unless ( $print =~ s#^ ##go ) { $out_body{$index} .= " "; } else { $out_body{$index} .= " "; } } elsif ( $format[$no] eq '%' ) { if ( $print eq '' or $print eq '-' ) { $out_body{$index} .= " "; } else { $out_body{$index} .= sprintf( ' ', $color, $print ); } } elsif ( $format[$no] =~ m/[bps|spb|spkb|rps|rpms|spr]$/ ) { my $factor = 1; $factor = 1000 if ($format[$no] =~ m#^rpms$# or $format[$no] =~ m#^mspr$#); $factor = 1024 if ($format[$no] =~ m#^bps$# or $format[$no] =~ m#^spb$#); if ( $print eq '' or $print eq '-' ) { $out_body{$index} .= " "; # kByte/sec } elsif ($format[$no] =~ m/bps/) { $out_body{$index} .= sprintf( ' ', $color, $print * $factor ); # sec/kByte } elsif ($format[$no] =~ m/spkb/ or $format[$no] =~ m/spb/) { $out_body{$index} .= sprintf( ' ', $color, 1 / ($factor * $print) ); # req/[m]sec } elsif ($format[$no] =~ m/rps/ or $format[$no] =~ m/rpms/) { $out_body{$index} .= sprintf( ' ', $color, 1 / ($print * $factor) ); # [m]sec/req } elsif ($format[$no] =~ m/spr/) { $out_body{$index} .= sprintf( ' ', $color, $print * $factor ); # % } else { $out_body{$index} .= sprintf( ' ', $color, $print ); } } elsif ( $no == 1 and $print !~ m#^[\d\.e\-\+]+$#o ) { $out_body{$index} .= sprintf( ' ', $color, $print ); } elsif ( $no == 1 or $print =~ m#^[\d\.e\-\+]+$#o ) { $out_body{$index} .= sprintf( ' ', $color, $print ); } else { if ($print) { $out_body{$index} .= " "; } else { $out_body{$index} .= " "; } } } else { if ( $no == 0 ) { if ( length($print) > $format[$no] ) { $out_body{$index} .= $print . "\n" . ' ' x ( ($format[$no] > 0) ? $format[$no] : 0) . ' '; } else { $out_body{$index} .= $print . ' ' x ( ( ($format[$no] - length($print)) > 0) ? ($format[$no] - length($print)) : 0 ) . ' '; } } elsif ( $format[$no] eq '10%' ) { if ( $print eq '' or $print eq '-' ) { $out_body{$index} .= ' ' x 11; } else { $out_body{$index} .= sprintf( '%10.2f ', $print ); } } elsif ( $format[$no] eq '%' ) { if ( $print eq '' or $print eq '-' ) { $out_body{$index} .= ' ' x 7; } else { $out_body{$index} .= sprintf( '%6.2f ', $print ); } } elsif ( $format[$no] =~ m/[bps|spb|spkb|rps|rpms|spr]$/ ) { my $factor = 1; $factor = 1000 if ($format[$no] =~ m#^rpms$# or $format[$no] =~ m#^mspr$#); $factor = 1024 if ($format[$no] =~ m#^bps$# or $format[$no] =~ m#^spb$#); if ( $print eq '-' ) { $out_body{$index} .= ' - '; # [k]Byte/sec } elsif ($format[$no] =~ m/bps/) { if ( $print >= 10000 ) { $out_body{$index} .= sprintf( '%7.0f ', $factor * $print ); } else { $out_body{$index} .= sprintf( '%7.2f ', $factor * $print ); } # sec/[k]Byte } elsif ($format[$no] =~ m/spkb/ or $format[$no] =~ m/spb/) { if ( $print >= 1000 ) { $out_body{$index} .= sprintf( '%7.0f ', 1 / ($factor * $print) ); } else { $out_body{$index} .= sprintf( '%7.3f ', 1 / ($factor * $print) ); } # req/[m]sec } elsif ($format[$no] =~ m/rps/ or $format[$no] =~ m/rpms/) { if ( $print >= 10000 ) { $out_body{$index} .= sprintf( '%7.0f ', 1 / ($factor * $print) ); } else { $out_body{$index} .= sprintf( '%7.2f ', 1 / ($factor * $print) ); } # [m]sec/req } elsif ($format[$no] =~ m/spr/) { if ( $print >= 10000 ) { $out_body{$index} .= sprintf( '%7.0f ', $factor * $print ); } else { $out_body{$index} .= sprintf( '%7.2f ', $factor * $print ); } } } else { $print = sprintf( '%d', $print + .5 ) if $print =~ m#^[\d\.e\-\+]+$#o; $out_body{$index} .= ' ' x ( ( ($format[$no] - length($print)) > 0) ? ($format[$no] - length($print)) : 0 ) . substr( $print, 0, $format[$no] ) . ' '; } } $no++; } $out_body{$index} .= "\n"; $out_body{$index} .= ' ' if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe); } sub outseperator { my $index = shift (@_); my $print; $out_body{$index} .= "\n " if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ); foreach $print (@format) { next if $print eq 'off'; if ($outtype_unformatted) { $out_body{$index} .= "--- "; } elsif ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $out_body{$index} .= ' '; } elsif ( $print eq '10%' ) { $out_body{$index} .= '-' x 10 . ' '; } elsif ( $print eq '%' ) { $out_body{$index} .= '-' x 6 . ' '; } elsif ( $print =~ m/[bps|spb|spkb|rps|rpms|spr]$/ ) { $out_body{$index} .= '-' x 7 . ' '; } else { $out_body{$index} .= '-' x ( ($print > 0) ? $print : 0) . ' '; } } $out_body{$index} .= "\n"; $out_body{$index} .= ' ' if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ); } sub outstop { my $index = shift (@_); my $link = ($outtype_htmlframe) ? "$file_prefix$filename" : '#top'; if ( $outtype_html or $outtype_htmlembed or $outtype_htmlframe ) { $out_body{$index} .= '
' . $reports[$index] . '
$p
\"Graphic:
$print   $print   %.2f   %.2f %.2f %.2f %.2f %.2f %s %d $print  
'; $out_body{$index} .= '

Back to Top

' unless $outtype_htmlframe; } else { $out_body{$index} .= "\n"; } } sub writecache { print CACHE join ( 'µ', @_ ) . "\n" if $opt_o; } sub geterrcode { my %err_code; $err_code{'000'} = 'Used mostly with UDP traffic'; $err_code{'100'} = 'Continue'; $err_code{'101'} = 'Switching Protocols'; $err_code{'102'} = 'Processing'; $err_code{'200'} = 'OK'; $err_code{'201'} = 'Created'; $err_code{'202'} = 'Accepted'; $err_code{'203'} = 'Non-Authoritative Information'; $err_code{'204'} = 'No Content'; $err_code{'205'} = 'Reset Content'; $err_code{'206'} = 'Partial Content'; $err_code{'208'} = 'Already Reported'; $err_code{'226'} = 'IM Used'; $err_code{'300'} = 'Multiple Choices'; $err_code{'301'} = 'Moved Permanently'; $err_code{'302'} = 'Moved Temporarily'; $err_code{'303'} = 'See Other'; $err_code{'304'} = 'Not Modified'; $err_code{'305'} = 'Use Proxy'; $err_code{'306'} = 'Switch Proxy'; $err_code{'307'} = 'Temporary Redirect'; $err_code{'307'} = 'Permanent Redirect'; $err_code{'308'} = 'Resume Incomplete'; $err_code{'400'} = 'Bad Request'; $err_code{'401'} = 'Unauthorized'; $err_code{'402'} = 'Payment Required'; $err_code{'403'} = 'Forbidden'; $err_code{'404'} = 'Not Found'; $err_code{'405'} = 'Method Not Allowed'; $err_code{'406'} = 'Not Acceptable'; $err_code{'407'} = 'Proxy Authentication Required'; $err_code{'408'} = 'Request Timeout'; $err_code{'409'} = 'Conflict'; $err_code{'410'} = 'Gone'; $err_code{'411'} = 'Length Required'; $err_code{'412'} = 'Precondition Failed'; $err_code{'413'} = 'Payload Too Large'; $err_code{'414'} = 'Request URI Too Large'; $err_code{'415'} = 'Unsupported Media Type'; $err_code{'416'} = 'Request Range Not Satisfiable'; $err_code{'417'} = 'Expectation Failed'; $err_code{'418'} = 'I\'m a teapot'; $err_code{'419'} = 'Authentication Timeout'; $err_code{'421'} = 'Misdirected Request'; $err_code{'422'} = 'Unprocessable Entity'; $err_code{'423'} = 'Locked'; $err_code{'424'} = 'Failed Dependency'; $err_code{'428'} = 'Precondition Required'; $err_code{'429'} = 'Too Many Requests'; $err_code{'431'} = 'Request Header Fields Too Large'; $err_code{'433'} = 'Unprocessable Entity'; $err_code{'451'} = 'Unavailable For Legal Reasons'; $err_code{'500'} = 'Internal Server Error'; $err_code{'501'} = 'Not Implemented'; $err_code{'502'} = 'Bad Gateway'; $err_code{'503'} = 'Service Unavailable'; $err_code{'504'} = 'Gateway Timeout'; $err_code{'505'} = 'HTTP Version Not Supported'; $err_code{'506'} = 'Variant Also Negotiates'; $err_code{'507'} = 'Insufficient Storage'; $err_code{'508'} = 'Loop Detected'; $err_code{'510'} = 'Not Extended'; $err_code{'511'} = 'Network Authentication Required'; $err_code{'522'} = 'Connection timed out (unofficial)'; $err_code{'600'} = 'Squid header parsing error'; return %err_code; } sub readconfig { # Default values undef($benchmark); undef($cache_input_file); undef($cache_output_file); undef($domain_report); undef($domain_report_limit); undef($domain_report_n_level); undef($errorcode_distribution_report); undef($generate_index); undef($hostname); undef($input_format); undef($ipfilter_exclude); undef($ipfilter_include); undef($logo); undef($meta); undef($no_input); undef($object_freshness_report); undef($output_file); undef($output_file_prefix); undef($output_format); undef($output_path); undef($peak_report); undef($performance_report); undef($performance_report_adjust); undef($requester_report); undef($requester_report_no_dns_lookup); undef($requester_report_use_user_info); undef($requester_report_with_targets); undef($response_time_report); undef($show_reports); undef($size_distribution_report); undef($sort_order); undef($status_report); undef($time_interval); undef($type_report); undef($type_report_ignore_case); undef($unit); undef($verbose); @response_time_report_interval = qw( 0.001 0.01 0.02 0.05 0.1 0.2 0.5 1 2 5 10 20 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1000000 1e10 ); $response_time_limit = $response_time_report_interval[$#response_time_report_interval]; # show $show_other_tcp_urlhost = 1; $show_other_tcp_urltld = 1; $show_other_tcp_content = 1; $show_other_tcp_urlext = 1; $show_other_udp_requester = 1; $show_other_tcp_requester = 1; # GRAPH SECTION $column1_color = '#6699cc'; $column2_color = '#ff9900'; $text_color = '#222266'; $bg_color = '#ffffcc'; $x_scale = 30; $image_type = 'png'; $width = 600; $test = 0; $verified = 0; @graph_legend = ('Requests', 'Byte', 'Request Hit Rate', 'Byte Hit Rate'); # HTML SECTION if ($opt_config_file) { my $file = $opt_config_file; my $return; unless ($return = do $file) { warn "$0: Parsing of $file failed: $@" if $@; warn "$0: do on $file failed: $!" unless defined $return; warn "$0: couldn't execute $file" unless $return; } } $opt_b = $benchmark unless $opt_b; $opt_i = $cache_input_file unless $opt_i; $opt_o = $cache_output_file unless $opt_o; $opt_d = $domain_report unless $opt_d; $opt_domain_report_limit = $domain_report_limit unless $opt_domain_report_limit; $opt_N = $domain_report_n_level unless $opt_N; $opt_errorcode_distribution = $errorcode_distribution_report unless $opt_errorcode_distribution; $opt_H = $hostname unless $opt_H; $opt_c = $type_report_ignore_case unless $opt_c; $opt_f = $input_format unless $opt_f; $opt_image_type = $image_type unless $opt_image_type; $opt_generate_index = $generate_index unless $opt_generate_index; $opt_ipfilter_exclude = $ipfilter_exclude unless $opt_ipfilter_exclude; $opt_ipfilter_include = $ipfilter_include unless $opt_ipfilter_include; $opt_l = $logo unless $opt_l; $opt_M = $meta unless $opt_M; $opt_z = $no_input unless $opt_z; $opt_output_file = $output_file unless $opt_output_file; $opt_output_file_prefix = $output_file_prefix unless $opt_output_file_prefix; $opt_F = $output_format unless $opt_F; $opt_output_path = $output_path unless $opt_output_path; $opt_p = $peak_report unless $opt_p; $opt_P = $performance_report unless $opt_P; $opt_T = $performance_report_adjust unless $opt_T; $opt_r = $requester_report unless $opt_r; $opt_n = $requester_report_no_dns_lookup unless $opt_n; $opt_u = $requester_report_use_user_info unless $opt_u; $opt_R = $requester_report_with_targets unless $opt_R; $opt_response_time = $response_time_report unless $opt_response_time; undef($opt_response_time) unless scalar(@response_time_report_interval); $opt_S = $show_reports unless $opt_S; $opt_D = $size_distribution_report unless $opt_D; $opt_O = $sort_order unless $opt_O; $opt_s = $status_report unless $opt_s; $opt_I = $time_interval unless $opt_I; $opt_t = $type_report unless $opt_t; $opt_U = $unit unless $opt_U; $opt_v = $verbose unless $opt_v; # -M: if it's a file, read it and store it in $opt_M if ( defined($opt_M) and $opt_M !~ /\n/ and -e $opt_M ) { open(IN, "<$opt_M") or die "$0: Couldn't open file $opt_M for reading: $!\n"; $opt_M = ''; while () { $opt_M .= $_ } } # -l: if it's a file, read it and store it in $opt_l if ( defined($opt_l) and $opt_l !~ /\n/ and -e $opt_l ) { open(IN, "<$opt_l") or die "$0: Couldn't open file $opt_l for reading: $!\n"; $opt_l = ''; while () { $opt_l .= $_ } } if ( $opt_b and $opt_b < 1 ) { print STDERR "$0: wrong value at -b -option: \"$opt_b\"\n\n"; $usage_err = 1; } else { $| = 1; } if ($opt_U) { unless ( $opt_U =~ m#^[KMGT]$# ) { print STDERR "$0: wrong value at -U -option: \"$opt_U\"\n\n"; $usage_err = 1; } } else { $opt_U = ''; } if ($opt_D) { if ( $opt_D <= 1 ) { print STDERR "$0: wrong value at -D -option: \"$opt_D\"\n\n"; $usage_err = 1; } } if ($opt_H) { if ( $opt_H eq '1' or $opt_H eq 'lookup' ) { use Sys::Hostname; $host_name = hostname(); } else { $host_name = $opt_H; } } else { $host_name = ''; } if ($opt_ipfilter_exclude or $opt_ipfilter_include) { unless (eval "require NetAddr::IP") { print STDERR "$0: You need package NetAddr::IP for ipfilter-*-Option, I searched it in @INC: $!\n\n"; $usage_err = 1; } } if ( $opt_N and $opt_N != -1 and $opt_N < 2 ) { print STDERR "$0: wrong value at -N -option: \"$opt_N\"\n\n"; $usage_err = 1; } if ($opt_I) { use Time::Local; ( $interval_begin, $interval_end ) = split ( '-', $opt_I ); if ( $interval_begin =~ m#^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$# ) { $interval_begin = timelocal( $6, $5, $4, $3, $2 - 1, $1 - 1900 ); } elsif ( $interval_begin eq '' ) { $interval_begin = 0; } else { print STDERR "$0: wrong value at -I -option: \"$opt_I\"\n\n"; $usage_err = 1; } if ( $interval_end =~ m#^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$# ) { $interval_end = timelocal( $6, $5, $4, $3, $2 - 1, $1 - 1900 ); } elsif ( $interval_end eq '' ) { $interval_end = 9999999999; } else { print STDERR "$0: wrong value at -I -option: \"$opt_I\"\n\n"; $usage_err = 1; } if ($interval_begin > $interval_end) { print STDERR "$0: wrong value at -I -option: \"$opt_I\". Interval begin newer than interval end!\n\n"; $usage_err = 1; } } $path = $opt_output_path ? $opt_output_path : '.'; if (-d "$path") { unless (-w "$path") { print STDERR "$0: directory $path not writable: $!\n\n"; $usage_err = 1; } } else { use File::Path qw(make_path); make_path( "$path", {error => \my $err} ); if (@err) { print STDERR "$0: can't create directory $path: @err\n\n"; $usage_err = 1; } } $filename = $opt_output_file ? $opt_output_file : 'calamaris.txt'; $file_prefix = $opt_output_file_prefix ? $opt_output_file_prefix : ''; if ($opt_F) { $outtype_htmlembed = $outtype_htmlframe = $outtype_html = 0; foreach $output ( split ( /\s*,\s*/, $opt_F ) ) { if ($output eq 'mail') { $outtype_mail = 1; } elsif ($output eq 'html') { $outtype_html = 1; } elsif ($output eq 'html-embed') { $outtype_htmlembed = 1; } elsif ($output eq 'html-frame') { $outtype_htmlframe = 1; } elsif ( $output eq 'graph' ) { unless (eval "require GD::Graph") { print STDERR "$0: You need package GD::Graph for -F 'graph'-Option, I searched it in @INC: $!\n\n"; $usage_err = 1; } use FindBin; use lib "$FindBin::Bin/.."; unless (eval "require calamaris::calBars3d") { print STDERR "$0: You need package calamaris::calBars3d for -F 'graph'-Option, I searched it in @INC: $!\n\n"; $usage_err = 1; } $outtype_graph = 1; } elsif ( $output eq 'unformatted' ) { $outtype_unformatted = 1; } else { print STDERR "$0: unknown output-format: $output\n\n"; $usage_err = 1; } } if ( ( $outtype_htmlembed + $outtype_htmlframe + $outtype_html ) > 1 ) { print STDERR "$0: only one of 'html', 'html-embed' or 'html-frame' can be used: $opt_F\n\n"; $usage_err = 1; } if ( $outtype_mail and ($outtype_htmlembed or $outtype_htmlframe or $outtype_graph) ) { print STDERR "$0: 'mail' together with 'html-embed', 'html-frame' or 'graph' won't work: $opt_F\n\n"; $usage_err = 1; } print STDERR "$0: please use --output-path /path, when using -F 'graph'\n\n" if ( $outtype_graph and not $opt_output_path ); if ($outtype_graph and not ($outtype_html or $outtype_htmlembed or $outtype_htmlframe) ) { print STDERR "$0: -F 'graph' is kinda useless without 'html', 'html-embed' or 'html-frame'.\n\n"; } } if ( $opt_generate_index and not $opt_output_path and not $opt_output_file_prefix) { print STDERR "$0: --generate-index needs --output-path and --output-file-prefix\n"; } if ($outtype_htmlembed or $outtype_html or $outtype_htmlframe) { $filename = $opt_output_file ? $opt_output_file : 'index.html'; } $sortorder = $opt_O ? '_size' : ''; if ($opt_a) { $opt_response_time = 1; $opt_errorcode_distribution = 1; $opt_D = 10 unless $opt_D; $opt_P = 60 unless $opt_P; $opt_d = 20 unless $opt_d; $opt_r = 20 unless $opt_r; $opt_s = 1; $opt_t = 20 unless $opt_t; } $opt_domain_report_limit = 0 unless $opt_domain_report_limit; $opt_N = 2 unless $opt_N; $opt_T = 0 unless $opt_T; $opt_r = $opt_R unless $opt_r; if ($object_freshness_report) { $opt_t = 20 unless $opt_t; } $P = $opt_P ? "$opt_P minute" : '60 minute'; $P = $opt_P/60 . ' hour' if ( defined($opt_P) and ($opt_P % 60) == 0 and $opt_P >= 60 ); $P = $opt_P/1440 . ' day' if ( defined($opt_P) and ($opt_P % 1440) == 0 and $opt_P >= 1440 ); if ( $opt_N == -1 or $opt_N > 2 ) { if ( $opt_N == 3 ) { $N = '3rd'; } elsif ( $opt_N == -1 ) { $N = 'all'; } else { $N = $opt_N . 'th'; } } else { $N = '2nd'; } $outref{E} = 1; $outref{0} = 1; $outref{1} = ($opt_p) ? 1 : 0; $outref{2} = ($opt_p and $opt_p eq 'new') ? 1 : 0; $outref{3} = 1; $outref{4} = 1; $outref{5} = 1; $outref{6} = 1; $outref{7} = 1; $outref{8} = ($opt_d) ? 1 : 0; $outref{9} = ($opt_d) ? 1 : 0; $outref{10} = ($opt_t) ? 1 : 0; $outref{11} = ($opt_t) ? 1 : 0; $outref{12} = ($opt_t) ? 1 : 0; $outref{13} = ($opt_r) ? 1 : 0; $outref{14} = ($opt_r) ? 1 : 0; $outref{15} = ($opt_D) ? 1 : 0; $outref{16} = ($opt_P) ? 1 : 0; $outref{17} = ($opt_response_time) ? 1 : 0; $outref{18} = ($opt_response_time) ? 1 : 0; $outref{19} = ($opt_errorcode_distribution) ? 1 : 0; $outref{20} = ($opt_errorcode_distribution) ? 1 : 0; @reports = ( 'Summary', 'Incoming request peak per protocol', 'Incoming transfer volume peak per protocol', 'Incoming requests by method', 'Incoming UDP-requests by status', 'Incoming TCP-requests by status', 'Outgoing requests by status', 'Outgoing requests by destination', "Request-destinations by ${N}-level-domain", 'Request-destinations by toplevel-domain', 'TCP-Request-protocol', 'Requested content-type', 'Requested extensions', 'Incoming UDP-requests by host', 'Incoming TCP-requests by host', 'Size Distribution Diagram', "Performance in $P steps", 'UDP-Request duration distribution in msec', 'TCP-Request duration distribution in msec', 'UDP Response code distribution', 'TCP Response code distribution' ); $LICENSE = 'Calamaris comes with ABSOLUTELY NO WARRANTY. It is free software, and you are welcome to redistribute it under certain conditions. See source for details.'; $COPYRIGHT = 'Copyright (C) 1997-2006, 2013, 2015, 2017, 2021 Cord Beermann. Authors: Cord Beermann and Michael Pophal.'; $HOMEPAGE = 'https://Calamaris.Cord.de/'; $HTMLCOPYRIGHT = '
Calamaris ' . $VERSION . ', Copyright © 1997-2006, 2013, 2015, 2017, 2021 Cord Beermann. Authors: Cord Beermann and Michael Pophal.

' . $LICENSE . '

'; $USAGE = ' Usage: cat log | ' . $0 . ' --config-file /path/to/calamaris.conf [switches] or cat log | ' . $0 . ' [switches] --config-file file Not all reports and modification can be made through command-line-switches. To use all options of Calamaris you\'ll have to use the configuration file. see the manpage for the configuration-file syntax. Reports: --all-useful-reports|-a extracts all useful reports available, --all-useful-reports equals --size-distribution-report 10 \ --domain-report 20 \ --performance-report 60 \ --requester-report 20 \ --status-report \ --type-report 20 \ --response-time-report \ --errorcode-distribution-report --domain-report|-d n show n Top-level and n second-level destinations, -1 = unlimited --domain-report-limit n limit display of domains to those with n requests or more. --domain-report-n-level|-N n change all 2nd-level-reports to n-level-reports. n can be any number from 2 up. -1 means full report. --errorcode-distribution-report shows the Response code distribution over all objects --peak-report|-p type measure peak requests old = make old request-peak mesurement new = make new request&byte-peak measurement (both slow Calamaris significantly down.) --performance-report|-P n show throughput data for every n minutes --performance-report-adjust|-T n adjust the Performance-Report in minutes --requester-report|-r n show n Requesters, -1 = unlimited --requester-report-no-dns-lookup|-n don\'t look IP-Numbers up --requester-report-use-user-info|-u use ident information if available (*) --requester-report-with-targets|-R n show n targets for every Requester, -1 = unlimited), implies --requester-report (*) --response-time-report shows the time distribution over all objects --size-distribution-report|-D n shows size-based distribution of requested objects, smaller numbers result in more verbose reports. choose 2, 10 or 100 for useful output. (You can also play with this ;-)) --status-report|-s show verbose status reports --type-report|-t n show n content-type, n extensions and requested protocols, -1 = unlimited --type-report-ignore-case|-c switch to case-insensitive (useful for extensions-report) More reports and report-modifications are available via the configuration-file. see manpage. Input: --input-format|-f type sets the type of input logfiles auto = tries to guess the input format (This is the Default) squid = Native-Logfile derived from Squid V1.1.beta26-V2.x squid-extended = Native-Logfile with log_mime_hdrs enabled derived from Squid V1.1.beta26-V2.x (*) or Cisco Content Engines (*) or Squid with SmartFilter-patch (*) squid-old = Native-Logfile derived from Squid V1.1.alpha1-V1.1.beta25 nc = Squid-style Logfiles derived from NetCache V?? (<5.x) its = Logfiles derived from Inktomi Traffic Server elff = Extended Logfile Format (i.e Compaq Tasksmart, Novell Internet Caching System, NetCache 5.x, BlueCoat) nse = Netscape Extended-1/2 Logfile Format --ipfilter-exclude IP/range all IPs are analyzed, except IP/range. (*) Format: 1.1.1.1/32:1.1.2.0/24 1.1.1.1/255.255.255.255:1.1.2.0/255.255.255.0 IP list separated by \':\' This switch needs the perl Module NetAddr::IP. --ipfilter-include IP/range no IPs are analyzed, except IP/range. (*) Format: see --ipfilter-exclude --no-input|-z no input via stdin --time-interval|-I t-t defines which time-interval should be parsed. t has to be the format yyyymmddhhmmss (localtime). omitting the beginning or ending is allowed. Output: (Default is plain formatted text) --hostname|-H name a name for the Output, -H \'lookup\' issues a lookup for the current host --image-type Sets the image type to gif, png, jpeg, gd or gd2. Only usefull when --output-format graph is set. The supported images types are dependend on your GD::Graph installation. --logo|-l string add this string to the head of the report. works only in combination with --output-format html or html-frame --meta|-M string/file includes the given strings in html-. If a file is given, the file is included in html-. works only in combination with --output-format html or html-frame --output-format|-F type output format (comma-seperated list) mail = mail format, disables graph output. html = HTML format html-frame = HTML frames, disables mail output. html-embed = HTML format without HTML-headers. graph = enable graphics, needs GD::Graph, only useful with html or html-embed, see --output-path. Disables mail output. This switch needs the perl Module GD::Graph. unformatted = plain unformatted output --output-path /path --output-file-prefix string --output-file filename output calamaris statistics to /path. In case of graph output, the graphics destination is /path and the filename is index.html, else it is calamaris.txt. If --output-path is not given, all graphics are written to the working directory. %h will be expanded to the hostname, %t to a timerange, %% to a single %. --generate-index Generates an index-file of all matching reports if output-path and output-file-prefix is set --show-reports|-S list Shows only the defined reports (comma-seperated list) in the specified order. The following numbers are defined: '; foreach ( 0 .. $#reports ) { $USAGE .= "\t $_\t$reports[$_]\n"; } $USAGE .= ' Note: only putting out one report does not speed up Calamaris as the internal operations were done based on the report-switches. Default: Reports are displayed based on activated reports. --sort-order|-O changes the sort order in the reports to request size, default is sorting by number of requests --unit|-U string define the Unit for the Byte-values, else it will be auto. K(ilo), M(ega), G(iga), T(era) There are more options to modify the output of Calamaris. Please see the man-page. Caching: --cache-input-file|-i file input-datafile for caching, to add many files separate them with a \':\') --cache-output-file|-o file output-datafile for caching, can be the same as --cache-input-file Misc: --benchmark|-b n prints a hash-sign (#) to stderr for each n lines processed --copyright|-C prints the copyright --help|-h prints out this message --version|-V prints version-info Debug: --verbose|-v print information what Calamaris is doing. Useful for debugging. --dump-loop|-L dumps the generated internal loop to STDERR for debugging. (*) These options break the privacy of your users. Please read the README on this.'; } sub readcache { ### Read Cache. foreach $file ( split ':', $opt_i ) { open( CACHE, "$file" ) or die ("$0: can't open $file for reading: $!\n"); while () { chomp; next if m#^$#; @cache = split 'µ'; $x = shift (@cache); next unless ($x ne ''); if ( $x eq '0' and $#cache == 39 ) { $time_begin = $cache[0] if $cache[0] < $time_begin; $time_end = $cache[1] if $cache[1] > $time_end; $counter += $cache[2]; $size += $cache[3]; $time += $cache[4]; $invalid += $cache[5]; $time_run += $cache[6]; $udp += $cache[7]; $udp_size += $cache[8]; $udp_time += $cache[9]; $udp_hit += $cache[10]; $udp_hit_size += $cache[11]; $udp_hit_time += $cache[12]; $udp_miss += $cache[13]; $udp_miss_size += $cache[14]; $udp_miss_time += $cache[15]; $tcp += $cache[16]; $tcp_size += $cache[17]; $tcp_time += $cache[18]; $tcp_hit += $cache[19]; $tcp_hit_size += $cache[20]; $tcp_hit_time += $cache[21]; $tcp_miss += $cache[22]; $tcp_miss_size += $cache[23]; $tcp_miss_time += $cache[24]; $tcp_miss_none += $cache[25]; $tcp_miss_none_size += $cache[26]; $tcp_miss_none_time += $cache[27]; $hier += $cache[28]; $hier_size += $cache[29]; $hier_time += $cache[30]; $hier_direct += $cache[31]; $hier_direct_size += $cache[32]; $hier_direct_time += $cache[33]; $hier_sibling += $cache[34]; $hier_sibling_size += $cache[35]; $hier_sibling_time += $cache[36]; $hier_parent += $cache[37]; $hier_parent_size += $cache[38]; $hier_parent_time += $cache[39]; } elsif ( $x eq '1' and $#cache == 17 ) { unless ( $peak_udp_sec == 0 ) { warn("multiple cache files.\n") if $opt_v; $peak_warn = 'Peak values are possibly wrong!'; } if ( $peak_udp_sec < $cache[0] ) { $peak_udp_sec = $cache[0]; $peak_udp_sec_time = $cache[1]; } if ( $peak_udp_min < $cache[2] ) { $peak_udp_min = $cache[2]; $peak_udp_min_time = $cache[3]; } $peak_udp_hour{ $cache[5] } = 0 unless defined $peak_udp_hour{ $cache[5] }; $peak_udp_hour{ $cache[5] } += $cache[4]; if ( $peak_tcp_sec < $cache[6] ) { $peak_tcp_sec = $cache[6]; $peak_tcp_sec_time = $cache[7]; } if ( $peak_tcp_min < $cache[8] ) { $peak_tcp_min = $cache[8]; $peak_tcp_min_time = $cache[9]; } $peak_tcp_hour{ $cache[11] } = 0 unless defined $peak_tcp_hour{ $cache[11] }; $peak_tcp_hour{ $cache[11] } += $cache[10]; if ( $peak_all_sec < $cache[12] ) { $peak_all_sec = $cache[12]; $peak_all_sec_time = $cache[13]; } if ( $peak_all_min < $cache[14] ) { $peak_all_min = $cache[14]; $peak_all_min_time = $cache[15]; } $peak_all_hour{ $cache[17] } = 0 unless defined $peak_all_hour{ $cache[17] }; $peak_all_hour{ $cache[17] } += $cache[16]; } elsif ( $x eq '1' and $#cache == 23 ) { unless ( $peak_udp_sec == 0 ) { warn("multiple cache files.\n") if $opt_v; $peak_warn = 'Peak values are possibly wrong!'; } if ( $peak_udp_sec < $cache[0] ) { $peak_udp_sec = $cache[0]; $peak_udp_sec_time = $cache[1]; } if ( $peak_udp_min < $cache[2] ) { $peak_udp_min = $cache[2]; $peak_udp_min_time = $cache[3]; } $peak_udp_hour{ $cache[5] } = 0 unless defined $peak_udp_hour{ $cache[5] }; $peak_udp_hour{ $cache[5] } += $cache[4]; $peak_udp_hour_size{ $cache[7] } = 0 unless defined $peak_udp_hour_size{ $cache[7] }; $peak_udp_hour_size{ $cache[7] } += $cache[6]; if ( $peak_tcp_sec < $cache[8] ) { $peak_tcp_sec = $cache[8]; $peak_tcp_sec_time = $cache[9]; } if ( $peak_tcp_min < $cache[10] ) { $peak_tcp_min = $cache[10]; $peak_tcp_min_time = $cache[11]; } $peak_tcp_hour{ $cache[13] } = 0 unless defined $peak_tcp_hour{ $cache[13] }; $peak_tcp_hour{ $cache[13] } += $cache[12]; $peak_tcp_hour_size{ $cache[15] } = 0 unless defined $peak_tcp_hour_size{ $cache[15] }; $peak_tcp_hour_size{ $cache[15] } += $cache[14]; if ( $peak_all_sec < $cache[16] ) { $peak_all_sec = $cache[16]; $peak_all_sec_time = $cache[17]; } if ( $peak_all_min < $cache[18] ) { $peak_all_min = $cache[18]; $peak_all_min_time = $cache[19]; } $peak_all_hour{ $cache[21] } = 0 unless defined $peak_all_hour{ $cache[21] }; $peak_all_hour{ $cache[21] } += $cache[20]; $peak_all_hour_size{ $cache[23] } = 0 unless defined $peak_all_hour_size{ $cache[23] }; $peak_all_hour_size{ $cache[23] } += $cache[22]; } elsif ( $x eq '3' and $#cache == 3 ) { $y = shift (@cache); $method{$y} = $method_size{$y} = $method_time{$y} = 0 unless defined $method{$y}; $method{$y} += $cache[0]; $method_size{$y} += $cache[1]; $method_time{$y} += $cache[2]; } elsif ( $x eq '4.1' and $#cache == 3 ) { $y = shift (@cache); $udp_hit{$y} = $udp_hit_size{$y} = $udp_hit_time{$y} = 0 unless defined $udp_hit{$y}; $udp_hit{$y} += $cache[0]; $udp_hit_size{$y} += $cache[1]; $udp_hit_time{$y} += $cache[2]; } elsif ( $x eq '4.2' and $#cache == 3 ) { $y = shift (@cache); $udp_miss{$y} = $udp_miss_size{$y} = $udp_miss_time{$y} = 0 unless defined $udp_miss{$y}; $udp_miss{$y} += $cache[0]; $udp_miss_size{$y} += $cache[1]; $udp_miss_time{$y} += $cache[2]; } elsif ( $x eq '5.1' and $#cache == 3 ) { $y = shift (@cache); $tcp_hit{$y} = $tcp_hit_size{$y} = $tcp_hit_time{$y} = 0 unless defined $tcp_hit{$y}; $tcp_hit{$y} += $cache[0]; $tcp_hit_size{$y} += $cache[1]; $tcp_hit_time{$y} += $cache[2]; } elsif ( $x eq '5.2' and $#cache == 3 ) { $y = shift (@cache); $tcp_miss{$y} = $tcp_miss_size{$y} = $tcp_miss_time{$y} = 0 unless defined $tcp_miss{$y}; $tcp_miss{$y} += $cache[0]; $tcp_miss_size{$y} += $cache[1]; $tcp_miss_time{$y} += $cache[2]; } elsif ( $x eq '5.3' and $#cache == 3 ) { $y = shift (@cache); $tcp_miss_none{$y} = $tcp_miss_none_size{$y} = $tcp_miss_none_time{$y} = 0 unless defined $tcp_miss_none{$y}; $tcp_miss_none{$y} += $cache[0]; $tcp_miss_none_size{$y} += $cache[1]; $tcp_miss_none_time{$y} += $cache[2]; } elsif ( $x eq '6.1' and $#cache == 3 ) { $y = shift (@cache); $hier_direct{$y} = $hier_direct_size{$y} = $hier_direct_time{$y} = 0 unless defined $hier_direct{$y}; $hier_direct{$y} += $cache[0]; $hier_direct_size{$y} += $cache[1]; $hier_direct_time{$y} += $cache[2]; } elsif ( $x eq '6.2' and $#cache == 3 ) { $y = shift (@cache); $hier_sibling{$y} = $hier_sibling_size{$y} = $hier_sibling_time{$y} = 0 unless defined $hier_sibling{$y}; $hier_sibling{$y} += $cache[0]; $hier_sibling_size{$y} += $cache[1]; $hier_sibling_time{$y} += $cache[2]; } elsif ( $x eq '6.3' and $#cache == 3 ) { $y = shift (@cache); $hier_parent{$y} = $hier_parent_size{$y} = $hier_parent_time{$y} = 0 unless defined $hier_parent{$y}; $hier_parent{$y} += $cache[0]; $hier_parent_size{$y} += $cache[1]; $hier_parent_time{$y} += $cache[2]; } elsif ( $x eq '7.1' and $#cache == 3 ) { $y = shift (@cache); $hier_neighbor{$y} = $hier_neighbor_size{$y} = $hier_neighbor_time{$y} = 0 unless defined $hier_neighbor{$y}; $hier_neighbor{$y} += $cache[0]; $hier_neighbor_size{$y} += $cache[1]; $hier_neighbor_time{$y} += $cache[2]; } elsif ( $x eq '7.2' and $#cache == 4 ) { $y = shift (@cache); $z = shift (@cache); $hier_neighbor_status{$y}{$z} = $hier_neighbor_status_size{$y}{$z} = $hier_neighbor_status_time{$y}{$z} = 0 unless defined $hier_neighbor_status{$y}{$z}; $hier_neighbor_status{$y}{$z} += $cache[0]; $hier_neighbor_status_size{$y}{$z} += $cache[1]; $hier_neighbor_status_time{$y}{$z} += $cache[2]; } elsif ( $x eq '8' and $#cache == 5 ) { $y = shift (@cache); $tcp_urlhost{$y} = $tcp_urlhost_size{$y} = $tcp_urlhost_time{$y} = $tcp_hit_urlhost{$y} = $tcp_hit_urlhost_size{$y} = 0 unless defined $tcp_urlhost{$y}; $show_other_tcp_urlhost = 0 if defined($tcp_urlhost{''}); $tcp_urlhost{$y} += $cache[0]; $tcp_urlhost_size{$y} += $cache[1]; $tcp_hit_urlhost{$y} += $cache[2]; $tcp_hit_urlhost_size{$y} += $cache[3]; $tcp_urlhost_time{$y} += $cache[4]; } elsif ( $x eq '9' and $#cache == 5 ) { $y = shift (@cache); $tcp_urltld{$y} = $tcp_urltld_size{$y} = $tcp_urltld_time{$y} = $tcp_hit_urltld{$y} = $tcp_hit_urltld_size{$y} = 0 unless defined $tcp_urltld{$y}; $show_other_tcp_urltld = 0 if defined($tcp_urltld{''}); $tcp_urltld{$y} += $cache[0]; $tcp_urltld_size{$y} += $cache[1]; $tcp_hit_urltld{$y} += $cache[2]; $tcp_hit_urltld_size{$y} += $cache[3]; $tcp_urltld_time{$y} += $cache[4]; } elsif ( $x eq '10' and $#cache == 5 ) { $y = shift (@cache); $tcp_urlprot{$y} = $tcp_urlprot_size{$y} = $tcp_urlprot_time{$y} = $tcp_hit_urlprot{$y} = $tcp_hit_urlprot_size{$y} = 0 unless defined $tcp_urlprot{$y}; $tcp_urlprot{$y} += $cache[0]; $tcp_urlprot_size{$y} += $cache[1]; $tcp_hit_urlprot{$y} += $cache[2]; $tcp_hit_urlprot_size{$y} += $cache[3]; $tcp_urlprot_time{$y} += $cache[4]; } elsif ( $x eq '11' and $#cache == 5 ) { $y = shift (@cache); $tcp_content{$y} = $tcp_content_size{$y} = $tcp_content_time{$y} = $tcp_hit_content{$y} = $tcp_hit_content_size{$y} = 0 unless defined $tcp_content{$y}; $show_other_tcp_content = 0 if defined($tcp_content{''}); $tcp_content{$y} += $cache[0]; $tcp_content_size{$y} += $cache[1]; $tcp_hit_content{$y} += $cache[2]; $tcp_hit_content_size{$y} += $cache[3]; $tcp_content_time{$y} += $cache[4]; } elsif ( $x eq '12' and $#cache == 10 ) { $y = shift (@cache); $tcp_urlext{$y} = $tcp_urlext_size{$y} = $tcp_urlext_time{$y} = $tcp_hit_urlext{$y} = $tcp_hit_urlext_size{$y} = 0 unless defined $tcp_urlext{$y}; $show_other_tcp_urlext = 0 if defined($tcp_urlext{''}); $tcp_urlext{$y} += $cache[0]; $tcp_urlext_size{$y} += $cache[1]; $tcp_hit_urlext{$y} += $cache[2]; $tcp_hit_urlext_size{$y} += $cache[3]; $tcp_urlext_time{$y} += $cache[4]; $tcp_urlext_fresh{$y} += $cache[5]; $tcp_urlext_stale{$y} += $cache[6]; $tcp_urlext_refresh{$y} += $cache[7]; $tcp_urlext_mod{$y} += $cache[8]; $tcp_urlext_unmod{$y} += $cache[9]; } elsif ( $x eq '13.1' and $#cache == 5 ) { $y = shift (@cache); $udp_requester{$y} = $udp_requester_size{$y} = $udp_requester_time{$y} = $udp_hit_requester{$y} = $udp_hit_requester_size{$y} = 0 unless defined $udp_requester{$y}; $show_other_udp_requester = 0 if defined($udp_requester{''}); $udp_requester{$y} += $cache[0]; $udp_requester_size{$y} += $cache[1]; $udp_requester_time{$y} += $cache[2]; $udp_hit_requester{$y} += $cache[3]; $udp_hit_requester_size{$y} += $cache[4]; } elsif ( $x eq '14.1' and $#cache == 5 ) { $y = shift (@cache); $tcp_requester{$y} = $tcp_requester_size{$y} = $tcp_requester_time{$y} = $tcp_hit_requester{$y} = $tcp_hit_requester_size{$y} = 0 unless defined $tcp_requester{$y}; $show_other_tcp_requester = 0 if defined($tcp_requester{''}); $tcp_requester{$y} += $cache[0]; $tcp_requester_size{$y} += $cache[1]; $tcp_requester_time{$y} += $cache[2]; $tcp_hit_requester{$y} += $cache[3]; $tcp_hit_requester_size{$y} += $cache[4]; } elsif ( $x eq '16' and $#cache == 15 ) { $y = shift (@cache); $perf_counter{$y} += $cache[0]; $perf_size{$y} += $cache[1]; $perf_time{$y} += $cache[2]; $perf_tcp_hit_size{$y} += $cache[3]; $perf_tcp_hit_time{$y} += $cache[4]; $perf_tcp_miss_size{$y} += $cache[5]; $perf_tcp_miss_time{$y} += $cache[6]; $perf_hier_direct_size{$y} += $cache[7]; $perf_hier_direct_time{$y} += $cache[8]; $perf_hier_sibling_size{$y} += $cache[9]; $perf_hier_sibling_time{$y} += $cache[10]; $perf_hier_parent_size{$y} += $cache[11]; $perf_hier_parent_time{$y} += $cache[12]; $perf_requester{$y} += $cache[13]; $perf_tcp_hit{$y} += $cache[14]; } elsif ( $x eq '13.2' and $#cache == 6 ) { $y = shift (@cache); $z = shift (@cache); $udp_requester_urlhost{$y}{$z} = $udp_requester_urlhost_size{$y}{$z} = $udp_requester_urlhost_time{$y}{$z} = $udp_hit_requester_urlhost{$y}{$z} = $udp_hit_requester_urlhost_size{$y}{$z} = 0 unless defined $udp_requester_urlhost{$y}{$z}; $udp_requester_urlhost{$y}{$z} += $cache[0]; $udp_requester_urlhost_size{$y}{$z} += $cache[1]; $udp_requester_urlhost_time{$y}{$z} += $cache[2]; $udp_hit_requester_urlhost{$y}{$z} += $cache[3]; $udp_hit_requester_urlhost_size{$y}{$z} += $cache[4]; } elsif ( $x eq '14.2' and $#cache == 6 ) { $y = shift (@cache); $z = shift (@cache); $tcp_requester_urlhost{$y}{$z} = $tcp_requester_urlhost_size{$y}{$z} = $tcp_requester_urlhost_time{$y}{$z} = $tcp_hit_requester_urlhost{$y}{$z} = $tcp_hit_requester_urlhost_size{$y}{$z} = 0 unless defined $tcp_requester_urlhost{$y}{$z}; $tcp_requester_urlhost{$y}{$z} += $cache[0]; $tcp_requester_urlhost_size{$y}{$z} += $cache[1]; $tcp_requester_urlhost_time{$y}{$z} += $cache[2]; $tcp_hit_requester_urlhost{$y}{$z} += $cache[3]; $tcp_hit_requester_urlhost_size{$y}{$z} += $cache[4]; } elsif ( $x eq '15' and $#cache == 5 ) { $y = shift (@cache); $tcp_distribution{$y} = $tcp_distribution_size{$y} = $tcp_distribution_time{$y} = $tcp_hit_distribution{$y} = $tcp_hit_distribution_size{$y} = 0 unless defined $tcp_distribution{$y}; $tcp_distribution{$y} += $cache[0]; $tcp_distribution_size{$y} += $cache[1]; $tcp_distribution_time{$y} += $cache[2]; $tcp_hit_distribution{$y} += $cache[3]; $tcp_hit_distribution_size{$y} += $cache[4]; # read max values } elsif ( $x eq '18' and $#cache == 1 ) { $ordered_tcp_req_time_max_interval = $cache[0]; $ordered_tcp_req_time_max = $cache[1]; } elsif ( $x eq '18' and $#cache == 5 ) { $y = shift (@cache); $ordered_tcp_req_time{$y} = $ordered_tcp_req_time_size{$y} = $ordered_tcp_hit_req_time{$y} = $ordered_tcp_hit_req_time_size{$y} = $ordered_tcp_req_time_time{$y} = 0 unless defined $ordered_tcp_req_time{$y}; $ordered_tcp_req_time{$y} += $cache[0]; $ordered_tcp_req_time_size{$y} += $cache[1]; $ordered_tcp_hit_req_time{$y} += $cache[2]; $ordered_tcp_hit_req_time_size{$y} += $cache[3]; $ordered_tcp_req_time_time{$y} += $cache[4]; # read max values } elsif ( $x eq '17' and $#cache == 1 ) { $ordered_udp_req_time_max_interval = $cache[0]; $ordered_udp_req_time_max = $cache[1]; } elsif ( $x eq '17' and $#cache == 5 ) { $y = shift (@cache); $ordered_udp_req_time{$y} = $ordered_udp_req_time_size{$y} = $ordered_udp_hit_req_time{$y} = $ordered_udp_hit_req_time_size{$y} = $ordered_udp_req_time_time{$y} = 0 unless defined $ordered_udp_req_time{$y}; $ordered_udp_req_time{$y} += $cache[0]; $ordered_udp_req_time_size{$y} += $cache[1]; $ordered_udp_hit_req_time{$y} += $cache[2]; $ordered_udp_hit_req_time_size{$y} += $cache[3]; $ordered_udp_req_time_time{$y} += $cache[4]; } elsif ( $x eq '19' and $#cache == 5 ) { $y = shift (@cache); $udp_code{$y} = $udp_code_size{$y} = 0 unless defined $udp_code{$y}; $udp_code{$y} += $cache[0]; $udp_code_size{$y} += $cache[1]; $udp_hit_code{$y} += $cache[2]; $udp_hit_code_size{$y} += $cache[3]; $udp_code_time{$y} += $cache[4]; } elsif ( $x eq '20' and $#cache == 5 ) { $y = shift (@cache); $tcp_code{$y} = $tcp_code_size{$y} = 0 unless defined $tcp_code{$y}; $tcp_code{$y} += $cache[0]; $tcp_code_size{$y} += $cache[1]; $tcp_hit_code{$y} += $cache[2]; $tcp_hit_code_size{$y} += $cache[3]; $tcp_code_time{$y} += $cache[4]; } else { print STDERR "can't parse cache-line: \"$x @cache\"\n"; $cache_warn = 1 if ( $x =~ m#^[A-Z]$# ); } } close(CACHE); } } sub htmlescape { my $toencode = shift; return undef unless defined($toencode); $toencode=~s/&/&/gso; $toencode=~s/\"/"/gso; $toencode=~s/>/>/gso; $toencode=~s/= $b) ? $a : $b; my $next = ($a >= $b) ? $b : $a; return $a, $b if !$gcd; if ($next) { foreach (1..3) { # reduces accuracy, but increases readability :-) my $r = $gcd % $next; $r += $next if $r < 0; # fix for % in integer mode $gcd = $next; $next = $r; last if ($next == 0); } } return $a/$gcd, $b/$gcd; } sub uri_unescape { # Note from RFC1630: "Sequences which start with a percent sign # but are not followed by two hexadecimal characters are reserved # for future extension" my $str = shift; if (@_ && wantarray) { # not executed for the common case of a single argument my @str = ($str, @_); # need to copy foreach (@str) { s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg } return @str; } $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; $str; } calamaris-2.99.4.7/calAxestype3d.pm0000644000175000017500000005555114161616434015450 0ustar cordcord#========================================================================== # Module: calamaris::calAxestype3d.pm # # Copyright # # calAxestype3d.pm Copyright (c) 2004 Michael Pophal based on # GD::Graph Copyright (c) 1999 Martien Verbruggen. # (https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm) # # All rights reserved. This package is free software; you can redistribute # it and/or modify it under the same terms as Perl itself. # # Acknowledgements # # Thanks to Martien Verbruggen's ingenious tool GD::Graph, which is basically # the same, except some small changes needed for calamaris. #========================================================================== # # Adapted to calamaris by: (c) 2004 Michael Pophal # # Based on: # GD::Graph::axestype3d.pm,v 1.21 2000/04/15 08:59:36 mgjv # https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm # Copyright (c) 1995-1998 Martien Verbruggen # #-------------------------------------------------------------------------- # # Name: # calamaris::calAxestype3d.pm # # $Id: calAxestype3d.pm,v 3.2 2004-09-15 21:02:13 cord Exp $ # #-------------------------------------------------------------------------- # Date Modification Author # ------------------------------------------------------------------------- # 2004AUG30 Adapted to calamaris staehler #========================================================================== package calamaris::calAxestype3d; use strict; use lib '/usr/local'; use GD::Graph; use calamaris::calAxestype; use GD::Graph::utils qw(:all); use GD::Graph::colour qw(:colours); use Carp; @calamaris::calAxestype3d::ISA = qw(calamaris::calAxestype); $calamaris::calAxestype3d::VERSION = '0.63'; # Commented inheritance from GD::Graph::axestype unless otherwise noted. use constant PI => 4 * atan2(1,1); my %Defaults = ( depth_3d => 20, '3d_shading' => 1, # the rest are inherited ); # Inherit _has_default # Can't inherit initialise, because %Defaults is referenced file- # specific, not class specific. sub initialise { my $self = shift; my $rc = $self->SUPER::initialise(); while( my($key, $val) = each %Defaults ) { $self->{$key} = $val } # end while return $rc; } # end initialise # PUBLIC # Inherit plot # Inherit set # Inherit setup_text # Inherit set_x_label_font # Inherit set_y_label_font # Inherit set_x_axis_font # Inherit set_y_axis_font # Inherit set_legend # Inherit set_legend_font # ---------------------------------------------------------- # Sub: init_graph # # Args: (None) # # Description: # Override GD::Graph::init_graph to add 3d shading colors, # if requested # # [From GD::Graph] # Initialise the graph output canvas, setting colours (and # getting back index numbers for them) setting the graph to # transparent, and interlaced, putting a logo (if defined) # on there. # ---------------------------------------------------------- # Date Modification Author # ---------------------------------------------------------- # 20Aug2000 Added to support 3d graph extensions JW # ---------------------------------------------------------- sub init_graph { my $self = shift; # Sets up the canvas and color palette $self->SUPER::init_graph( @_ ); # Now create highlights and showdows for each color # in the palette if( $self->{'3d_shading'} ) { $self->{'3d_highlights'} = []; $self->{'3d_shadows'} = []; $self->{'3d_highlights'}[$self->{bgci}] = $self->set_clr( $self->_brighten( _rgb($self->{bgclr}) ) ); $self->{'3d_shadows'}[$self->{bgci}] = $self->set_clr( $self->_darken( _rgb($self->{bgclr}) ) ); $self->{'3d_highlights'}[$self->{fgci}] = $self->set_clr( $self->_brighten( _rgb($self->{fgclr}) ) ); $self->{'3d_shadows'}[$self->{fgci}] = $self->set_clr( $self->_darken( _rgb($self->{fgclr}) ) ); $self->{'3d_highlights'}[$self->{tci}] = $self->set_clr( $self->_brighten( _rgb($self->{textclr}) ) ); $self->{'3d_shadows'}[$self->{tci}] = $self->set_clr( $self->_darken( _rgb($self->{textclr}) ) ); $self->{'3d_highlights'}[$self->{lci}] = $self->set_clr( $self->_brighten( _rgb($self->{labelclr}) ) ); $self->{'3d_shadows'}[$self->{lci}] = $self->set_clr( $self->_darken( _rgb($self->{labelclr}) ) ); $self->{'3d_highlights'}[$self->{alci}] = $self->set_clr( $self->_brighten( _rgb($self->{axislabelclr}) ) ); $self->{'3d_shadows'}[$self->{alci}] = $self->set_clr( $self->_darken( _rgb($self->{axislabelclr}) ) ); $self->{'3d_highlights'}[$self->{acci}] = $self->set_clr( $self->_brighten( _rgb($self->{accentclr}) ) ); $self->{'3d_shadows'}[$self->{acci}] = $self->set_clr( $self->_darken( _rgb($self->{accentclr}) ) ); $self->{'3d_highlights'}[$self->{valuesci}] = $self->set_clr( $self->_brighten( _rgb($self->{valuesclr}) ) ); $self->{'3d_shadows'}[$self->{valuesci}] = $self->set_clr( $self->_darken( _rgb($self->{valuesclr}) ) ); $self->{'3d_highlights'}[$self->{legendci}] = $self->set_clr( $self->_brighten( _rgb($self->{legendclr}) ) ); $self->{'3d_shadows'}[$self->{legendci}] = $self->set_clr( $self->_darken( _rgb($self->{legendclr}) ) ); if( $self->{boxclr} ) { $self->{'3d_highlights'}[$self->{boxci}] = $self->set_clr( $self->_brighten( _rgb($self->{boxclr}) ) ); $self->{'3d_shadows'}[$self->{boxci}] = $self->set_clr( $self->_darken( _rgb($self->{boxclr}) ) ); } # end if } # end if return $self; } # end init_graph # PRIVATE # ---------------------------------------------------------- # Sub: _brighten # # Args: $r, $g, $b # $r, $g, $b The Red, Green, and Blue components of a color # # Description: Brightens the color by adding white # ---------------------------------------------------------- # Date Modification Author # ---------------------------------------------------------- # 21AUG2000 Created to build 3d highlights table JW # ---------------------------------------------------------- sub _brighten { my $self = shift; my( $r, $g, $b ) = @_; my $p = ($r + $g + $b) / 70; $p = 3 if $p < 3; my $f = _max( $r / $p, _max( $g / $p, $b / $p ) ); $r = _min( 255, int( $r + $f ) ); $g = _min( 255, int( $g + $f ) ); $b = _min( 255, int( $b + $f ) ); return( $r, $g, $b ); } # end _brighten # ---------------------------------------------------------- # Sub: _darken # # Args: $r, $g, $b # $r, $g, $b The Red, Green, and Blue components of a color # # Description: Darkens the color by adding black # ---------------------------------------------------------- # Date Modification Author # ---------------------------------------------------------- # 21AUG2000 Created to build 3d shadows table JW # ---------------------------------------------------------- sub _darken { my $self = shift; my( $r, $g, $b ) = @_; my $p = ($r + $g + $b) / 70; $p = 3 if $p < 3; my $f = _max( $r / $p, _max( $g / $p, $b / $p) ); $r = _max( 0, int( $r - $f ) ); $g = _max( 0, int( $g - $f ) ); $b = _max( 0, int( $b - $f ) ); return( $r, $g, $b ); } # end _darken # inherit check_data from GD::Graph # [JAW] Setup boundaries as parent, the adjust for 3d extrusion sub _setup_boundaries { my $self = shift; $self->SUPER::_setup_boundaries(); # adjust for top of 3-d extrusion $self->{top} += $self->{depth_3d}; return $self->_set_error('Vertical size too small') if $self->{bottom} <= $self->{top}; # adjust for right of 3-d extrusion $self->{right} -= $self->{depth_3d}; return $self->_set_error('Horizontal size too small') if $self->{right} <= $self->{left}; return $self; } # end _setup_boundaries # [JAW] Determine 3d-extrusion depth, then call parent sub setup_coords { my $self = shift; # Calculate the 3d-depth of the graph # Note this sets a minimum depth of ~20 pixels # if (!defined $self->{x_tick_number}) { my $depth = _max( $self->{bar_depth}, $self->{line_depth} ); if( $self->{overwrite} == 1 ) { $depth *= $self->{_data}->num_sets(); } # end if $self->{depth_3d} = _max( $depth, $self->{depth_3d} ); # } # end if $self->SUPER::setup_coords(); return $self; } # end setup_coords # Inherit create_y_labels # Inherit get_x_axis_label_height # Inherit create_x_labels # inherit open_graph from GD::Graph # Inherit draw_text # [JAW] Draws entire bounding cube for 3-d extrusion sub draw_axes { my $s = shift; my $g = $s->{graph}; my ($l, $r, $b, $t) = ( $s->{left}, $s->{right}, $s->{bottom}, $s->{top} ); my $depth = $s->{depth_3d}; if ( $s->{box_axis} ) { # -- Draw a bounding box if( $s->{boxci} ) { # -- Fill the box with color # Back box $g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci}); # Left side my $poly = new GD::Polygon; $poly->addPt( $l, $t ); $poly->addPt( $l + $depth, $t - $depth ); $poly->addPt( $l + $depth, $b - $depth ); $poly->addPt( $l, $b ); if( $s->{'3d_shading'} ) { $g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] ); } else { $g->filledPolygon( $poly, $s->{boxci} ); } # end if # Bottom $poly = new GD::Polygon; $poly->addPt( $l, $b ); $poly->addPt( $l + $depth, $b - $depth ); $poly->addPt( $r + $depth, $b - $depth ); $poly->addPt( $r, $b ); if( $s->{'3d_shading'} ) { $g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] ); } else { $g->filledPolygon( $poly, $s->{boxci} ); } # end if } # end if # -- Draw the box frame # Back box $g->rectangle($l+$depth, $t-$depth, $r+$depth, $b-$depth, $s->{fgci}); # Connecting frame $g->line($l, $t, $l + $depth, $t - $depth, $s->{fgci}); $g->line($r, $t, $r + $depth, $t - $depth, $s->{fgci}); $g->line($l, $b, $l + $depth, $b - $depth, $s->{fgci}); $g->line($r, $b, $r + $depth, $b - $depth, $s->{fgci}); # Front box $g->rectangle($l, $t, $r, $b, $s->{fgci}); } else { if( $s->{boxci} ) { # -- Fill the background box with color # Back box $g->filledRectangle($l+$depth+1, $t-$depth+1, $r+$depth-1, $b-$depth-1, $s->{boxci}); # Left side my $poly = new GD::Polygon; $poly->addPt( $l, $t ); $poly->addPt( $l + $depth, $t - $depth ); $poly->addPt( $l + $depth, $b - $depth ); $poly->addPt( $l, $b ); if( $s->{'3d_shading'} ) { $g->filledPolygon( $poly, $s->{'3d_shadows'}[$s->{boxci}] ); } else { $g->filledPolygon( $poly, $s->{boxci} ); } # end if # Bottom $poly = new GD::Polygon; $poly->addPt( $l, $b ); $poly->addPt( $l + $depth, $b - $depth ); $poly->addPt( $r + $depth, $b - $depth ); $poly->addPt( $r, $b ); if( $s->{'3d_shading'} ) { $g->filledPolygon( $poly, $s->{'3d_highlights'}[$s->{boxci}] ); } else { $g->filledPolygon( $poly, $s->{boxci} ); } # end if } # end if # -- Draw the frame only for back & sides # Back box $g->rectangle($l + $depth, $t - $depth, $r + $depth, $b - $depth, $s->{fgci}); # Y axis my $poly = new GD::Polygon; $poly->addPt( $l, $t ); $poly->addPt( $l, $b ); $poly->addPt( $l + $depth, $b - $depth ); $poly->addPt( $l + $depth, $t - $depth ); $g->polygon( $poly, $s->{fgci} ); # X axis if( !$s->{zero_axis_only} ) { $poly = new GD::Polygon; $poly->addPt( $l, $b ); $poly->addPt( $r, $b ); $poly->addPt( $r + $depth, $b - $depth ); $poly->addPt( $l + $depth, $b - $depth ); $g->polygon( $poly, $s->{fgci} ); } # end if # Second Y axis if( $s->{two_axes} ){ $poly = new GD::Polygon; $poly->addPt( $r, $b ); $poly->addPt( $r, $t ); $poly->addPt( $r + $depth, $t - $depth ); $poly->addPt( $r + $depth, $b - $depth ); $g->polygon( $poly, $s->{fgci} ); } # end if } # end if # Zero axis if ($s->{zero_axis} or $s->{zero_axis_only}) { my ($x, $y) = $s->val_to_pixel(0, 0, 1); my $poly = new GD::Polygon; $poly->addPt( $l, $y ); $poly->addPt( $r, $y ); $poly->addPt( $r + $depth, $y - $depth ); $poly->addPt( $l + $depth, $y - $depth); $g->polygon( $poly, $s->{fgci} ); } # end if } # end draw_axes # [JAW] Draws ticks and values for y axes in 3d extrusion # Modified from MVERB source sub draw_y_ticks { my $self = shift; for my $t (0 .. $self->{y_tick_number}) { for my $a (1 .. ($self->{two_axes} + 1)) { my $value = $self->{y_values}[$a][$t]; my $label = $self->{y_labels}[$a][$t]; my ($x, $y) = $self->val_to_pixel(0, $value, $a); $x = ($a == 1) ? $self->{left} : $self->{right}; # CONTRIB Jeremy Wadsack # Draw on the back of the extrusion $x += $self->{depth_3d}; $y -= $self->{depth_3d}; if ($self->{y_long_ticks}) { $self->{graph}->line( $x, $y, $x + $self->{right} - $self->{left}, $y, $self->{fgci} ) unless ($a-1); # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x, $y, $self->{fgci} ) unless ($a-1); } else { $self->{graph}->line( $x, $y, $x + (3 - 2 * $a) * $self->{y_tick_length}, $y, $self->{fgci} ); # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x - $self->{depth_3d} + (3 - 2 * $a) * $self->{y_tick_length}, $y + $self->{depth_3d} - (3 - 2 * $a) * $self->{y_tick_length}, $self->{fgci} ); } next if $t % ($self->{y_label_skip}) || ! $self->{y_plot_values}; $self->{gdta_y_axis}->set_text($label); $self->{gdta_y_axis}->set_align('center', $a == 1 ? 'right' : 'left'); $x -= (3 - 2 * $a) * $self->{axis_space}; # CONTRIB Jeremy Wadsack # Subtract 3-d extrusion width from left axis label # (it was added for ticks) $x -= (2 - $a) * $self->{depth_3d}; # CONTRIB Jeremy Wadsack # Add 3-d extrusion height to label # (it was subtracted for ticks) $y += $self->{depth_3d}; $self->{gdta_y_axis}->draw($x, $y); } # end foreach } # end foreach return $self; } # end draw_y_ticks # [JAW] Darws ticks and values for x axes wih 3d extrusion # Modified from MVERB source sub draw_x_ticks { my $self = shift; for (my $i = 0; $i < $self->{_data}->num_points; $i++) { my ($x, $y) = $self->val_to_pixel($i + 1, 0, 1); $y = $self->{bottom} unless $self->{zero_axis_only}; # CONTRIB Damon Brodie for x_tick_offset next if (!$self->{x_all_ticks} and ($i - $self->{x_tick_offset}) % $self->{x_label_skip} and $i != $self->{_data}->num_points - 1 ); # CONTRIB Jeremy Wadsack # Draw on the back of the extrusion $x += $self->{depth_3d}; $y -= $self->{depth_3d}; if ($self->{x_ticks}) { if ($self->{x_long_ticks}) { # CONTRIB Jeremy Wadsack # Move up by 3d depth $self->{graph}->line( $x, $self->{bottom} - $self->{depth_3d}, $x, $self->{top} - $self->{depth_3d}, $self->{fgci}); # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x, $y, $self->{fgci} ); } else { $self->{graph}->line( $x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci} ); # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x - $self->{depth_3d} + $self->{x_tick_length}, $y + $self->{depth_3d} - $self->{x_tick_length}, $self->{fgci} ); } } # CONTRIB Damon Brodie for x_tick_offset next if ($i - $self->{x_tick_offset}) % ($self->{x_label_skip}) and $i != $self->{_data}->num_points - 1; $self->{gdta_x_axis}->set_text($self->{_data}->get_x($i)); # CONTRIB Jeremy Wadsack # Subtract 3-d extrusion width from left label # Add 3-d extrusion height to left label # (they were changed for ticks) $x -= $self->{depth_3d}; $y += $self->{depth_3d}; my $yt = $y + $self->{axis_space}; if ($self->{x_labels_vertical}) { $self->{gdta_x_axis}->set_align('center', 'right'); $self->{gdta_x_axis}->draw($x, $yt, PI/2); } else { $self->{gdta_x_axis}->set_align('top', 'center'); $self->{gdta_x_axis}->draw($x, $yt); } } # end for return $self; } # end draw_x_ticks # CONTRIB Scott Prahl # Assume x array contains equally spaced x-values # and generate an appropriate axis # #### # 'True' numerical X axis addition # From: Gary Deschaines # # These modification to draw_x_ticks_number pass x-tick values to the # val_to_pixel subroutine instead of x-tick indices when ture[sic] numerical # x-axis mode is detected. Also, x_tick_offset and x_label_skip are # processed differently when true numerical x-axis mode is detected to # allow labeled major x-tick marks and un-labeled minor x-tick marks. # # For example: # # x_tick_number => 14, # x_ticks => 1, # x_long_ticks => 1, # x_tick_length => -4, # x_min_value => 100, # x_max_value => 800, # x_tick_offset => 2, # x_label_skip => 2, # # # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # | | | | | | | | | | | | | # 1 -| | | | | | | | | | | | | # | | | | | | | | | | | | | # 0 _|_________|____|____|____|____|____|____|____|____|____|____|_________| # | | | | | | | | | | | # 200 300 400 500 600 700 #### # [JAW] Added commented items for 3d rendering # Based on MVERB source sub draw_x_ticks_number { my $self = shift; for my $i (0 .. $self->{x_tick_number}) { my ($value, $x, $y); if (defined($self->{x_min_value}) && defined($self->{x_max_value})) { next if ($i - $self->{x_tick_offset}) < 0; next if ($i + $self->{x_tick_offset}) > $self->{x_tick_number}; $value = $self->{x_values}[$i]; ($x, $y) = $self->val_to_pixel($value, 0, 1); } else { $value = ($self->{_data}->num_points - 1) * ($self->{x_values}[$i] - $self->{true_x_min}) / ($self->{true_x_max} - $self->{true_x_min}); ($x, $y) = $self->val_to_pixel($value + 1, 0, 1); } $y = $self->{bottom} unless $self->{zero_axis_only}; # Draw on the back of the extrusion $x += $self->{depth_3d}; $y -= $self->{depth_3d}; if ($self->{x_ticks}) { if ($self->{x_long_ticks}) { # XXX This mod needs to be done everywhere ticks are # drawn if ( $self->{x_tick_length} >= 0 ) { # Move up by 3d depth $self->{graph}->line( $x, $self->{bottom} - $self->{depth_3d}, $x, $self->{top} - $self->{depth_3d}, $self->{fgci}); } else { $self->{graph}->line( $x, $self->{bottom} - $self->{x_tick_length}, $x, $self->{top}, $self->{fgci}); } # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x, $y, $self->{fgci} ); } else { $self->{graph}->line($x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci} ); # CONTRIB Jeremy Wadsack # Draw conector ticks $self->{graph}->line( $x - $self->{depth_3d}, $y + $self->{depth_3d}, $x, - $self->{depth_3d} + $self->{tick_length}, $y, + $self->{depth_3d} - $self->{tick_length}, $self->{fgci} ); } # end if -- x_long_ticks } # end if -- x_ticks # If we have to skip labels, we'll do it here. # Make sure to always draw the last one. next if $i % $self->{x_label_skip} && $i != $self->{x_tick_number}; $self->{gdta_x_axis}->set_text($self->{x_labels}[$i]); # CONTRIB Jeremy Wadsack # Subtract 3-d extrusion width from left label # Add 3-d extrusion height to left label # (they were changed for ticks) $x -= $self->{depth_3d}; $y += $self->{depth_3d}; if ($self->{x_labels_vertical}) { $self->{gdta_x_axis}->set_align('center', 'right'); my $yt = $y + $self->{text_space}/2; $self->{gdta_x_axis}->draw($x, $yt, PI/2); } else { $self->{gdta_x_axis}->set_align('top', 'center'); my $yt = $y + $self->{text_space}/2; $self->{gdta_x_axis}->draw($x, $yt); } # end if } # end for return $self; } # end draw_x_tick_number # Inherit draw_ticks # Inherit draw_data # Inherit draw_data_set # Inherit set_max_min # Inherit get_max_y # Inherit get_min_y # Inherit get_max_min_y_all # Inherit _get_bottom # Inherit val_to_pixel # Inherit setup_legend # [JW] Override draw_legend and reverse the drawing order # if cumulate is enabled so legend matches data on chart sub draw_legend { my $self = shift; return unless defined $self->{legend}; my $xl = $self->{lg_xs} + $self->{legend_spacing}; my $y = $self->{lg_ys} + $self->{legend_spacing} - 1; # If there's a frame, offset by the size and margin $xl += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size}; $y += $self->{legend_frame_margin} + $self->{legend_frame_size} if $self->{legend_frame_size}; my $i = 0; my $row = 1; my $x = $xl; # start position of current element my @legends = @{$self->{legend}}; my $i_step = 1; # If we are working in cumulate mode, then reverse the drawing order if( $self->{cumulate} ) { @legends = reverse @legends; $i = scalar(@legends); $i = $self->{_data}->num_sets if $self->{_data}->num_sets < $i; $i++; $i_step = -1; } # end if foreach my $legend (@legends) { $i += $i_step; # Legend for Pie goes over first set, and all points # Works in either direction last if $i > $self->{_data}->num_sets; last if $i < 1; my $xe = $x; # position within an element next unless defined($legend) && $legend ne ""; $self->draw_legend_marker($i, $xe, $y); $xe += $self->{legend_marker_width} + $self->{legend_spacing}; my $ys = int($y + $self->{lg_el_height}/2 - $self->{lgfh}/2); $self->{gdta_legend}->set_text($legend); $self->{gdta_legend}->draw($xe, $ys); $x += $self->{lg_el_width}; if (++$row > $self->{lg_cols}) { $row = 1; $y += $self->{lg_el_height}; $x = $xl; } } # If there's a frame, draw it now if( $self->{legend_frame_size} ) { $x = $self->{lg_xs} + $self->{legend_spacing}; $y = $self->{lg_ys} + $self->{legend_spacing} - 1; for $i ( 0 .. $self->{legend_frame_size} - 1 ) { $self->{graph}->rectangle( $x + $i, $y + $i, $x + $self->{lg_x_size} + 2 * $self->{legend_frame_margin} - $i - 1, $y + $self->{lg_y_size} + 2 * $self->{legend_frame_margin} - $i - 1, $self->{acci}, ); } # end for } # end if } # Inherit draw_legend_marker 1; calamaris-2.99.4.7/calamaris.conf0000644000175000017500000010437414161616434015202 0ustar cordcord############################################################################### ################## CONFIGURATION FILE FOR CALAMARIS V3 #################### ############################################################################### # # Configuration file for calamaris V3.x # # This configuration file follows the perl syntax. To define variables, just # do it as you are used to do it. # $var = value; # undef($var); # same as $var = 0; # # To run calamaris with a configuration file, use: # cat access.log | ./calamaris --config-file calamaris.conf # # All command line arguments overwrites the configuration file items. # # Most of the configration items can be configured by commandline # arguments. Try # ./calamaris --help # # Other commandline arguments: # -L or --dump-loop: Loop (dumps the generated internal loop to STDERR for # debugging.) # # -C or --copyright copyright (prints the copyright) # -h or --help help (prints out this message) # -V or --version Version (prints version-info) # # On each section, you find a small description, the command line argument if # available, an example output (to give you an idea of this section), the # default value and how to use in this configuration file. # ############################################################################### # # IMPORTANT: # (*) These options break the privacy of your users. Please read the README # on this. # # Some items have to be configured in this configuration file, because no # command line options are available. Otherwise default values are taken! # ############################################################################### ############################################################################### ############################# REPORT SECTION ############################## ############################################################################### ############################################################################### # # show 'n' Top-level and 'n' second-level destinations, # -1 = unlimited # # command line argument: -d n | --domain-report n # # Example output: # # Request-destinations by toplevel-domain # destination request % Byte % hit-% # --------------------------------------- --------- ------ -------- ------ ------ # *.de 360753 51.58 4576770K 47.41 22.48 # *.com 202536 28.96 4684139K 48.52 18.88 # # Request-destinations by 2nd-level-domain # destination request % Byte % hit-% # --------------------------------------- --------- ------ -------- ------ ------ # *.plaxo.com 36 10.00 84835 8.00 0.80 # *.ebay.com 20 7.40 44735 5.50 1.10 # # # Default: # undef($domain_report); # (no top- and second-level destinations are # reported) # # Usage: # $domain_report = n; # ############################################################################### # # limit the display of lines to those with a minimum of requests. # # command line argument: --domain-report-limit n # # Default : # undef($domain_report_limit); # no limit. # # Usage: # $domain_report_limit = n; ############################################################################### # # change all 2nd-level-reports to N-level-reports. 'n' can be # any number from 2 up. -1 means full report. # This is only useful, if $domain_report is set (see above). # # command line argument: -N n | --domain-report-n-level n # # # Default: # undef($domain_report_n_level); # (reporting of second-level destinations) # # Usage: # $domain_report_n_level = n; # (reporting of n-level destinations) ############################################################################### # # Error code distribution # # command line argument: --errorcode-distribution-report # # Example output: # # TCP Response code distribution # status-code request % Byte % # ----------------------------------- --------- ------ -------- ------ # 000 (Used mostly with UDP traffic) 727633 2.93 3625190K 1.97 # 100 (Continue) 4 0.00 687 0.00 # 200 (OK) 20145830 81.19 171223M 95.12 # # # Default: # undef($errorcode_distribution_report); # (no reporting) # # Usage: # $errorcode_distribution_report = [0|1]; ############################################################################### # # Object freshness report # Here you can find information about the freshness of objects in your cache. # # Calamaris looks for freshness tags like 'TCP_HIT', 'TCP_REFRESH_MISS', ... # and make statistics on it. With this information you can optimize the # caching behaviour of your cache depending on the objects content type. # E.g. squid admins could use this information to configure the # refresh_pattern. # # Default: # undef($object_freshness_report); # (no reporting) # # Usage: # $object_freshness_report = [0|1]; # Here you have to define the 'TRANSACTION HEADER' for your cache software! # # Note: the variable $refresh_tags is not used at the moment # Usage: the hash keys have to be one of this (see --input-format): # squid, squid-old, nc, elff, its or nse # Please adjust the 'TRANSACTION HEADER' according your cache manual. # # $xxx_tags{'hash keys'} = [( 'TRANSACTION HEADER 1', # 'TRANSACTION HEADER 2', # 'TRANSACTION HEADER 3' ... )]; # # $fresh_tags: all fresh hits # $stale_tags: all stale misses # $refresh_tags: not used at the moment # $mod_tags: hits which have been modified after an IMS # $unmod_tags: hits which have not been modified after an IMS # # Explanation: # all hits = $fresh_tags + $stale_tags # $stale_tags = $mod_tags + $unmod_tags # # The following list is not complete (as you can see) and may be incorrect. # If there is a need of improvement please notify. #Tags for squid $fresh_tags{'squid'} = [( 'TCP_HIT', 'TCP_MEM_HIT', 'TCP_IMS_HIT', 'TCP_IMS_MISS' )]; $stale_tags{'squid'} = [( 'TCP_REFRESH_HIT', 'TCP_REFRESH_MISS', 'TCP_REF_FAIL_HIT' )]; $refresh_tags{'squid'} = [( 'TCP_CLIENT_REFRESH' )]; $mod_tags{'squid'} = [( 'TCP_REFRESH_MISS' )]; $unmod_tags{'squid'} = [( 'TCP_REFRESH_HIT' )]; #Tags for squid-old $fresh_tags{'squid-old'} = [( 'TCP_HIT', 'TCP_MEM_HIT', 'TCP_IMS_HIT', 'TCP_IMS_MISS' )]; $stale_tags{'squid-old'} = [( 'TCP_REFRESH_HIT', 'TCP_REFRESH_MISS', 'TCP_REF_FAIL_HIT' )]; $refresh_tags{'squid-old'} = [( 'TCP_CLIENT_REFRESH' )]; $mod_tags{'squid-old'} = [( 'TCP_REFRESH_MISS' )]; $unmod_tags{'squid-old'} = [( 'TCP_REFRESH_HIT' )]; #Tags for NetCache 5.5 $fresh_tags{'nc'} = [( 'TCP_HIT', 'TCP_HIT_ACCESS_DENIED', 'TCP_HIT_EJECT', 'TCP_HIT_HIT_PARTIAL', 'TCP_HIT_HIT_VERIFY' )]; $stale_tags{'nc'} = [( 'TCP_HIT_IMS_NOTMOD','TCP_HIT_PRECONDITION_FAILED', 'TCP_MISS_CACHE_VERSION', 'TCP_MISS_VERIFY', 'TCP_REF_FAIL_HIT' )]; $refresh_tags{'nc'} = [( 'TCP_MISS_RELOAD' )]; $mod_tags{'nc'} = [( 'TCP_MISS_VERIFY' )]; $unmod_tags{'nc'} = [( 'TCP_HIT_IMS_NOTMOD' )]; $fresh_tags{'elff'} = [( 'TCP_HIT', 'TCP_HIT_ACCESS_DENIED', 'TCP_HIT_EJECT', 'TCP_HIT_HIT_PARTIAL', 'TCP_HIT_HIT_VERIFY' )]; $stale_tags{'elff'} = [( 'TCP_HIT_IMS_NOTMOD','TCP_HIT_PRECONDITION_FAILED', 'TCP_MISS_CACHE_VERSION', 'TCP_MISS_VERIFY', 'TCP_REF_FAIL_HIT' )]; $refresh_tags{'elff'} = [( 'TCP_MISS_RELOAD' )]; $mod_tags{'elff'} = [( 'TCP_MISS_VERIFY' )]; $unmod_tags{'elff'} = [( 'TCP_HIT_IMS_NOTMOD' )]; ############################################################################### # # measure peak requests # # command line argument: -p [new|old] | --peak-report [new|old] # # Example output: # # Incoming request peak per protocol # prt sec peak begins at min peak begins at hour peak begins at # --- ---- ------------------ ----- ------------------ ------- ------------------ # UDP 0 0 0 # TCP 348 04.Apr 04 04:33:58 3059 04.Apr 04 02:01:18 82479 04.Apr 04 23:00:00 # --- ---- ------------------ ----- ------------------ ------- ------------------ # ALL 348 04.Apr 04 04:33:58 3059 04.Apr 04 02:01:18 82479 04.Apr 04 23:00:00 # # Incoming transfer volume per protocol # proto kB/hour peak begins at # ----- -------- ------------------ # UDP 0 # TCP 1964368 04.Apr 04 22:00:00 # ----- -------- ------------------ # ALL 1964368 04.Apr 04 22:00:00 # # # Default: # undef($peak_report); # (no peak measurement is reported) # # Usage: # $peak_report = ['new'|'old']; # old = make old request-peak mesurement # 'Incoming transfer volume per protocol' is not calculated! # new = make new request&byte-peak measurement # (both slow Calamaris significantly down.) ############################################################################### # # Performance: show throughput data for every 'n' minutes # # command line argument: -P n | --performance-report n # # Example output: # # Performance in 60 minute steps # incomin hit miss direct sibling fetch # date request Byte kB/sec kB/sec kB/sec kB/sec kB/sec kB/sec # --------------- --------- ----- ------- ------- ------- ------- ------- ------- # 04.Apr 04 00:00 20217 211M 8.69 53.23 6.35 7.38 4.03 1.11 # 04.Apr 04 01:00 14685 169M 7.93 77.43 5.16 5.64 2.79 13.18 # 04.Apr 04 02:00 23450 388M 15.45 44.42 13.13 16.09 5.76 1.14 # 04.Apr 04 03:00 15092 284M 10.50 3.76 8.52 8.15 16.98 0.39 # # # Default: # undef($performance_report); # (no performance is reported) # # Usage: # $performance_report = n; ############################################################################### # # Time # adjust the Performance-Report in minutes # # command line argument: -T | --performance-report-adjust # # # Default: # undef($performance_report_adjust); # don't adjust the Performance-Report # # Usage: # $performance_report_adjust = [0|1]; ############################################################################### # # requester: show 'n' Requesters/User, -1 = unlimited # # command line argument: -r n | --requester-report n # # Example output: # # Incoming TCP-requests by host # host request hit-% Byte hit-% sec kB/sec # --------------------------------- --------- ------ -------- ------ ---- ------- # 10.1.1.1 186643 3.80 6366926K 0.22 1 55.18 # 10.1.4.2 86331 0.00 26654655 0.00 0 130.18 # 10.1.1.3 48482 7.43 13294970 20.33 0 53.73 # 10.1.5.10 48474 7.43 13289730 20.34 0 57.84 # # # Default: # undef($requester_report); # (no requester is be monitored) # # Usage: # $requester_report = n; ############################################################################### # # no-lookup # don't look IP-Numbers up # # command line argument: -n | --requester-report-no-dns-lookup # # # Default: # undef($requester_report_no_dns_lookup); # lookup IP-Numbers # # Usage: # $requester_report_no_dns_lookup= [0|1]; ############################################################################### # # use ident information if available (*) # # command line argument: -u | --requester-report-use-user-info # # # Default: # undef($requester_report_use_user_info); # don't use login information # # Usage: # $requester_report_use_user_info= [0|1]; ############################################################################### # # targets for requester: show 'n' targets for every Requester, # -1 = unlimited), implies $requester_report = n (*) # If $requester_report is not set, $requester_report is set to # $requester_report_with_targets. # # command line argument: -R n | --requester-report-with-targets n # # Example: # # Incoming TCP-requests by host # host / target request hit-% Byte hit-% sec kB/sec # --------------------------------- --------- ------ -------- ------ ---- ------- # 10.101.93.111 917 8.07 1529952 12.26 1 1.94 # *.the-arena.de 665 10.68 882366 14.49 0 35.11 # *.gmx.net 93 3.23 397865 15.00 0 66.17 # *.ebay.de 54 0.00 53779 0.00 0 24.69 # # # Default: # undef($requester_report_with_targets); # (no requester is monitored) # # Usage: # $requester_report_with_targets = n; ############################################################################### # # Response Time Diagram: # sum up the time distribution over all objects. # # command line argument: --response-time-report # # Example output: # # TCP-Request duration distribution in msec # time request % Byte % # --------------- --------- ------ -------- ------ # <= 0.1 88936 0.36 80003410 0.04 # <= 0.2 88936 0.36 80003410 0.04 # <= 0.5 88936 0.36 80003410 0.04 # <= 1 482528 1.94 339898K 0.18 # # # Default: # undef($response_time_report); # (no reporting) # # Usage: # $response_time_report = [0|1]; ############################################################################### # # Response Time Interval: # This array defines the time steps, which should be reported in the # 'Response Time Diagram', see above. # # # Default: # @response_time_report_interval = qw(0.001 0.01 0.02 0.05 0.1 0.2 0.5 1 2 5 10 20 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1000000 1e10); # # Usage: # @response_time_report_interval = qw(0.001 0.1 0.2 0.5 1 2 5 10 20 50 100 200 500 1000 2000 5000 10000 20000 50000 1e10); ############################################################################### # # Response Time Limit: # Calamaris calculates an average response time value, which is shown in the cache statistics overview. # Very slow requests (web server) can be skipped, by setting this value. # This value is only recognized, when $response_time_report is set. # # # Default: # $response_time_limit = $response_time_report_interval[$#response_time_report_interval]; # # Usage: # $response_time_limit = 10000; ############################################################################### # # Size-Distribution-Report: # shows size-based distribution of requested # objects, smaller numbers result in more verbose reports. # choose 2, 10 or 100 for useful output. (You can also play # with this ;-)) # # command line argument: -D [2|10|100] | --size-distribution-report [2|10|100] # # Example output: # # object-size (bytes) request hit-% Byte hit-% sec kB/sec # -------------------- --------- ------- ------- ------ ------- ------ # 0-0 138146 33.70 0 0.00 4 0.00 # 1-9 7 0.00 35 0.00 0 0.01 # 10-99 38240 0.00 2772033 0.00 10 0.01 # # # Default: # undef($size_distribution_report); # (no reporting) # # Usage: # $size_distribution_report = [2|10|100]; ############################################################################### # # status: show verbose status reports # # command line argument: -s | --status-report # # Example output: # # Summary # lines parsed: 699415 # invalid lines: 0 # unique hosts/users: 363 # parse time (sec): 136 # # # Default: # undef($status_report); # (no status reporting) # # Usage: # $status_report = [0|1]; ############################################################################### # # show 'n' content-type, 'n' extensions and requested protocols, # -1 = unlimited # # command line argument: -t n | --type-report n # # Example output: # # Requested content-type # content-type request % Byte % hit-% # --------------------------------------- --------- ------ -------- ------ ------ # text/html 223479 31.95 4600042K 47.65 11.02 # text/plain 116291 16.63 1460336K 15.13 0.74 # # Requested extensions # extensions request % Byte % hit-% # --------------------------------------- --------- ------ -------- ------ ------ # 202347 28.93 4720924K 48.90 4.65 # 139819 19.99 1480113K 15.33 5.59 # gif 115411 16.50 186475K 1.93 62.50 # # # Default: # undef($type_report); # (no reporting) # # Usage: # $type_report = n; ############################################################################### # # switch to case-insensitive reporting (useful for extensions-report) # # command line argument: -c | --type-report-ignore-case # # # Default: # undef($type_report_ignore_case); # make the reports case sensitive # # Usage: # $type_report_ignore_case= [0|1]; ############################################################################### ############################# INPUT SECTION ############################### ############################################################################### ############################################################################### # # Logformat type: # sets the type of input logfiles # auto = tries to guess the input format # (This is the Default) # squid = Native-Logfile derived from Squid V1.1.beta26-V2.x # squid-extended = Native-Logfile with log_mime_hdrs enabled # derived from Squid V1.1.beta26-V2.x (*) # or Cisco Content Engines (*) # or Squid with SmartFilter-patch (*) # squid-old = Native-Logfile derived from Squid # V1.1.alpha1-V1.1.beta25 # nc = Squid-style Logfiles derived from NetCache V?? (<5.x) # its = Logfiles derived from Inktomi Traffic Server # elff = Extended Logfile Format (i.e Compaq Tasksmart, Novell # Internet Caching System, NetCache 5.x) # nse = Netscape Extended-1/2 Logfile Format # # command line argument: -f [options] | --input-format [options] # # # Default: # $input_format = 'auto'; # auto detection # # Usage: # $input_format = ['auto'|'squid'|'squid-extended'|'squid-old'|'nc'|'its'|'elff'|'nse']; ############################################################################### # # IP-Filters: # # This item needs the perl Module NetAddr::IP! # The IP-list which should be excluded from reporting or which only should be # monitored (included) is separated by ':' # There are two kind of filters: exclude and include: # # exclude: # all IPs are reported, except IP/range. (*) # command line argument: --ip-filter-exclude List # # include: # no IPs are analyzed, except IP/range. (*) # command line argument: --ip-filter-include List # # List-Format: 1.1.1.1/32:1.1.2.0/24 # 1.1.1.1/255.255.255.255:1.1.2.0/255.255.255.0 # # # command line argument: # --ipfilter-exclude IP/range # --ipfilter-include IP/range # # Default: # undef($ipfilter_exclude); # no IPs are excluded # undef($ipfilter_include); # no IPs are included # # Usage: # $ipfilter_exclude = '1.1.1.1/255.255.255.255:1.1.2.0/255.255.255.0'; # $ipfilter_include = '1.1.1.1/255.255.255.255:1.1.2.0/255.255.255.0'; ############################################################################### # # no input via STDIN # This is useful when reading cache files. # # command line argument: -z | --no-input # # # Default: # undef($no_input); # (calamaris expects logfile via STDIN) # # Usage: # $no_input = [0|1]; ############################################################################### # # Interval # defines which time-interval should be parsed # t has to be the format yyyymmddhhmmss (localtime) # omitting the beginning or ending is allowed. # # command line argument: -I t1-t2 | --time-interval t1-t2 # # # Default: # undef($time_interval); # # Usage: # $time_interval= 't1-t2'; ############################################################################### ############################# OUTPUT SECTION ############################## ############################################################################### ############################################################################### # # Graph colours: # These values cannot be configured by commandline arguments! # If you want to change the default values, you have to use this # configuration items. # # Define the colours of the columns and text/axis/legend/labels. # The colours for Hit-% are automatically darkend. # # Default: # $column1_color = '#6699cc'; # $column2_color = '#ff9900'; # $text_color = '#222266'; ############################################################################### # # image type # Sets the image type to gif, png, jpeg, gd or gd2. Only usefull when # --output-format graph is set. The supported images types are dependend # on your GD::Graph installation. # Calamaris tells you which formats are supported, if an error occurs. # # # Default: # $image_type = 'png'; # # Usage: # $image_type = ['gif'|'png'|'jpeg'|'gd'|'gd2']; ############################################################################### # # output format of the tables # # Better don't play with this ;-), no warranty what happen with the output, if # not used correctly # Please consider: # - you can not change the order of the table columns. # - you can switch off the output of single columns by using the keyword 'off'. # - don't change the numbers or '%'. Do you know, what you are doing? # - you can change the output of Request/sec and Byte/sec by using the # following keywords: # # kbps = kByte/sec # spkb = sec/kByte # bps = Byte/sec # spb = sec/Byte # rps = req/sec # spr = sec/req # rpms = req/msec # mspr = msec/req # off # % # # Default: the output is optimized to 79 character per line. # # This units (keywords) are not influenced by $unit, see below. # Incoming requests by method $formats[3] = [ 30, 9, '%', 'spr', 8, '%', 'kbps' ]; # Incoming UDP-requests by status $formats[4] = [ 30, 9, '%', 'mspr', 8, '%', 'kbps' ]; # Incoming TCP-requests by status $formats[5] = [ 30, 9, '%', 'spr', 8, '%', 'kbps' ]; # Outgoing requests by status $formats[6] = [ 30, 9, '%', 'spr', 8, '%', 'kbps' ]; # Outgoing requests by destination $formats[7] = [ 30, 9, '%', 'spr', 8, '%', 'kbps' ]; # Request-destinations by ${N}-level-domain $formats[8] = [ 26, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Request-destinations by toplevel-domain $formats[9] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # TCP-Request-protocol $formats[10] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Requested content-type $formats[11] = [ 26, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Requested extensions $formats[12] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps', 11, 11 ]; # Incoming UDP-requests by host $formats[13] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Incoming TCP-requests by host $formats[14] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Distribution Histogram $formats[15] = [ 16, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # Performance in $P steps $formats[16] = [ 15, 9, '%', 5, '%', 6, 'kbps', 'kbps', 'kbps', 'kbps', 'kbps', 'kbps' ]; # UDP-Request duration distribution in msec $formats[17] = [ 16, 9, '%', '%', 'mspr', 8, '%', '%', 'kbps' ]; # TCP-Request duration distribution in msec $formats[18] = [ 16, 9, '%', '%', 'mspr', 8, '%', '%', 'kbps' ]; # UDP Response code distribution $formats[19] = [ 36, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; # TCP Response code distribution $formats[20] = [ 36, 9, '%', '%', 'spr', 8, '%', '%', 'kbps' ]; ############################################################################### # # Hostname # Define the name for the Report Output # 'lookup' issues a lookup for the current host # FQDN means, give an full qualified domain name or any name you want. # # command line argument: -H ['FQDN|'lookup'] | --hostname ['FQDN|'lookup'] # # # Default: # undef($hostname); # The report output headline is without any hostname # # Usage: # $hostname= ['FQDN|'lookup']; ############################################################################### # # logo # Here you can define a HTML-string which should be included into the report # head. You can also define a filename, then the file is included into the # report head. It works only in combination with # $output_format = 'html' or 'html,graph'. # # command line argument: -l [string|filename] | --logo [string|filename] # # # Default: # undef($logo); # no logo is included into the html head # # Usage: # $logo= ' HTML-TEXT '; # define string # $logo= './calamaris_head.html'; # or define file ############################################################################### # # Meta # includes the given strings in html-. You can also give a filename, then # the file is included in html-. It works only in combination with # $output_format = 'html' or 'html,graph'. # This is useful to include CSS or JavaScript. It's up to you, to include some # more CSS Tags in the calamaris output. You have to edit the source code. # # command line argument: -M [string|filename] | --meta [string|filename] # # # Default: # undef($meta); # (no meta information is included) # # Usage: # $meta = ''; # define string # $meta ='./calamaris.css'; # or define CSS-file $meta = ' '; ############################################################################### # # output format (comma-seperated list) # (Default is plain formatted text) # mail = mail format # html = HTML format # html-embed = HTML format without HTML-headers # html-frame = HTML format with Frames # graph = enable graphics, needs GD::Graph, only useful with # html, html-embed or html-frame # (see also $output_path) # unformatted = plain unformatted output # # command line argument: -F [options] | --output-format [options] # # # Default: # undef($output_format); # Default is plain formatted text # # Usage: # $output_format = ['mail'|'html'|'html-embed'|'html-frame'|'graph'|'unformatted']; ############################################################################### # # output path # output file # output file prefix # # defines where the output of calamaris is written. # # output_path defines the path where to write, # output_file contains the filename, where the data is stored. # output_file_prefix prepends a pattern to the filename. # # In case of html-embed,graph; html-frame,graph or html,graph output, # the graphics destination is the value of $output_path. If $output_path # is not given, all graphics are written to the working directory. './'. # # If $output_file is not given the Filename is index.html for html-output and # calamaris.txt for plain-output. # # If $output_file_prefix the pattern is prepended to all written files. # # You may use the special pattern # %h (value of $hostname) # %t (the calculated report-timerange) # %% (use this to get a single %) # in all three configuration-directives. # # command line argument: --output-path 'path' # command line argument: --output-file 'filename' # command line argument: --output-file-prefix 'prefix' # # Default: # undef($output_path); # Default is output path is working directory './' # undef($output_file); # Default is index.html or calamaris.txt # undef($output_file_prefix); # Default is no prefix # # Usage: # $output_path= '/path'; # $output_file= 'filename'; # $output_file_prefix= 'prefix'; ############################################################################### # # list Show # Shows only the defined reports (comma-seperated list) in the # specified order. The following numbers are defined (see ./calamaris -h): # 0 Summary # 1 Incoming request peak per protocol # 2 Incoming transfer volume peak per protocol # 3 Incoming requests by method # 4 Incoming UDP-requests by status # 5 Incoming TCP-requests by status # 6 Outgoing requests by status # 7 Outgoing requests by destination # 8 Request-destinations by 2nd-level-domain # 9 Request-destinations by toplevel-domain # 10 TCP-Request-protocol # 11 Requested content-type # 12 Requested extensions # 13 Incoming UDP-requests by host # 14 Incoming TCP-requests by host # 15 Size Distribution Diagram # 16 Performance in n minute steps # 17 UDP-Request duration distribution in msec # 18 TCP-Request duration distribution in msec # 19 UDP Response code distribution # 20 TCP Response code distribution # # Note: only putting out one report does not speed up Calamaris # as the internal operations were done based on the # report-switches. Default: Reports are displayed based on # activated reports. # # command line argument: # -S comma-separated-list | --show-reports comma-separated-list # # # Default: # undef($show_reports); # sort request size # # Usage: # $show_reports = 0,1,2,4,6; ############################################################################### # # Sort Order # changes the sort order in the reports to request size, # default is sorting by number of requests. # # command line argument: -O | --sort-order # # # Default: # undef($sort_order); # sort request size # # Usage: # $sort_order = [0|1]; ############################################################################### # # define the Unit for the Byte-values, else it will be auto # K(ilo), M(ega), G(iga), T(era) # # command line argument: -U option | --unit option # # # Default: # undef($unit); # Default is yoto formatting of unit. # # Usage: # $unit = [K|M|G|T]; ############################################################################### # # Define the graph size in pixel. # The image ratio (width : height) is 3 : 2. # # Default: # $width = 600; # the graph has a size of 600x400 Pixel # Usage: # $width = 300; ############################################################################### # # How many datasets should be drawn on the graph. # $x_scale = 30 is a good value, play with this -> no warranty what happens # if $x_scale is too big! # # Default: # $x_scale = 30; # Usage: # $x_scale = 10; ############################################################################### # # Generate an index-page for all reports that match the # output_*-Directives. # # Default: # undef($generate_index); # don't generate an index # # Usage: # $generate_index = [0|1]; ############################################################################### ############################# CACHE SECTION ############################### ############################################################################### ############################################################################### # # input-file # input-datafile for caching, to add many files separate them with a ':'. # # command line argument: # -i 'inputfile.dat' | --cache-input-file 'inputfile.dat' # # # Default: # undef($cache_input_file); # no input from cache file # # Usage: # $cache_input_file= 'file1:file2:file3'; ############################################################################### # # output-file # output-datafile for caching, can be the same as $cache_input_file # # command line argument: -o filename.dat | --cache-output-file filename.dat # # # Default: # undef($cache_output_file); # no cachefile will be written # # Usage: # $cache_output_file = 'cache.dat'; ############################################################################### ############################## MISC SECTION ############################### ############################################################################### ############################################################################### # # benchmark # prints a hash-sign (#) to STDERR for each n lines # processed # # command line argument: -b n | --benchmark n # # # Default: # undef($benchmark); # don't show hashes (#) # # Usage: # $benchmark = n; ############################################################################### ############################# DEBUG SECTION ############################### ############################################################################### ############################################################################### # # make some small tests (only for programmer) #$test = 1; ############################################################################### # # verbose # print information what Calamaris is doing. Useful for debugging. # # command line argument: -v | --verbose # # # Default: # undef($verbose); # don't write debug information # # Usage: # $verbose = [0|1]; ############################################################################### # #Copyright (C) 1997-2006, 2013, 2015, 2017, 2021 # Cord Beermann. Authors: Cord Beermann and Michael Pophal #Calamaris comes with ABSOLUTELY NO WARRANTY. It is free software, and you are #welcome to redistribute it under certain conditions. See source for details. #Calamaris-Homepage: https://Calamaris.Cord.de/ # ############################################################################### calamaris-2.99.4.7/CONTRIBUTORS0000644000175000017500000000622714161616434014255 0ustar cordcordThanks to these contributors, bug reporters, and feature requesters: John Heaton Andreas Lamprecht Kenny Ng Claus Langhans Andreas Jung Ernst Heiri Shamil R. Yahin Thoralf Freitag Marco Paganini Michael Riedel Kris Boulez Mark Visser Gary Palmer Stefan Watermann Roar Smith Bernd Lienau Gary Lindstrom Jost Krieger Gerd Michael Hoffmann Gerold Meerkoetter Iain Lea Emmanuel Adeline John Line Christos Cheretakis Ryan Donnelly Richard Vaughan Jonas Luster Clare Lahiff Toni Andjelkovic Chris Teakle Dancer Vesperman Vincent ? Elrond ? Holger Marzen Panagiotis Christias Patrik Rak Steve Snyder Michael Copeland Warren Brown Andy Nik Frank Roechter Antonio Casado Rodríguez Pavol Adamec Ram Cherukuri Marco Koch Stephen Welker Christian Niederdorfer Klaus Brinkmeyer Filip ? Matt Hubbard James Crocker Enrico Ardizzoni Shawn Switenky Jarkko Saloranta Jigar Rasalawala Philipp Frauenfelder Alexey Markov Mark Güthling Sergey Zarubin Helge Oldach Michael R. Schwarzbach Radu - Eosif Mihailescu Steffen Sledz Kenytt Avery SO Kwok Tsun Chris Knight ycdtosa ? Peter W. Osel Pawel Worach Franck Bourdonnec Chris Clemson Scott Tregear Sythos ? Dmitriy Daniel Echeverry Laurent Licour Panagiotis Christias Marc Dostal Julien Chiaramello Jorge Redondo calamaris-2.99.4.7/CHANGES0000644000175000017500000027112314161616434013367 0ustar cordcordcommit b61e5e60e12976e9c2f7666edd12f80a199a8535 Author: Cord Beermann Date: Sun Dec 19 12:26:03 2021 +0100 new version: 2.99.4.7 - fix: logfile determination for squid (reported by Kamil Jonca ) - update Copyright years - update hyperlinks commit ce906a976b7ce5cc72e0bdbc0ad544bd6e23313e Author: Cord Beermann Date: Sat Nov 11 12:14:30 2017 +0100 * protect all character 'x' operations against negative numbers. (thanks to Jorge Redondo ) * remove sprintf where it is not needed. * fix a typo in the manpage. commit ee41217498f4b96bde716a3a2aee6f06c6b69730 Merge: f815e15 840c36d Author: Cord Beermann Date: Mon Oct 23 14:38:01 2017 +0200 Merge branch 'master' of github.com:C0RD/calamaris commit f815e1587adb698745548ada4255ce20234baaf3 Author: Cord Beermann Date: Mon Oct 23 14:33:36 2017 +0200 * fix negative argument to length(). Reported by Julien Chiaramello commit 840c36de07a2b6e84ddcbbe2c5a29f0f4d1c2b41 Author: Cord Beermann Date: Thu Nov 24 11:39:58 2016 +0100 * add new Hierarchy Method STANDBY_POOL as Parent-Miss. (thanks Marc Dostal ) commit c22ab4ccdc12c4c10ad2e962bf03adfa6ff29bad Author: Cord Beermann Date: Tue Jul 5 18:09:24 2016 +0200 * update Contributors commit 0e67f78c032185843b08ec34f9b5dc155a0f309e Author: Cord Beermann Date: Tue Jul 5 18:02:40 2016 +0200 * fix a missing variable (reported by Panagiotis Christias ) commit 22aee6f247c327be5f343cfe53e976f8b9e1f4c6 Author: Cord Beermann Date: Sat Jul 25 13:25:33 2015 +0200 * moved list of Contributors to its own file. commit 77ef423debd0dfe4004bc80a135076e6a839fa59 Author: Cord Beermann Date: Fri Jul 24 22:32:37 2015 +0200 * load Socket only if we need to resolve IPs. commit df735c57f593c5a35b22401cfbb59813fe6e19fc Author: Cord Beermann Date: Fri Jul 24 21:56:20 2015 +0200 * rework DNS-resolver to handle IPv6 * add more HTTP-response codes. * move Sys::Hostname that we only load it when needed. * change 'use lib' to search graphic-libs in the same dir as calamaris itself. we expect that calamaris runs out of a directory named calamaris. (or it is installed in the usual perl-search-paths.) commit 7a9dfda916cf464d801b84c92453a561e664ee1e Author: Cord Beermann Date: Wed Jul 22 21:37:51 2015 +0200 * bump version to 2.99.4.5 commit a91e0d949c051b1768a8e30aa7ba1f1e2375e486 Author: Cord Beermann Date: Wed Jul 22 19:30:23 2015 +0200 * check and create if nessecary the output-path commit 38d9abf9941939605eab6324febf9879823d10de Author: Cord Beermann Date: Wed Jul 22 17:47:58 2015 +0200 fix PWD commit 74c743733961ebcd4f74d04da25abb75732f1bb5 Author: Cord Beermann Date: Tue Jul 21 07:38:16 2015 +0200 * drop RCS-Id, we are on Git now. * reworked use-statements for non-standard-perl-modules + remove /usr/local from path + make more helpful messages if a module hasn't been found * fix typo commit 4de42ffeab1caf4a5184a4a590eb198441955c5a Author: Cord Beermann Date: Mon Jul 20 20:57:10 2015 +0200 * minor refomatting * fix one description * drop RCS-Tag commit 9960d4fc2c4d68c3b6a186be20b022e859a4a147 Author: Cord Beermann Date: Wed Jul 15 23:29:37 2015 +0200 * remove double report. commit dd4aefae7e984f7f70a704878049e5e484a14344 Author: Cord Beermann Date: Wed Jul 15 23:12:45 2015 +0200 * fix a bug in calculation of the performance-table (patch by Laurent Licour ) * adjust size of Calamaris statistic to handle large logfiles correctly (reported by Enrico Ardizzoni ) commit 728f7b9ffaacb9057560ab3d1f0793d208c078ed Author: Cord Beermann Date: Tue Jun 30 21:39:33 2015 +0200 * add TCP_REDIRECT and TCP_REFRESH_UNMODIFIED to HIT-Category (thanks to Yuri Voinov ) * fix a formatting error in Proxy statistic. commit 78b49eb4f4c7cc57cc62ac6c095fbffc98c0abef Author: Cord Beermann Date: Sun Jun 28 20:28:59 2015 +0200 * adopt a fix for perl deprecation-messages from Debian * fix another perl deprecation-message. * adopt manpage-fixes from Debian by Daniel Echeverry * add another year and shrunk the years for copyright * add Github-Link * increment version to 2.99.4.2 for release commit 8c4bc31f7a045812cf1655664bf25ac5d21839b8 Author: Cord Beermann Date: Sun Jun 28 14:33:54 2015 +0200 fix for new upstream status ORIGINAL_DST by Dmitriy commit bdd034b8b14f914c5f3b040680c21259aee6f9ed Author: svn Date: Thu Dec 19 06:31:46 2013 +0000 + new unreleased version 2.99.4.1 + updated copyright year + added Squid3-hierachy method PINNED (reported by many users.) + added workaround for sloppy Squid-Logs with leading space. + changed defined %hash to %hash to avoid deprcation warning. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@203 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3a698e30f71e7115dbc3056f25f2a8e406fbae30 Author: cord Date: Sun Mar 19 17:59:03 2006 +0000 introducing EXAMPLES for Calamaris v3 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@202 af268522-00f2-45aa-b56c-050e69c5c3bf commit 064916cfad18225da3d7013539282d46cb5adb4c Author: cord Date: Sun Mar 19 17:58:25 2006 +0000 * fixed typos * again reflecting all changes of Calamaris. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@201 af268522-00f2-45aa-b56c-050e69c5c3bf commit b5c8dad806f5a67515125af3f642fb3e90ceb891 Author: cord Date: Sun Mar 19 17:52:48 2006 +0000 * reflecting the changes of Calamaris + HTML-Frame-Output + mention localtime in the timerange option + graphics-format + output-* + generate-index + omitting wrong s git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@200 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8565dfc30db4e0b6f9fe1fb40a5e0ce6de550432 Author: cord Date: Sun Mar 19 17:28:02 2006 +0000 * Release V2.99.4.0 * don't use rcs-version-number anymore. now use an own variable * fixed error-messages on missing perl-modules * added rudimentary BlueCoat-Support (thanks to Michael Riedel ) * added --output-file-prefix -option * added %h (hostname) and %t (timerange) placeholders for --output-* -options. * added --generate-index -Option * updated HTML-Output from HTML 4.01 Trans to XHTML 1.0 Strict * added Jumbo-Patch by Michael Pophal + nicer HTML-Output including CSS (should be tidy(1)-clean) + more Reports + HTML-Frame-Output + GRaphic-Format depending possible in all formats libgd supports. + workaround a bug when Cachefiles contain -Entries. * fixed some division by zero issues * Timerange now in localtime (switched from gmt-time (reported by Scott Tregear )) * fixed a problem with Oops-Logfiles (reported by Sythos ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@199 af268522-00f2-45aa-b56c-050e69c5c3bf commit b76d2e974ff8daf425537ac00843c147d1ebd51f Author: cord Date: Sun Mar 19 16:11:25 2006 +0000 no changes git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@198 af268522-00f2-45aa-b56c-050e69c5c3bf commit 61500bc6f0058c477051f7e7970c056fd5622a6c Author: cord Date: Sun Mar 19 16:10:53 2006 +0000 * added content-type bug. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@197 af268522-00f2-45aa-b56c-050e69c5c3bf commit 34c10429f6ee11d980a5bee66e3544767b0e90cb Author: cord Date: Thu Dec 23 20:16:10 2004 +0000 * Patch by Michael Pophal: + reflect adding of the configuration-option for the graphics-format git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@196 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6b0b2c3064783359f324029719b12790279fb9a3 Author: cord Date: Thu Dec 23 20:05:27 2004 +0000 * Patch by Michial Pophal: + added configuration-option fpr the graphics-format + corrected the report_index for the new peak-report. + fixed handling of % in usernames. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@195 af268522-00f2-45aa-b56c-050e69c5c3bf commit 19fbf0be8030c77bbedecebb15b7ac8b726b9b2f Author: cord Date: Thu Dec 23 20:01:03 2004 +0000 clarified installation instructions. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@194 af268522-00f2-45aa-b56c-050e69c5c3bf commit bda37464a39c8916d79debe4457595ce578dd168 Author: cord Date: Wed Sep 22 20:39:15 2004 +0000 * added $output_file * clarified $output_path git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@193 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0d5f36dc0c37439076297c2c76ce3c611d6ba9e7 Author: cord Date: Wed Sep 22 20:37:29 2004 +0000 * added --output-file git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@192 af268522-00f2-45aa-b56c-050e69c5c3bf commit b9e1f76f5160407e67f9e784a481202707254d06 Author: cord Date: Wed Sep 22 20:34:29 2004 +0000 * fixed a bug in the benchmark-switch (reported by Chris Clemson * added a --output-file-switch to alter the filename for --output-path (suggested by Peter W. Osel ) * fixed a warning for usinf graph without --output-path git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@191 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3fb88104c3d1f9b0270f70790a251001b520597f Author: cord Date: Wed Sep 22 20:27:05 2004 +0000 * reflect the inclusion of Michael Pophals perl-modules which are dual-licensed GPL and Perl Artictic License. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@190 af268522-00f2-45aa-b56c-050e69c5c3bf commit 714f2ac6bb249f0cf47aa9aab67f979b3751cf0b Author: cord Date: Sat Sep 18 11:03:30 2004 +0000 * added Version Id. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@189 af268522-00f2-45aa-b56c-050e69c5c3bf commit 25a94c4f7794989f7d2962f59c131ac95cc2f2a1 Author: cord Date: Fri Sep 17 21:04:44 2004 +0000 * fixed a typo. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@188 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9bca87ab256f2b2c46c99f59b09d70c757be524b Author: cord Date: Fri Sep 17 21:03:50 2004 +0000 * added bug-workaround from Calamaris v2 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@187 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3d9fbfbf76e40bebab1724961771b3beede30009 Author: cord Date: Fri Sep 17 21:02:30 2004 +0000 * all errors now show which program caused them. * only try to graph if $xaxis is set. * only try 'most something' if $maxi and $xaxis[$maxi] is set. * only divide in removezerotime if divisor is != 0. * moved interval-sanity-check down behind interval-conversation. * define $opt_domain_report_limit if unset. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@186 af268522-00f2-45aa-b56c-050e69c5c3bf commit 443332ace45fd532378990d8642d13bc23c714b2 Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Wed Sep 15 21:51:11 2004 +0000 This commit was manufactured by cvs2svn to create branch 'unlabeled-2.99.1'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@185 af268522-00f2-45aa-b56c-050e69c5c3bf commit c5f220ba5a66db52411f8c3d9eb00266074f5c07 Author: cord Date: Wed Sep 15 21:51:10 2004 +0000 * added Michael Pophal as Co-Author, he provided a jumbo patch which + adds graphics to Calamaris + adds a new report regarding duration distribution + adds a new report regarding server Response code distribution + extends information of the Requested extensions report + extends most other reports + adds an ipfilter-function + changes the cache-file-format + adds a config-file * removed old bug-workaround-options. * switched to long-options (short-options still work) * added a domain-report-limit (suggested by Franck Bourdonnec ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@184 af268522-00f2-45aa-b56c-050e69c5c3bf commit 09197273f455af3ae803406f7dfe91e403c4e1bd Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Wed Sep 15 21:30:47 2004 +0000 This commit was manufactured by cvs2svn to create branch 'unlabeled-3.0.0'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@183 af268522-00f2-45aa-b56c-050e69c5c3bf commit c9dfd06ede992c7a66b3ff0dc04916da9901d396 Author: cord Date: Wed Sep 15 21:30:46 2004 +0000 * reflect the calamaris-changes in the manpage * new options added. * longoptions and configuration-file-options added. * tried to use a more sane grouping of the options. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@182 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4dc6780317d112077c2a0dcb408379a1c7b8ff95 Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Wed Sep 15 21:06:48 2004 +0000 This commit was manufactured by cvs2svn to create branch 'unstable'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@181 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5a50d2288c4d7efcb55a4de2fe2a6e59a5871a9e Author: cord Date: Wed Sep 15 21:06:47 2004 +0000 Initial Calamaris-Config-File. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@180 af268522-00f2-45aa-b56c-050e69c5c3bf commit a20ed658f73efde5e50a6fe6b33545724abe7477 Author: cord Date: Wed Sep 15 21:02:13 2004 +0000 Extended perl-Modul by Michael Pophal git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@179 af268522-00f2-45aa-b56c-050e69c5c3bf commit 7ef87f92a3fdbacf77377c0f0c6d05a27e550fa9 Author: cord Date: Wed Sep 15 20:59:39 2004 +0000 Initial revion of the conversion program git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@178 af268522-00f2-45aa-b56c-050e69c5c3bf commit fa218f46b2658bb29fb40c58f63530e8f24cec58 Author: cord Date: Wed Sep 15 20:58:46 2004 +0000 * splitted old README into 5 seperate files. * updated the suggested perl-Version. * reworked Installation-Instructions (thanks to Michael Pophal ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@177 af268522-00f2-45aa-b56c-050e69c5c3bf commit c85d4a0d099a7ec6022cffffe4e7d6bea5bcf05b Author: cord Date: Wed Sep 15 20:56:00 2004 +0000 * splitted old README into 5 seperate files. * added a note about an Installation-Routine * removed suggestion about limiting domain-reports. * added a comment to a suggestion for the Performance-Report. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@176 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5d0ace80d06979bce479d8aec5dc5253c3145765 Author: cord Date: Wed Sep 15 20:51:43 2004 +0000 * splitted old README into 5 seperate files. * removed notes about old legacy-bugs. * added a note about the new cachefile-format. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@175 af268522-00f2-45aa-b56c-050e69c5c3bf commit 953fb04334ac6e1f70ac10dd16c32d4da1bae27d Author: cord Date: Wed Sep 15 20:46:31 2004 +0000 * splitted old README into 5 seperate files. * extended the History of Calamaris * updated links to NetBSD and FreeBSD-Packages * removed dead link for rpm-Packages. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@174 af268522-00f2-45aa-b56c-050e69c5c3bf commit d00ae75239772b717b533145ee5b690ec46eef6c Author: cord Date: Wed Sep 15 20:41:58 2004 +0000 * added a note that the EXAMPLES-File isn't updated yet. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@173 af268522-00f2-45aa-b56c-050e69c5c3bf commit efdc32245de875ce8463e7543c3455be62a8fabd Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Sun Jun 6 16:29:03 2004 +0000 This commit was manufactured by cvs2svn to create tag 'stable'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@172 af268522-00f2-45aa-b56c-050e69c5c3bf commit c8f0b0d360803794e0d4daecc8ae10a0e8c74933 Author: cord Date: Sun Jun 6 16:29:02 2004 +0000 * documented a problem with Logfiles from accelerated proxies. (reported by Pawel Worach ) * added a feature Request (requested by Ahjmad Kamal ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@171 af268522-00f2-45aa-b56c-050e69c5c3bf commit a3bb80f2c91115361cae210568d7112228fcd78f Author: cord Date: Sun Jun 6 16:26:14 2004 +0000 * added 2004 to year-lines * changed Michael Pophals Mailadress * added sanity-check for time-interval-option (Michael Pophal ) * changed interval-display (Michael Pophal ) * added x-hiername for NetCache-Logparsing. (Peter W. Osel ) * added fix for iPlanet Web Proxy Server (Pawel Worach ) * moved CARP from HIT to MISS section (Michael Pophal ) * added a generation time stamp and reformatted Text-Output-Header. (Michael Pophal ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@170 af268522-00f2-45aa-b56c-050e69c5c3bf commit b2c87b73372a6664df63ac6a9bed20f7829f576c Author: cord Date: Tue Mar 2 20:17:24 2004 +0000 * added a suggestion from Alain Williams for a shorter and easier catting of Logfiles. * fixed Gottfried Hamms squidrep-example. Fixes sent in by Hanno 'Rince' Wagner . git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@169 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8ae6f608776b2e7ce77d00a3ce61b2081b17f9e1 Author: cord Date: Wed May 14 21:22:37 2003 +0000 * added new -M-switch. * fixed some -m and -w examples, they are replaced by -F in the last version. * bumped refered Calamaris Version. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@168 af268522-00f2-45aa-b56c-050e69c5c3bf commit a4eb3112e1a109db06c38e2b5164dae38aaeed7a Author: cord Date: Wed May 14 21:13:55 2003 +0000 * added a -M (Meta) switch to add free defined strings to html-. This switch may be useful to provide stylesheets to the html-report. (suggested by ycdtosa ? ) * Heavy tested and fixed problems with 'Division by zero'-errors (with broken logfiles caused by bugs of some Proxyservers.) (reported by Chris Knight ) While fixing those problems i removed the .00..001 workarounds with a correct solution. * found that .ru (Russia) now mainly uses 2nd-level domains, so i removed that from the 3rd-level-group of TopLevelDomains. * fixed warnings in HTML-Output, so now that will also be correct HTML. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@167 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5fe97f31ba2a678389194b6e3c9beee5ecaaebb9 Author: cord Date: Wed May 14 21:00:25 2003 +0000 * Clarified the RedHat-Bug a bit (triggered by a bug report from Massimo Carnevali ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@166 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9839327605bd7094c6aa4c99feefe5390059872a Author: cord Date: Sun Feb 9 00:06:59 2003 +0000 * added the new -F-switch and pulled the -w, -m, -W-switches. * cleaned up a little. * bumped referenced version to 2.57 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@165 af268522-00f2-45aa-b56c-050e69c5c3bf commit 737c2a13dd4d72e52252216965fa2cb3068478e0 Author: cord Date: Sat Feb 8 23:55:49 2003 +0000 * Holger Marzen requested an output-format which he can use to parse afterwards. -F unformatted is the result. if you use -F unformatted along with -U, the byte values are calculated in the given Unit, and displayed without indication along with the numbers. the indication moves up to the header of the report. * as announced in the README i converted -m -w and -W also into the new -F-switch. so you now have to use -F mail, -F html and -F html-embed. For now the old switches will still work, but Calamaris puts out warnings about that. The switches defunct in the first release of '04. * I deleted (as scheduled) a warning about -N f which has been replaced by -N -1 * I pushed back removal schedules for Cachefile-Workarounds to the end of the year. * code-cleanup. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@164 af268522-00f2-45aa-b56c-050e69c5c3bf commit f1d4f6d481d3c6c847dfbaecae85b64ac4ce7643 Author: cord Date: Sat Feb 8 23:06:07 2003 +0000 * removed note about pending changes in the output-options. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@163 af268522-00f2-45aa-b56c-050e69c5c3bf commit 7a58b5f0aca083c2d80c0f25ffcd03aaa6e900d0 Author: cord Date: Sat Feb 8 22:57:24 2003 +0000 * changed the examples to the new output-switch syntax git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@162 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4c90f2faffff1d348dce6ffd9a10504025eb52b0 Author: cord Date: Sun Jan 19 19:47:09 2003 +0000 * fixed a bug in error-check for obsolete input-formats. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@161 af268522-00f2-45aa-b56c-050e69c5c3bf commit 80aae2d17ad57d62958872f10de37e68275ab14b Author: cord Date: Sun Jan 19 16:58:33 2003 +0000 * reflect the chneges in input-formats in the manpage. * bumped refered Calamaris-Version-number * added 2003 to the copyright git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@160 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3dfa899ba07d942115a3da8fd8befa10c1aa842a Author: cord Date: Sun Jan 19 16:57:32 2003 +0000 * replaced 'squid-mime' and 'squid-smartfilter' input formats with 'squid-extended' which is also usable for Cisco Content Engines Logfiles. (initial patch from Kenytt Avery ) * added an error for users of the replaced input formats. * fixed parsing of NetCache NetApp/5.2 Logfiles. (patch by SO Kwok Tsun ) * added 2003 to the copyright-notice * added/changed <> to all mailadresses git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@159 af268522-00f2-45aa-b56c-050e69c5c3bf commit d10432f4d74acb9b9c0d9dce7c0eea248af4433c Author: cord Date: Sun Jan 19 16:52:16 2003 +0000 * added Cisco Content Engines * added <> to all mailadresses * modified the SmartFilter-comment * added a wishlist-item 'limit reports to a minimum number of transactions' requested by Franck Bourdonnec git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@158 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9d50818ca62e84cf1b770e81d325239ffb997722 Author: cord Date: Sun Jan 19 16:50:03 2003 +0000 * added <> to all mailadresses. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@157 af268522-00f2-45aa-b56c-050e69c5c3bf commit d98fd5a0de89ae1033abb0c05f17e726c5266965 Author: cord Date: Sat Nov 23 17:53:48 2002 +0000 * fixed small bug with new option. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@156 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6af7d9a20aca9d0d53d1d3f19772711a29d9552e Author: cord Date: Sat Nov 23 17:38:42 2002 +0000 * added new Time-Interval-Option. * bumped version-number for calamaris git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@155 af268522-00f2-45aa-b56c-050e69c5c3bf commit f24d82a26131858f6b64fb079a5eabddea2844b3 Author: cord Date: Sat Nov 23 17:37:58 2002 +0000 * added a comment regarding a RedHat 8.0-Problem. * changed comment about SmartFilter. * removed wishlist-item Timerange. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@154 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5bc4347d4e18f85198592b3225c6f7f765ba598a Author: cord Date: Sat Nov 23 17:35:11 2002 +0000 * added an Time-Range-Interval (first suggested by Steffen Sledz (sledz@zone42.org)) * rewrote internal-help-information. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@153 af268522-00f2-45aa-b56c-050e69c5c3bf commit cbafc999642f37034efbb75ae30708aa905ad999 Author: cord Date: Wed Aug 28 16:58:22 2002 +0000 * re-added cache-bug workarounds. * added warnings for the reports, so everyone could know about problems with old cache-files. * fixed a perl-warning which appears in ascii-reports error-section (found by Michael Pophal (michael.pophal@siemens.com)) * moved the error-section to the top of the report. It now also produces a valid HTML-Table. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@152 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1920357b013edba0ebeaf7a7a2893fa21fe0f9f4 Author: cord Date: Wed Aug 28 16:54:56 2002 +0000 * spelling fixes. * added a note about (not) announcing spy-features. * re-added the statement about fixed cache-bugs. * added a workaround for broken SmartFilter-Logfiles. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@151 af268522-00f2-45aa-b56c-050e69c5c3bf commit dc9d2f8ca0a0de0596324ccb52a5ce6cc8f52a7a Author: cord Date: Fri Aug 2 20:15:23 2002 +0000 + fixed a bug in cache-file-writing. other-lines in host-related sub-reports in the requester-reports were put out with a missing field, which makes it impossible to read them in again. However: this part of the reports is not the default so this won't hit many users. I put a workaround in, which normally should recover 'broken' cachefiles without data-loss. (This one is reported by Radu - Eosif Mihailescu (rmihailescu@lumina.ro)) + removed some old bug-workarounds. + moved the Error-report to the Top of the reports. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@150 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3ec63d024261e770fa530159551d8924663b4a79 Author: cord Date: Fri Aug 2 20:06:20 2002 +0000 + removed note about a workaround. which is now removed from the source. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@149 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0dd0e7906c656477c6d419729c9afb538f90b167 Author: cord Date: Mon Jun 10 19:48:03 2002 +0000 + reflected change in -N-switch from f to -1 + bumped version Number to 2.50 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@148 af268522-00f2-45aa-b56c-050e69c5c3bf commit 7a083d8b968872032916d824ebdd10623deb5911 Author: cord Date: Mon Jun 10 19:46:55 2002 +0000 + fixed a problem with the new -N-switch. changed the f-value to -1 to make it more consistent to the other switches. + enabled IPv6-IPs. Calamaris now accepts IPv6-Ips and is able to resolve encapsulated IPv4-Ips. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@147 af268522-00f2-45aa-b56c-050e69c5c3bf commit 42b17113456d7962a38b80ffcb5fb948829e0f9b Author: cord Date: Mon Jun 10 19:41:05 2002 +0000 + changed comment on IPv6: Calamaris cannot resolve real IPv6-IPs yet. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@146 af268522-00f2-45aa-b56c-050e69c5c3bf commit b5f2fc98edb1538d62e25e1bc34d1536a7542f58 Author: cord Date: Wed Jun 5 17:46:21 2002 +0000 + added a statement about the net-yet supported IPv6 + added plan to change output-options. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@145 af268522-00f2-45aa-b56c-050e69c5c3bf commit b9bb70f13a570a893cd74e2509351f94c29390c8 Author: cord Date: Wed Jun 5 17:34:16 2002 +0000 + added new -W-option. + bumped calamaris-version-number. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@144 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6381eb509f920b185f13659a2196c31c5e674813 Author: cord Date: Wed Jun 5 17:31:21 2002 +0000 + fixed a bug with %-signs in the url, which Calamaris tried to expand internal. (reported by Sergey Zarubin (serge-home@yandex.ru)) + Helge Oldach (calamaris@oldach.net) submitted a patch which fixes a problem with syntactical-wrong html-output, and also added a -W-switch to produce HTML-Output without HTML-Headers, so it can used for Server-Side-Includes. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@143 af268522-00f2-45aa-b56c-050e69c5c3bf commit dce5aecaabc83e2e717c5976b996fdf2bbdf1645 Author: cord Date: Wed May 29 20:13:06 2002 +0000 + changed 3rd-level to N-level-reports. + bumped calamaris-version to 2.48. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@142 af268522-00f2-45aa-b56c-050e69c5c3bf commit 47a5015b6c29b869802eb1f18c38ffe5116fb7b8 Author: cord Date: Wed May 29 20:10:51 2002 +0000 + changed -3-switch to -N, which makes it possible for the user to define how many levels of URL-Hosts should be displayed. -Nf displays all Host-Components. (requested by Mark Güthling (privat@mague-pcservice.de)) + changed behaviour when wrong switches are submitted. Now there will be only a one-line hint will be displayed. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@141 af268522-00f2-45aa-b56c-050e69c5c3bf commit c1b40013db61eaf0851400fa5e2cd4b0a4499b91 Author: cord Date: Thu May 23 20:26:26 2002 +0000 + fixed problem with dynamic help, which happened if Calamris is run without -a or -P-option. (reported by Steve Snyder (swsnyder@home.com)) + fixed bug with -m -option. Mail-Subject wasn't printed out in the correct order. (reported by Philipp Frauenfelder (philipp.frauenfelder@swissonline.ch)) + found a problem with 'Incoming TCP-requests by status'. It wasn't displayed if all requestes were classified as ERROR. (found with the help of Alexey Markov (markov@crpi.ru)) + concentrated some Regexps. + cleaned even more up ;-) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@140 af268522-00f2-45aa-b56c-050e69c5c3bf commit cebbde2b4088a7925260d11392eee3ab69e9a3b9 Author: cord Date: Fri May 17 20:49:10 2002 +0000 + added documentation for the new -S and -3 options. + bumped referenced Calamaris-Version-Number. + cleaned up. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@139 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5a4cd3283d857b5032be0ec68697c3128ba3c2a0 Author: cord Date: Fri May 17 20:47:52 2002 +0000 + added third-level-switch (requested by Shawn Switenky (S.Switenky@telesat.ca)) + added seperate on/off-switching and sorting for all reports (requested by Jarkko Saloranta (jjs@kpo.fi) a long time ago, and Jigar Rasalawala (jrasalawala@fourelle.com)) + bugfixed Netscape-Proxy-Logfiles. The months were off-by-one. + cleaned up. made Calamaris better perl?! ;-) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@138 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1367938b597dbbd97211329f249d77364628b8fa Author: cord Date: Fri May 17 20:33:24 2002 +0000 + added Squid with SmartFilter-Patch to the supported Logfiles + added a statement about broken Squid-Smartfilterpatch-Logfiles. + added a statement for 0-0-bytes lines in the distribution histogram + removed wishlist item 'seperate on/off switching of incoming UDP/TCP-Requests' + removed wishlist item 'n-level requester report' git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@137 af268522-00f2-45aa-b56c-050e69c5c3bf commit f50f28f52d14457e34ffea8603e4a9bd9a67417e Author: cord Date: Fri May 17 20:30:13 2002 +0000 + cleaned up a little bit. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@136 af268522-00f2-45aa-b56c-050e69c5c3bf commit ce1b3a671b0242830cdbf385647ef6ad261b74ba Author: cord Date: Fri Jan 25 21:25:11 2002 +0000 - added 'squid-smartfilter'-Input-Format. - bumped Version-Number to 2.45 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@135 af268522-00f2-45aa-b56c-050e69c5c3bf commit a171a41076d26ad424691c15bedbc9a269ab71d1 Author: cord Date: Fri Jan 25 21:24:18 2002 +0000 - added 'squid-smartfilter' input format (thanks to James Crocker (jcrocker@menasha.com)) - fixed/added the new Netcache V5.2-Logfile-Support (thanks to Enrico Ardizzoni (enrico@unife.it)) - added warnings and workarounds to the 'eating-all-memory'-problem in peak-reports (thanks to John Line (webadm@info.cam.ac.uk)) - corrected order of shorcuts in HTML-output. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@134 af268522-00f2-45aa-b56c-050e69c5c3bf commit 67ea86f5dcc31d6e77270b8560c523f9748d7e19 Author: cord Date: Fri Jan 25 21:19:05 2002 +0000 - changed notes about peak-reports and unsorted input - removed note about Calamaris eating up all memory, as that problem is found and fixed. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@133 af268522-00f2-45aa-b56c-050e69c5c3bf commit dd59ad16b14c758a3edae1e0168ec032e4b5a8af Author: cord Date: Fri Jan 18 18:29:26 2002 +0000 - added documentation about the Debug-switch -L git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@132 af268522-00f2-45aa-b56c-050e69c5c3bf commit d0fafcb3a109580768ce94db77dd06607e53b71c Author: cord Date: Fri Jan 18 18:28:53 2002 +0000 - fixed a bug in the new -D-option. now you should be able to set it yourself. (fix by John Line (webadm@info.cam.ac.uk)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@131 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9326b69fd5289a1ea482ed2d0fddfe94631ebb0b Author: cord Date: Fri Jan 18 18:27:13 2002 +0000 - removed the part about a probably buggy input-file guessing from the Bug-section. It's in there for months and nobody complained about it. - added a notice about a possible bug somewhere else, causing Calamaris to eat all your Memory. Reason unknown yet. Hints welcome. (reported by John Line (webadm@info.cam.ac.uk)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@130 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1be2faf39377cb467b537329c3a2febc129b016e Author: cord Date: Thu Jan 17 21:04:34 2002 +0000 * added -D-option. * clarified NetCache-Versions. * fixed typo. * bumped Version-Number for Calamaris * extended Copyright notice. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@129 af268522-00f2-45aa-b56c-050e69c5c3bf commit d2c16fac9cd5bc7b084520c66bd59e8cacbdb135 Author: cord Date: Thu Jan 17 20:55:42 2002 +0000 * expanded Copyright-Notice. Hey! Calamaris is 5 years old! * added a new report about size-based Distribution of objects. (suggested by Gerold Meerkoetter (gerold@noc.fh-lippe.de)) * the -a-switch contains the new switch -D * clarified NetCache-Versions. (thanks to Stephane Lentz (Stephane.Lentz@ansf.alcatel.fr)) * added a -L-switch for debugging purposes (idea by Matt Hubbard (m.hubbard@ic.ac.uk)) * fixed 'gt' vs. > -bug in invalid counter (first reported by Gerold Meerkoetter (gerold@noc.fh-lippe.de)) * also fixed about 10 more similar bugs (maybe now i can remember when which is correct?) * added 'cs-username' as possible ident-content and cs(X-Forwarded-For) to ignore in elff-format. (patch by Matt Hubbard (m.hubbard@ic.ac.uk)) * quoted unquoted POST. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@128 af268522-00f2-45aa-b56c-050e69c5c3bf commit 350a8dabbc500ebee4486f1f31ef456a3cdbaa2d Author: cord Date: Thu Jan 17 19:46:57 2002 +0000 * added NetCache V5.x to the supported Proxies. * added wishlist-item about a timerange-option. (suggested by Steffen Sledz ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@127 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5b07e880d9b99fc2c5a80593f2ee8b4d04c7f2c8 Author: cord Date: Thu Jan 17 19:42:56 2002 +0000 The FSF (in person of Janet Casey) pointed out, that the 'How to Apply These Terms to Your New Programs' is a part of the GNU GPL. So i corrected this now. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@126 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4fcb275e136bdb28422d69e9b3ec394658d3a8a0 Author: cord Date: Sun Aug 12 15:19:02 2001 +0000 calamaris: * fixed a bug in Logfile-guessing git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@125 af268522-00f2-45aa-b56c-050e69c5c3bf commit fbacb489d156bf65cb60ff3e834082fb2b1ee62c Author: cord Date: Sat Mar 24 21:40:31 2001 +0000 * fixed bug in cache-reading routines witn unquoted keys. (noted by Elrond (elrond@Wunder-Nett.org)) * added support for NetApp NetCache V (thanks to Christian Niederdorfer (christian.niederdorfer@infineon.com) for providing logfiles, testing and also for the donmation. Thank You.) * fixed a bug in cache-reading of Requesters. (fixed by Klaus Brinkmeyer (Klaus_Brinkmeyer@inasys.de)) * corrected indentation * added 2001 to the copyright. (uh, since 1997. Calamaris is 4 now.) * added a warning to the output if more that 5% of the input lines are unparsable. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@124 af268522-00f2-45aa-b56c-050e69c5c3bf commit d6ccc6f0ae2e1fdca6f919b11dacff467f9e18e0 Author: cord Date: Sat Mar 24 21:27:48 2001 +0000 * changed Link to Inktomi Proxy * added 'NetApp NetCache V' to the supported Proxies. * overworked pointers to deb/rpm and *BSD-Ports. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@123 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9aa27630bb6eac672b5b0c50310912842f629230 Author: cord Date: Fri Oct 27 13:52:51 2000 +0000 * added 'nse' (Netscape Extended Logfile-Format) to the manpage. * added a workaround-hint for reusing cache-files * the manpage now described V2.40 and later of calamaris git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@122 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1b04d6624d7714bb60a506eff8a9b19618ad1a2d Author: cord Date: Fri Oct 27 13:50:57 2000 +0000 * improved Netscape Extended-1/2 Logfile Format support * fixed a seldom occuring problem with some perl-versions (reported by Stephen Welker (stephen.welker@nemostar.com.au)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@121 af268522-00f2-45aa-b56c-050e69c5c3bf commit 68c7c65edeb6e87a2eaeb7821973cd1e8a11208e Author: cord Date: Fri Oct 27 13:48:37 2000 +0000 * added Netscape/iplanet Web Proxy Server to the supported servers. * added a pointer with a workaround to a problem with reusing cache-files. (problem noted by Clare Lahiff (clare@tarboosh.anu.edu.au)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@120 af268522-00f2-45aa-b56c-050e69c5c3bf commit da16e4a2d03f630627aed47d486994e705353179 Author: cord Date: Fri Oct 27 13:42:57 2000 +0000 added an EXAMPLE for usage of caching taken from the Debian-package (written by Philipp Frauenfelder (pfrauenf@debian.org)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@119 af268522-00f2-45aa-b56c-050e69c5c3bf commit ad9d20cef33b262eb025aa4add273dc1f080498b Author: cord Date: Thu Oct 12 17:14:15 2000 +0000 fixed the unit-bug again. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@118 af268522-00f2-45aa-b56c-050e69c5c3bf commit faf60b8f22c03d19049030b3158be4415d5e5d54 Author: cord Date: Thu Oct 12 17:03:41 2000 +0000 changed the pointer to the Calamaris Version. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@117 af268522-00f2-45aa-b56c-050e69c5c3bf commit c6ba0cf1f85683e7e65ec2b002a211b79c852be4 Author: cord Date: Thu Oct 12 17:03:13 2000 +0000 fixed a bug regarding units on byte values. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@116 af268522-00f2-45aa-b56c-050e69c5c3bf commit 975ba7ac213ba30f610be5f2022f955374f08ebb Author: cord Date: Mon Sep 18 17:25:29 2000 +0000 * fixed a bug with undefined variable git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@115 af268522-00f2-45aa-b56c-050e69c5c3bf commit 40e8d04857f750cdb8d0b00989721b2428688bc0 Author: cord Date: Mon Sep 18 17:20:19 2000 +0000 * added a -U -option to define the Unit used on the Byte-stats. (suggested by Steven Snyder (Steven_Snyder@3com.com)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@114 af268522-00f2-45aa-b56c-050e69c5c3bf commit f8dda3445e4605b902c1dd33c3062aa7f53ce9ee Author: cord Date: Thu Sep 14 17:15:58 2000 +0000 * added Novell ICS to -f elff-help. * we get $log_url now from cs-uri-stem instead of cs-uri in elff-logs. * added cs(Referer)-field for elff. all reported and patched by Ram Cherukuri (ram@edgix.com) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@113 af268522-00f2-45aa-b56c-050e69c5c3bf commit fd0cfb6c1f22f42669697cb6dad1605f5700f624 Author: cord Date: Thu Sep 14 17:08:36 2000 +0000 added link for Novell Internet Caching System git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@112 af268522-00f2-45aa-b56c-050e69c5c3bf commit f580c9b5bf81c4efae4bba0e5048688258e79225 Author: cord Date: Sat Sep 2 20:36:19 2000 +0000 * fixed a bug in Logfile-guessing. * added alpha-quality support for Netscape-Extend-1/2 Logfiles. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@111 af268522-00f2-45aa-b56c-050e69c5c3bf commit d6076b95ff4fb285ca69530b04a9cac502540356 Author: cord Date: Sat Sep 2 20:34:54 2000 +0000 added a statement. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@110 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6bb3d5257b9aeb123f1f5361ce27c8915fd5fc98 Author: cord Date: Sat Jun 24 14:00:57 2000 +0000 * changed default for -a to -r 20 * added -R-Option. * added a new Section 'PRIVACY' git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@109 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6e4b816e384e445da50152b89748ae5e9b386f8f Author: cord Date: Sat Jun 24 12:56:35 2000 +0000 * changed the one-line description. * changed the -a option to -r 20. * added -R-option to extend -r to report targets. * removed cts (Compaq Tasksmart)-Logformat. * added elff (Extended Logfile Format)-Logformat. * corrected help about -T * added another pointer to privacy-problems to help. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@108 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4286f738131e526bcbfe8bf1d9b3e4026807c4c8 Author: cord Date: Sat Jun 24 12:44:30 2000 +0000 * checked referenced documents and corrected them where nessecary. * changed 'Which formats are supported?' to 'Which software can produce Calamaris-parseable Logfiles?' * changed 'How to use it?' from Squid-specific to a more general description. and added a pointer to Extended Logfile Format. * removed some pointers to known problems as nobody noted these for longer than a year. * added a harsh comment about (mis-?)using Calamaris to break the privacy of users. * removed the comment about not adding privacy-breaking functions. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@107 af268522-00f2-45aa-b56c-050e69c5c3bf commit e89f3a415309e87dbf8174001a5e470433ecb431 Author: cord Date: Thu Jun 22 10:58:03 2000 +0000 * changed short description. * added all known Caches which can produce Calamaris-parseble logs. * changed the -f Default. * corrected -T description. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@106 af268522-00f2-45aa-b56c-050e69c5c3bf commit bc72c633b99099d7fd569dbb7b9d8db7c7c71d86 Author: cord Date: Thu Jun 22 10:06:50 2000 +0000 * added support for 'Oops', a forking Squid-relative. * added support for Compaq Tasksmart. * changed guessing messages. * made guessing the default. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@105 af268522-00f2-45aa-b56c-050e69c5c3bf commit c1198e68cc93345cb06888c9dddd8dab49fdf024 Author: cord Date: Thu Jun 22 10:00:27 2000 +0000 * added a new section 'Which formats are supported?' * changed the comment on Logfile-guessing. * removed 'Compaq Cache' from wishlist. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@104 af268522-00f2-45aa-b56c-050e69c5c3bf commit fd353b320694b5d2abeec171b4b32d185abc57da Author: cord Date: Thu May 25 17:44:09 2000 +0000 fixed a small bug in Thomas Wahyudis Example (noted by himself) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@103 af268522-00f2-45aa-b56c-050e69c5c3bf commit 009b5381bc460b1b4a153d18e55cf39d291aa9f9 Author: cord Date: Wed May 24 21:34:19 2000 +0000 added a note about the to come support of Compaq Cache git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@102 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9dc2bcb843515fa293ad6c5cf88270421b537aea Author: cord Date: Wed May 24 21:31:15 2000 +0000 * added a new hierarchie-method of Inktomi Traffic Server --> EMPTY (patched by Warren Brown (wbrown@inktomi.com)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@101 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0e8f6399c596988d86e7f2e10f1da35a5e22d8b6 Author: cord Date: Wed May 24 21:18:22 2000 +0000 * added another example provided by Thomas Wahyudi (thomas@home.unpar.ac.id) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@100 af268522-00f2-45aa-b56c-050e69c5c3bf commit a4d59314b9daef25562c835515ae968b86ee71f7 Author: cord Date: Sat May 13 20:06:45 2000 +0000 * added descriptions for the new logfile formats. * added descriptions for -T, -c and -v * changed -c and -v to -C and -V. * manpage now reflects V2.30 and above. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@99 af268522-00f2-45aa-b56c-050e69c5c3bf commit b98da933723978d7d52bbbb265b4f5495e303191 Author: cord Date: Sat May 13 20:03:11 2000 +0000 * corrected Dancer Vesperman's credit. * added a new logfile-type for Inktomi Traffic Server. (reported by Michael Smith (good_guy93@hotmail.com) * added a pseudo logfile type 'auto' which let's Calamaris guess what logfile is read. (still beta, please test) * added a verbose switch, (but it didn't do more yet as displaying which kind of logfile is guessed, maybe i should move the -b-switch in here?) * added a switch which enables correcting the Performance Report to a specific timezone. (noted by Holger Marzen (hm@sik-gmbh.de) * added a switch to make the file-extensions report case-insensitive. (requested by Steve Snyder (swsnyder@home.com) * changed the copyright switch from -c to -C. * changed the version switch from -v to -V. * changed the output of byte values: now all output is in Byte (not KByte anymore) if the space in the output would cut off something Calamaris will switch to KByte, MByte, GByte and TByte (I think this is enough ;-) indicating this by appending a K, M, G or T to the value. I saved a digit in the output here and gave it to the requests. (a problem with this is reported by Panagiotis Christias (P.Christias@noc.ntua.gr) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@98 af268522-00f2-45aa-b56c-050e69c5c3bf commit 2182799c6844eabfcace9aae71b0d27099f25452 Author: cord Date: Sat May 13 19:01:07 2000 +0000 * Removed a hint for very old browsers. * Added a HELP REQUEST according the new Logfile-guessing. * Changed the comment on Common Logfile-Format. * Added a reply to the many requests about more user tracking with Calamaris. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@97 af268522-00f2-45aa-b56c-050e69c5c3bf commit bac07c3348e3333d336df3514b2ed7e9223917f9 Author: cord Date: Sat May 13 18:56:08 2000 +0000 * added an example provided by Gottfried Hamm (ghamm@ghks.de) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@96 af268522-00f2-45aa-b56c-050e69c5c3bf commit 072206725df26feadd456ce10641755719e4816f Author: cord Date: Thu Dec 16 22:56:45 1999 +0000 * Bugfix to 2.28. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@95 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4f41e1c824bb7a4f2b8dc26f6c97aad5f0e63839 Author: cord Date: Sat Sep 25 12:33:34 1999 +0000 * the benchmark option gives now hash-signs which were written to STDERR. (patch provided by Gerold Meerkoetter (gerold@noc.fh-lippe.de)) * all warn-calls were replaced by print to STDERR, so get rid of the automagically apended line-numbers. * now Calamaris checks the syntax of Logfilelines a little more, because lines such as 'if needed, or if running Squid for the first time.' lead to strange errors. A correct line has to have a date-field with the syntax \d+\.\d\d\d (reported by Gerold Meerkoetter (gerold@noc.fh-lippe.de)) * if ident-information parsing is activated, but there isn't an ident-information available now the ouput is without the leading '-@'. (patch by Chris Teakle (ccteakle@its.uq.edu.au)) * added new hierarchie-method 'ANY_PARENT'. * added a small invisible Y2K-fix. Now Calamaris uses internal the correct 4-digit-year. However Calamaris only prints 2-digit-years because i want to produce lines which were max. 79 chars long. (patch by Toni Andjelkovic (toni@telecom.at)) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@94 af268522-00f2-45aa-b56c-050e69c5c3bf commit 140965cb207b90b8b117f9c40c3f6d39ae216c29 Author: cord Date: Sat Sep 25 09:47:17 1999 +0000 * Feature request added: n-level requester report. (suggested by Jarkko Saloranta ) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@93 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8f295454b132cfc49df48379faf4ae0695e893ac Author: cord Date: Tue Jun 8 19:48:01 1999 +0000 fixed parsing of squid-mime Logfiles. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@92 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6f5adae4c836a7ec15c342f43165e465b0c291c2 Author: cord Date: Sat Jun 5 12:31:42 1999 +0000 * changed the 'require 5' to 'require 5.002' because of vars.pm. (pointed out by Jonas Luster (jonas@nethammer.qad.org)) * fixed a bug regarding 'Outgoing requests by destination' where the approximate request time was calculated wrong for the Status-lines. (Clare Lahiff (Clare.Lahiff@anu.edu.au) reported this bug.) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@91 af268522-00f2-45aa-b56c-050e69c5c3bf commit 21ef7be4f4377bbf390133edcb3642866eabe80d Author: cord Date: Tue May 11 18:22:25 1999 +0000 * added a new input-format 'squid-mime' for log_mime_hdrs-enhanced Squids. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@90 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6e4090f18b3d4f8f5b419a3fa4f8ad8059601641 Author: cord Date: Sat May 1 19:01:16 1999 +0000 * added a new kind of ERROR from NetCache (reported by Ryan Donnelly) * changed the unknown log_hier_method -error, because many people simply sent the output to me, without thinking if the bug could be somewhere else (corrupted Logfile) or fixed in a later release. * cleaned up the HTML-Output (suggested and patch by Christos Cheretakis) because better HTML will be rendered faster (and weblint is now also happy ;-) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@89 af268522-00f2-45aa-b56c-050e69c5c3bf commit 574bffea4d07eae26fe48a6533c4b2c7d4fac56f Author: cord Date: Sat May 1 18:55:46 1999 +0000 * clarified Mailinglist-Subcription. * changed link to FreeBSD-Port. * added a point to 'bugs and shortcomings regarding corrupted Logfiles. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@88 af268522-00f2-45aa-b56c-050e69c5c3bf commit 45df1e2b4c6d2b6d39f3132a25936a3f8be8933f Author: cord Date: Fri Apr 2 15:19:10 1999 +0000 * added a confirmation-request on wrong SSL-Request parsing. * added a suggestion from John Line ) about seperate on/off-switching for UDP/TCP-Requests-reports. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@87 af268522-00f2-45aa-b56c-050e69c5c3bf commit a233b8af7b135e2aee7262a4a833bbc3b1b7e492 Author: cord Date: Fri Apr 2 15:17:01 1999 +0000 * Copyright an Usage-Information will now also appear on STDOUT. * added new symbolic Protocol, Content-Type and extension for SSL-Requests. * all INVALID_URL-Requests will now be reported as symbolic in the TCP-Request report. * moved Nameserverlookups back into the main loop to avoid double reportings of Hosts, which were sometimes resolved by Squid, and sometimes not. (reported by John Line (webadm@info.cam.ac.uk)) * moved checking for -n also into the mainloop. * moved CARP-Requests from the 'FETCH from Parent Cache' to the 'HIT on Sibling or Parent Cache'-section of the Outgoing-request-status. (Hope this is correct, but the Reports provided by Emmanuel Adeline (emmanuel.adeline@mail.dotcom.fr) look to me like this is the correct section for CARP.) * the Performance-Report is now sorted correctly. * added some   to the HTML-Report to make the HTML-Report more readable. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@86 af268522-00f2-45aa-b56c-050e69c5c3bf commit a7e87cf86796fb1384e053cd2b54d698b00928c5 Author: cord Date: Fri Apr 2 14:59:44 1999 +0000 added an Example of Matthew King. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@85 af268522-00f2-45aa-b56c-050e69c5c3bf commit c5f059a60594c454ba868b1ba0163be9b368d739 Author: cord Date: Sat Feb 20 19:33:48 1999 +0000 * bugfix for the old peak-calculation method. * added format-info to reports. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@84 af268522-00f2-45aa-b56c-050e69c5c3bf commit 91b08d4de8cc2324c7ab74fb91a585556fdf1be0 Author: cord Date: Sat Feb 20 17:59:51 1999 +0000 changed reference Id for Calamaris. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@83 af268522-00f2-45aa-b56c-050e69c5c3bf commit 59c1429c79e37b10acb836ed548ea1b9411e7058 Author: cord Date: Sat Feb 20 17:45:13 1999 +0000 * added new option -l (logo) for adding a customizable head to HTML-Report. * fixed (again) a small problem with -H option. * changed the hack to parse broken NetCache 3.2.x-Logfiles. The old hack broke some lines if a semicolon is the last char of a field. * all hostnames converted to lowercase. NuTsCaPe and nUtScApE as host is now recognized as the same. * fixed something with NetCaches ICP-Requests. * TIMEOUT_NONE is now recognized, Calamaris doesn't complain anymore. * added a HTML 4.0-header to the HTML-Report. (thanks to Iain Lea) * Performance-Report corrected. ICP-Request are not counted anymore. * Fixed a Y2K-Problem :-) Y2K has been reported as 100, which is correct, but this breaks my 80-chars text-width, and it is not that intuitive. Now Y2K will show up as 00. (Internal I calculate all with UNIX-epoch (seconds since 1.1.1970). A quick test shows that Calamaris should work 'til 19.1.19^H^H2038 ;-) However: Y2K-Statement: Calamaris comes with ABSOLUTELY NO WARRANTY. * added Homepage-Location to the Copyright-Footer. * added '-- ' to seperate footer and report in Mail-reports. * added links to the HTML-Copyright-footer. * cleaned up (printf --> print where possible.) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@82 af268522-00f2-45aa-b56c-050e69c5c3bf commit 700fa68206ea58b06cfefecf2c4c0aa60dea7340 Author: cord Date: Sat Feb 20 17:12:08 1999 +0000 moved the Common-Log-Statement from todo to bugs&shortcomings. NetCache is now in late beta-state. Removed some warnings :-) cleaned up. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@81 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0c0b6d988b0be9bf6c8c10f0ee38c5d41169b9b2 Author: cord Date: Sat Feb 20 17:07:51 1999 +0000 cleaned all up a bit (mainly in the groff-source) added new option -l git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@80 af268522-00f2-45aa-b56c-050e69c5c3bf commit e7e7279a2635d0fef12ed0ead1f9166ee13065ea Author: cord Date: Sat Feb 6 21:08:26 1999 +0000 NetCache-Support changed. removed the Support for Common-Log-style Logfiles. added a -f-option type for the default. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@79 af268522-00f2-45aa-b56c-050e69c5c3bf commit 96c5de79d59f5a2978b8c4e5a67c6a8f6a29713a Author: cord Date: Thu Feb 4 22:39:47 1999 +0000 fixed a bug regarding old squid logfile support. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@78 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4e2d691e8418823349f92dd7ed1bcce3ef975b03 Author: cord Date: Thu Feb 4 22:30:37 1999 +0000 chnaged a few things to reflect changes of V2.19 and later. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@77 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1a4fd174a7913df440b0a6eb68946a409f6031e5 Author: cord Date: Thu Feb 4 22:29:36 1999 +0000 * added new -f -option for selecting input logfile format * worked on NetCache-Support, now Calamaris should understand another format. (untested) * added support for pre-V1.1.beta26-Squid-Logfiles. * changed -p -option to select between old (2.8) and new (2.16) peak-measurement method * removed -p -option from the -a -switch. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@76 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6e511ebc2724f57f3a7e4680b744c12b75ac08cd Author: cord Date: Thu Feb 4 22:18:32 1999 +0000 changed statements regarding NetCache and peak mesurement. added Help Requests to these points. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@75 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9eeacbab50c8d26faea910d17e29e122430b5847 Author: cord Date: Wed Feb 3 22:27:26 1999 +0000 Added pointer to the FreBSD-Calamris-Port. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@74 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8cc80e312048659124434a03bdf58439a51e8f7f Author: cord Date: Fri Jan 22 21:06:57 1999 +0000 added a todo. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@73 af268522-00f2-45aa-b56c-050e69c5c3bf commit ff28ef371361b7942a8b35426187570893e06f15 Author: cord Date: Fri Jan 22 21:05:59 1999 +0000 made the error message more helpful. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@72 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9c22d88e4e33dbc957fe8e9f91707dd31d6e2ab5 Author: cord Date: Fri Jan 22 21:02:51 1999 +0000 only a little reformatting. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@71 af268522-00f2-45aa-b56c-050e69c5c3bf commit dc6001361d025652443c28f32e30131b09b1b918 Author: cord Date: Wed Dec 9 22:23:53 1998 +0000 looked through it and cleaned up again... git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@70 af268522-00f2-45aa-b56c-050e69c5c3bf commit 50d56166dfb80baa3e57668772bef2607bb2f9eb Author: cord Date: Wed Dec 9 22:21:14 1998 +0000 taken over the manpage... there is more work to be done... git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@69 af268522-00f2-45aa-b56c-050e69c5c3bf commit e5076e73c93879f36c418a885b37751880ee2ea9 Author: cord Date: Sun Dec 6 16:36:23 1998 +0000 added manpage to the installation-'manual' changed the comments on the new Squid-generation changed comments on peak-measurement added a comment about Common Logfileformat git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@68 af268522-00f2-45aa-b56c-050e69c5c3bf commit c4d9a1f490efbc0bc3d1f29f13af506fb1616c29 Author: cord Date: Sat Dec 5 14:12:17 1998 +0000 fixed small bug to handle (drop) negative reqtimes. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@67 af268522-00f2-45aa-b56c-050e69c5c3bf commit ebc0060f3e903d8321bc3fc35d606254c362b9ec Author: cord Date: Sat Dec 5 13:18:48 1998 +0000 reworked the measurement of peak-usage. Hour-data is now calculated in hour-steps, and a throughput peak is also there. The changes make Calamaris about 20% faster (on a 60k-line-file compared with V2.8). With bigger Logfiles the gain should be greater. However: The Peakmeasurement is the less efficient part of Calamaris, if you switch it off Calamaris will be 30% (with 60k-lines) or more faster. (I'm not glad with it, maybe someone has an idea how to build a routine which is fast AND more reliable?). made some changes in line-formating and some cosmetic changes in the code. included new adress for the Calamaris-Homepage. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@66 af268522-00f2-45aa-b56c-050e69c5c3bf commit a61f291b21c4e63916f0cfcf0800d8f51ec611d0 Author: cord Date: Sat Dec 5 13:07:10 1998 +0000 Included new adress for the Calamaris-Homepage. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@65 af268522-00f2-45aa-b56c-050e69c5c3bf commit 35a75b4895af9321a2f3e5700114818aececfe70 Author: cord Date: Sat Dec 5 13:06:19 1998 +0000 wrapped the long lines and added a warning. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@64 af268522-00f2-45aa-b56c-050e69c5c3bf commit a465255ac93fa19a63a83a15b7875476bd9e94ed Author: cord Date: Sat Dec 5 10:42:08 1998 +0000 Added a few suggestions by Gerold Meerkoetter git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@63 af268522-00f2-45aa-b56c-050e69c5c3bf commit 231fd9be59d738e10178b33352540ff69063d90c Author: cord Date: Tue Nov 17 23:08:41 1998 +0000 A manpage for Calamaris. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@62 af268522-00f2-45aa-b56c-050e69c5c3bf commit 367a354f23db54065a52993d1df4d13d4e0bf589 Author: cord Date: Tue Nov 17 22:51:17 1998 +0000 Fixed some faults. Thanks to gerold Meerkoetter for pointing me on them. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@61 af268522-00f2-45aa-b56c-050e69c5c3bf commit 947b7d97a134e3e024549adfd5feac2243ec6b01 Author: cord Date: Mon Nov 16 21:56:29 1998 +0000 New Manpage for Calamaris Many thanks to Philipp Frauenfelder git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@60 af268522-00f2-45aa-b56c-050e69c5c3bf commit 047bc7355dd1d787593506da0317d4c0d96c7249 Author: cord Date: Mon Nov 16 21:52:51 1998 +0000 changed the name of calamris.pl to calamaris git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@59 af268522-00f2-45aa-b56c-050e69c5c3bf commit cec65ea79a02bb7d29a4907a68a36b7b7a200729 Author: cord Date: Mon Nov 16 21:44:36 1998 +0000 save the previous revisionnumbers from calamaris.pl 2.13 is the actual number of calamaris git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@58 af268522-00f2-45aa-b56c-050e69c5c3bf commit ba2a9152feeb97e27a74a95cbcb2611add8beb31 Author: cord Date: Mon Nov 16 21:42:49 1998 +0000 Renamed calamaris.pl to calamaris to make it more logically with the new manpage. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@57 af268522-00f2-45aa-b56c-050e69c5c3bf commit 03a850a09e8459aed603d906944cb807d4eefb3e Author: cord Date: Mon Nov 16 21:25:32 1998 +0000 A manpage for Calamaris. Many thanks to Philipp Frauenfelder for it. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@56 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6a9e3d44eacc5a84f28c4485e55723c4da856d70 Author: cord Date: Thu Oct 22 22:37:14 1998 +0000 found another performance-thing... Now it is ~8% faster than 2.8 (last release) git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@55 af268522-00f2-45aa-b56c-050e69c5c3bf commit f2af833865346386aa25326a213d5eff57eaf3a4 Author: cord Date: Thu Oct 22 19:36:52 1998 +0000 moved $perf-initialisation to the TCP-Part. cleaned Calamaris up. Calamaris is now ~5% faster, if you use '-a' git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@54 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8c2e45a1a330384a95abf0027f6b7e2952993dbc Author: cord Date: Tue Oct 20 09:37:57 1998 +0000 Added new switch for chnaging the sort order in reports from number of requests to size of requests. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@53 af268522-00f2-45aa-b56c-050e69c5c3bf commit 2c480a5d8afef9c1f7c7612dcbbd9f168853a356 Author: cord Date: Sun Oct 18 22:06:00 1998 +0000 on Squid V2.0.x: I'm still looking for a report of a CARP-User how Calamaris works for him. I removed the todo 'rewrite Mainloop'. I have build it in, and now the Mainloop is build first and then run. But: It doesn't work as good as i hoped. On my measurements on my (slow) 386DX40 with a very short access.log it is slower, with a longer file (60k lines) it is faster by about 2% git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@52 af268522-00f2-45aa-b56c-050e69c5c3bf commit 22d49655c9eb342fb56d24ea28098d72a487c27c Author: cord Date: Sun Oct 18 21:37:17 1998 +0000 Moved logfile-parsing part into a pre-run-part. Now the Mainloop for parsing is build before running it. Static things like switches are build in... git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@51 af268522-00f2-45aa-b56c-050e69c5c3bf commit c464140eddec1abf817d02633dc460e21e896239 Author: cord Date: Wed Oct 14 20:56:36 1998 +0000 Added pointers for rpm and Debian-Packages git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@50 af268522-00f2-45aa-b56c-050e69c5c3bf commit 74b8dbb48993be3b67ea5f88275e28b5682055a9 Author: cord Date: Mon Oct 12 20:03:54 1998 +0000 Had a better idea how to handle the broken data while showering :-) Now wrong data is printed as - in the Report. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@49 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3be5117c88936c4cf1e5a00896a4ee6b359b7c3b Author: cord Date: Mon Oct 12 19:26:46 1998 +0000 fixed breaking old (buggy) cachefile. Now old and new Cachefile work without complaining... But with old cachefiles the performance-values of Cache-Hits are wrong... git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@48 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0676e7fe57d4d2afa1783c83e43a7e087bd37dbc Author: cord Date: Mon Oct 12 19:22:50 1998 +0000 added text about the Cachefile-breaking Bug. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@47 af268522-00f2-45aa-b56c-050e69c5c3bf commit bc4350f7277105916157ff28d66b4e15367b010a Author: cord Date: Mon Oct 12 18:41:17 1998 +0000 found and removed no longer needed tcp_miss_neighbor-strings. moved caching for peakvalues into the $opt_P-Option. corrected (again) the measurement of transfered data in the Performance-Report git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@46 af268522-00f2-45aa-b56c-050e69c5c3bf commit da2f805ca493989582c4824af4b8407a1ab0b543 Author: cord Date: Mon Oct 12 18:37:58 1998 +0000 added a statement regarding perl 5.001 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@45 af268522-00f2-45aa-b56c-050e69c5c3bf commit 70147aa1ba82bda12415d78c0e9abf0b584aaae1 Author: cord Date: Sat Oct 10 18:51:48 1998 +0000 fixed more bugs regarding cached Performance... git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@44 af268522-00f2-45aa-b56c-050e69c5c3bf commit 28340f396f11f988325f266629a85d56d97cc1c8 Author: cord Date: Sat Oct 10 17:16:53 1998 +0000 added better handling of cached 'other'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@43 af268522-00f2-45aa-b56c-050e69c5c3bf commit e8732a8e16d729d62a055455608b32495a644faa Author: cord Date: Sat Oct 10 13:39:06 1998 +0000 fixed bug regarding caching function. WARNING: This breaks cached Performance-data from old cachefiles. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@42 af268522-00f2-45aa-b56c-050e69c5c3bf commit 3c4856deac5bedad1cce3a317e6815744f2727e9 Author: cord Date: Sat Oct 10 13:35:37 1998 +0000 added another todo git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@41 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6f2ec92eb7140454c34e81a0650cd3123ac5d5db Author: cord Date: Wed Oct 7 17:41:44 1998 +0000 fixed bugs reported ans patched by Roar Smith git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@40 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1a10db8b70d6c3d78fbe15199d8c51315a200f20 Author: cord Date: Wed Oct 7 17:40:52 1998 +0000 added wish for switch the sorting between requests and size git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@39 af268522-00f2-45aa-b56c-050e69c5c3bf commit 6fe35e9632278215d8383630e1c8645f08ec0262 Author: cord Date: Mon Oct 5 18:50:29 1998 +0000 no program changes. checked the spelling and rewrote a few parts of the README 'official' release of Calamaris V2 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@38 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5a43f169727f0ef47258396f7d7c327e6da94c2f Author: cord Date: Sat Oct 3 12:33:28 1998 +0000 added CACHE_DIGEST and CARP git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@37 af268522-00f2-45aa-b56c-050e69c5c3bf commit cb24f91986fd9d700087bbb3eec498b918c41168 Author: cord Date: Wed Sep 30 17:46:21 1998 +0000 added a sentence to 'What Is It?' git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@36 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8d5f64ee661d0af1c7499de2455806e6df51e811 Author: cord Date: Wed Sep 30 17:35:01 1998 +0000 changed location of Calamaris-Homepage. changed adress of Announcementlist git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@35 af268522-00f2-45aa-b56c-050e69c5c3bf commit cd9b93a4e79b32f213f0b6931ce18ab1ffdd1ca2 Author: cord Date: Wed Sep 30 17:33:02 1998 +0000 changed location of calamaris-Homepage. added link to the calamaris C++ port Seafood. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@34 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4bbdb9f9112b11135bc56fbbcfd434458cd33acb Author: cord Date: Fri Sep 25 19:02:44 1998 +0000 Cleaned up README. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@33 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5933f47aefb820b47253aa4beee4318b8207d2e7 Author: cord Date: Thu Sep 24 21:56:05 1998 +0000 Added Version-Information. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@32 af268522-00f2-45aa-b56c-050e69c5c3bf commit 19221b00811f36125ea704831e6c76b261e1f1aa Author: cord Date: Thu Sep 24 21:52:50 1998 +0000 New File for Examples of calamaris usage. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@31 af268522-00f2-45aa-b56c-050e69c5c3bf commit d675b480de4aeeb4ea8571e642aee2479e83eee8 Author: cord Date: Thu Sep 24 21:39:30 1998 +0000 Damned! CVS lost my first rewrite. OK, so here we go again. This is the text which was formerly at the beginning of calamaris.pl. Now it's more verbose, HTH git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@30 af268522-00f2-45aa-b56c-050e69c5c3bf commit 1dab55b9f8df17a6deffe5b99ceccfed015793b7 Author: cord Date: Thu Sep 24 18:07:43 1998 +0000 Fixed bug in Performancereport: Transfered Data is now real given in MBytes git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@29 af268522-00f2-45aa-b56c-050e69c5c3bf commit af48626628a9242d37f68799b6527816efcec35f Author: cord Date: Wed Sep 23 21:03:20 1998 +0000 Moved READMEs out of calamaris into the New README file Added GPL-File git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@28 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4b3fecb6db8eab7601aaa546cfe69a6456d13c8d Author: cord Date: Tue Sep 22 21:43:35 1998 +0000 changed Performance-report: now zero-sized measures are printed as '-' instead of 0.00 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@27 af268522-00f2-45aa-b56c-050e69c5c3bf commit 99fc34b47696c5ec348ecea7f4efd063c9c588df Author: cord Date: Mon Sep 21 21:29:50 1998 +0000 added more usage-information. Hmmm... i think i'm going to wait a few weeks and then i release this as 'official' calamaris v2 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@26 af268522-00f2-45aa-b56c-050e69c5c3bf commit 7387a8d1d96a813ac659392c1aac06a4104ad2fd Author: cord Date: Mon Sep 21 19:14:55 1998 +0000 added default-values for the -a -Option changed caching to add many cachefile at once fixed a bug in the Syntaxcheck of the input cachefiles. removed checks for -a-option git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@25 af268522-00f2-45aa-b56c-050e69c5c3bf commit 66473d05f8c662bf9af56d09790f02b210b879cd Author: cord Date: Fri Sep 18 22:30:57 1998 +0000 changed URL for calamaris added Announcement-Mailinglist added -P-switch for measuring performance values added new report for it removed transfervariable for peakmeasurement git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@24 af268522-00f2-45aa-b56c-050e69c5c3bf commit 11c95e413fd41457f4ff3fe907fba64b68ee3a02 Author: cord Date: Wed Aug 12 21:48:48 1998 +0000 added CLOSEST_PARENT method wrote a few lines on NetCache-Support git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@23 af268522-00f2-45aa-b56c-050e69c5c3bf commit add5540c91e9447cd6072dbfcff52298ef9d3803 Author: cord Date: Wed Aug 12 21:04:00 1998 +0000 changed syntaxcheck of Logfile for parsing NetCache-Logs git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@22 af268522-00f2-45aa-b56c-050e69c5c3bf commit 32b695b1c7e2c20c4f327778ad7cdd57d6845ef3 Author: cord Date: Sun Jul 19 11:41:46 1998 +0000 fixed small bug in hostnamelookup git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@21 af268522-00f2-45aa-b56c-050e69c5c3bf commit c85dc4bd7b1d74e28921df17033711f0b3659803 Author: cord Date: Sat Jul 18 21:52:07 1998 +0000 moved DNS-Lookups from the parsing part into the output part of calamaris git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@20 af268522-00f2-45aa-b56c-050e69c5c3bf commit 009bafadffb424caecc9292ce82f5b3a0ec7c23a Author: cord Date: Thu Jul 9 19:56:06 1998 +0000 added support for parsing NetCache-Logfiles wrote a few lines in the README-Section git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@19 af268522-00f2-45aa-b56c-050e69c5c3bf commit 617580c51d3d5bc65a47b51c112b8c1cc30dc4ed Author: cord Date: Thu Jul 9 19:04:32 1998 +0000 added reporting number of unique clients. fixed small bug with git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@18 af268522-00f2-45aa-b56c-050e69c5c3bf commit e3293baba54673402dc0d0748df9a5d67c6ddd68 Author: cord Date: Sun May 10 21:39:31 1998 +0000 fixed bug in content-type-limiting git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@17 af268522-00f2-45aa-b56c-050e69c5c3bf commit 4d940ac85696fb4721fa771620cf83cbb4305516 Author: cord Date: Sun May 10 20:54:00 1998 +0000 added 3 todos changed usage line added Content-type for HTML-Mails *urgs* git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@16 af268522-00f2-45aa-b56c-050e69c5c3bf commit f21455b638ea4a7f122628155a81bf781ea679cf Author: cord Date: Sat May 9 15:36:53 1998 +0000 fixed hostname output (again) removed bogus Debug-line corrected usage line git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@15 af268522-00f2-45aa-b56c-050e69c5c3bf commit b45088ead50e93dcd9c8e582e9c049e6f2b42d72 Author: cord Date: Wed Apr 15 21:24:08 1998 +0000 added Link for jumping back to the Top in HTML-Output fixed small bug in the content-type report (other content-types) wrapped long lines where possible. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@14 af268522-00f2-45aa-b56c-050e69c5c3bf commit 2f575fabd12633e251412225d446525916b93e7a Author: cord Date: Thu Apr 9 20:44:23 1998 +0000 changed output string. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@13 af268522-00f2-45aa-b56c-050e69c5c3bf commit 8cf8a501538163e340f3036b423d33bc7410c8e5 Author: cord Date: Tue Apr 7 20:06:41 1998 +0000 now report ERR_INVALID_URL correct as error git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@12 af268522-00f2-45aa-b56c-050e69c5c3bf commit ad5c64d2483d976aacfab9c655d39f34596deea1 Author: cord Date: Tue Apr 7 19:26:44 1998 +0000 added Referers into HTML-Output for indocument links. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@11 af268522-00f2-45aa-b56c-050e69c5c3bf commit d081f2d7bcfefb9eb42301389d74cd1261ea6d6a Author: cord Date: Tue Apr 7 18:31:27 1998 +0000 fixed small bug with hostname-output. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@10 af268522-00f2-45aa-b56c-050e69c5c3bf commit d41294b4aab675ee7c59c94745ba01fe7a16649b Author: cord Date: Sun Apr 5 22:50:10 1998 +0000 changed short variables back into long ones. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@9 af268522-00f2-45aa-b56c-050e69c5c3bf commit 9c96fed4c46a3c6bb0a22cc097d5ac038d88e433 Author: cord Date: Sat Jan 17 18:19:56 1998 +0000 at this point i remember tht there was 1.99.1.1, i put that changes in the 'official' devel branch. RCS simply fooled me ;-( replaced -f-option with -i and -o option moved -o-option into -H-option readded syntaxcheck of cachefiles git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@8 af268522-00f2-45aa-b56c-050e69c5c3bf commit 80656ecc03c15578ee47af18ae5f6a5931f6c742 Author: cord Date: Thu Jan 15 22:34:47 1998 +0000 chnged behaviour of error reporting git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@7 af268522-00f2-45aa-b56c-050e69c5c3bf commit 509db694e2345ad6fd2b13dec5ecaf65359ed20f Author: cord Date: Sun Jan 11 21:25:48 1998 +0000 This version is based on 1.99 added -o option for defining Hostname added more TLD's with functional subdomains. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@6 af268522-00f2-45aa-b56c-050e69c5c3bf commit e5208b558a393943742a2d4dea562aab250253db Author: cord Date: Mon Dec 29 20:53:02 1997 +0000 changed the Cachefile-Option -f to two options -i and -o added syntaxcheck to cachefileparser fixed a few bugs git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@5 af268522-00f2-45aa-b56c-050e69c5c3bf commit 898f841bf8fbe4b79f43f733524bd532887868c2 Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Sun Dec 28 21:51:43 1997 +0000 This commit was manufactured by cvs2svn to create branch 'unlabeled-1.99.1'. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@4 af268522-00f2-45aa-b56c-050e69c5c3bf commit 5232785547c95c914827737c687f41438835d7e5 Author: cord Date: Sun Dec 28 21:51:42 1997 +0000 i choose this number to give the old calamaris room to grow shorten all variables to make calamaris shorter and faster added caching of data added -z option for only parsing cached data git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@3 af268522-00f2-45aa-b56c-050e69c5c3bf commit 402c8da378b5da6ec6cb754081157ac2f50f5586 Author: cord Date: Tue Dec 23 20:52:59 1997 +0000 cleaned up calamaris v1 added command-line-options made peak-measurement more effective added HTML-Output-option added new reports and changed some old reports moved diverse functions into subroutines This is the initial revision of calamaris v2 git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@2 af268522-00f2-45aa-b56c-050e69c5c3bf commit 0f77c8850cb681258b56ff82330d66310b516f4b Author: (no author) <(no author)@af268522-00f2-45aa-b56c-050e69c5c3bf> Date: Tue Dec 23 20:52:59 1997 +0000 Standard project directories initialized by cvs2svn. git-svn-id: svn+ssh://weyoun2.vpn.cord.de/home/svn/calamaris@1 af268522-00f2-45aa-b56c-050e69c5c3bf calamaris-2.99.4.7/README0000644000175000017500000000675114161616434013257 0ustar cordcordCalamaris Version 3 What is it? ----------- Calamaris is a Perl script, which was first intended as demo for a statistical software for Squid. I started it at 13 January 1997 (Version 1.1) as a rewrite of my old Squid-Analysis-Script weekly.pl (which was in German language). I announced it (Version 1.16) to the public at 28 Feb 1997. (see http://www.squid-cache.org/mail-archive/squid-users/199702/0551.html for the Original-Announcement) Since then it is used by people all around the world, and i decided to build a new improved version of it. Calamaris V2 was a nearly complete rewrite, with changed and more reports. 2004 Michael Pophal send me a jumbo-patch against Calamaris 2.59, which adds two more reports, and the long wanted graphics to make your mangle^H^H^Hagement happy. Which software can produce Calamaris-parseable Log-files? --------------------------------------------------------- * Squid V1.1.alpha1-V2.x (http://www.squid-cache.org/) * NetCache V??? (http://www.netapp.com/products/netcache/) * Inktomi Traffic Server V??? (http://www.inktomi.com/products/network/products/) * Oops! proxy server V??? (http://zipper.paco.net/~igor/oops.eng/) * Compaq Tasksmart (http://www.compaq.com/tasksmart/) * Novell Internet Caching System (http://www.novell.com/products/ics/) * Netscape/iPlanet/SunONE Web Proxy Server (http://www.iplanet.com/downloads/download/detail_14_13.html) * Squid with the SmartFilter-patch * Cisco Content Engines (http://www.cisco.com/en/US/products/hw/contnetw/index.html) Where to get Calamaris? ----------------------- The Calamaris-Home-page is located at https://Calamaris.Cord.de/ The Development-Repository is at https://github.com/C0RD/calamaris There is also an Announcement-Mailing-list. To subscribe send mail with 'subscribe your@mail.adr.ess' in the Mail-Body to . Subscribers will get a mail on every new release, including a list of the changes. --> low traffic. Philipp Frauenfelder has build a Debian Package, which can be found via https://packages.debian.org/calamaris . There is a port for FreeBSD, which can be found at https://www.freebsd.org/cgi/ports.cgi?query=calamaris . A package for NetBSD is here: ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/www/calamaris/README.html rpms are also available from various people. You can search for them via http://rpmfind.net/linux/rpm2html/search.php?query=calamaris . Is there anything else? ----------------------- Ernst Heiri has build a spin-off of my Calamaris V1, which can be found *where?* There is also a C++-port of Ernst Heiri's Calamaris available. It is (according to the author Jens-S. Voeckler ) five times faster than the Perl-variant. check http://www.cache.dfn.de/DFN-Cache/Development/seafood.html for this. more Squid-logfile-Analysers can be found via the Squid-Home-page at http://www.squid-cache.org/Scripts/ Thank You! ---------- * The developers and contributors of Squid. * The developers and contributors of Perl. * The contributors, feature requesters and bug-reporters of Calamaris. * Gerold 'Nimm Perl' Meerkoetter. * Massimo Carnevali * Michael Pophal Not happy yet? -------------- Drop me a line to and tell me what is missing or wrong or not clear or whatever. You are welcome (especially if you read this file that far :-) Version of the README --------------------- $Id: README,v 3.0 2004-09-15 20:46:31 cord Exp $ calamaris-2.99.4.7/calAxestype.pm0000644000175000017500000016564714161616434015231 0ustar cordcord#========================================================================== # Module: calamaris::calAxestype.pm # # Copyright # # calAxestype.pm Copyright (c) 2004 Michael Pophal based on # GD::Graph Copyright (c) 1995-1999 Martien Verbruggen. # (https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm) # # All rights reserved. This package is free software; you can redistribute # it and/or modify it under the same terms as Perl itself. # # Acknowledgements # # Thanks to Martien Verbruggen's ingenious tool GD::Graph, which is basically # the same, except some small changes needed for calamaris. #========================================================================== # # Adapted to calamaris by: (c) 2004 Michael Pophal # # Based on: # GD::Graph::axestype.pm,v 1.21 2000/04/15 08:59:36 mgjv # https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm # Copyright (c) 1995-1998 Martien Verbruggen # #-------------------------------------------------------------------------- # # Name: # calamaris::calAxestype.pm # # $Id: calAxestype.pm,v 3.2 2004-09-15 21:02:13 cord Exp $ # #-------------------------------------------------------------------------- # Date Modification Author # ------------------------------------------------------------------------- # 2004AUG30 Adapted to calamaris staehler #========================================================================== package calamaris::calAxestype; ($axestype::VERSION) = '$Revision: 3.2 $' =~ /\s([\d.]+)/; use strict; use lib '/usr/local'; use GD::Graph; use GD::Graph::utils qw(:all); use Carp; @calamaris::calAxestype::ISA = qw(GD::Graph); use constant PI => 4 * atan2(1,1); my %Defaults = ( # Set the length for the 'short' ticks on the axes. x_tick_length => 4, y_tick_length => 4, # Do you want ticks to span the entire width of the graph? x_long_ticks => 0, y_long_ticks => 0, # Number of ticks for the y axis y_tick_number => 5, x_tick_number => undef, # CONTRIB Scott Prahl x_tick_offset => 0, # CONTRIB Damon Brodi # Skip every nth label. if 1 will print every label on the axes, # if 2 will print every second, etc.. x_label_skip => 1, y_label_skip => 1, # Do we want ticks on the x axis? x_ticks => 1, x_all_ticks => 0, # Where to place the x and y labels x_label_position => 3/4, y_label_position => 1/2, # vertical printing of x labels x_labels_vertical => 0, # Draw axes as a box? (otherwise just left and bottom) box_axis => 1, # Disable axes? # undef -> all axes, 0 -> Only line for bars, other -> no axes at all. no_axes => undef, # Use two different axes for the first and second dataset. The first # will be displayed using the left axis, the second using the right # axis. You cannot use more than two datasets when this option is on. two_axes => 0, # Which axis to use for each dataset. This only is in effect when # two_axes is true. The axis number will wrap around, just like # the dclrs array. use_axis => [1, 2], # Print values on the axes? x_plot_values => 1, y_plot_values => 1, # Space between axis and text axis_space => 4, # Do you want bars to be drawn on top of each other, or side by side? overwrite => 0, # This will replace 'overwrite = 2'. For now, it is hardcoded to set # overwrite to 2 cumulate => 0, # Do you want me to correct the width of the graph, so that bars are # always drawn with a nice integer number of pixels? # # The GD::Graph::bars::initialise sub will switch this on. # Do not set this to anything else than undef! correct_width => undef, # XXX The following two need to get better defaults. Maybe computed. # Draw the zero axis in the graph in case there are negative values zero_axis => 0, # Draw the zero axis, but do not draw the bottom axis, in case # box-axis == 0 # This also moves the x axis labels to the zero axis zero_axis_only => 0, # Size of the legend markers legend_marker_height => 8, legend_marker_width => 12, legend_spacing => 4, legend_placement => 'BC', # '[BR][LCR]' lg_cols => undef, # Display the y values above the bar or point in the graph. show_values => undef, values_vertical => undef, # vertical? values_space => 4, # extra spacing values_format => undef, # how to format the value # Draw the X axis left and the y1 axis at the bottom (y2 at top) rotate_chart => undef, # CONTRIB Edwin Hildebrand # How narrow is a dataset allowed to become before we drop the # accents? accent_treshold => 4, # Format of the numbers on the x and y axis y_number_format => undef, x_number_format => undef, # CONTRIB Scott Prahl # and some attributes without default values x_label => undef, y_label => undef, y1_label => undef, y2_label => undef, x_min_value => undef, x_max_value => undef, y_min_value => undef, y1_min_value => undef, y2_min_value => undef, y_max_value => undef, y1_max_value => undef, y2_max_value => undef, y_min_range => undef, # CONTRIB Ben Tilly y1_min_range => undef, y2_min_range => undef, borderclrs => undef, # XXX # Multiple inheritance (linespoints and mixed) finally bit me. The # _has_defaults and set methods can only work correctly when the # spot where the defaults are kept are in a mutual parent, which # would be this. The odd implementation of SUPER doesn't help # XXX points # The size of the marker to use in the points and linespoints graphs # in pixels marker_size => 4, # attributes with no default markers => undef, # XXX lines # The width of the line to use in the lines and linespoints graphs # in pixels line_width => 1, # Set the scale of the line types line_type_scale => 8, # Which line types to use line_types => [1], # Skip undefined values, and don't draw them at all skip_undef => 0, # XXX bars # Spacing between the bars bar_width => undef, bar_spacing => 0, set_spacing => 0, # cycle through colours per data point, not set cycle_clrs => 0, # colour of the shadow shadowclr => 'dgray', shadow_depth => 0, # XXX mixed default_type => 'lines', types => undef, ); sub _has_default { my $self = shift; my $attr = shift || return; exists $Defaults{$attr} || $self->SUPER::_has_default($attr); } sub initialise { my $self = shift; $self->SUPER::initialise(); while (my($key, $val) = each %Defaults) { $self->{$key} = $val } $self->set_x_label_font(GD::gdSmallFont); $self->set_y_label_font(GD::gdSmallFont); $self->set_x_axis_font(GD::gdTinyFont); $self->set_y_axis_font(GD::gdTinyFont); $self->set_legend_font(GD::gdTinyFont); $self->set_values_font(GD::gdTinyFont); } # PUBLIC sub plot { my $self = shift; my $data = shift; $self->check_data($data) or return; $self->init_graph() or return; $self->setup_text() or return; $self->setup_legend(); $self->setup_coords() or return; $self->draw_text(); unless (defined $self->{no_axes}) { $self->draw_axes(); $self->draw_ticks() or return; } $self->draw_data() or return; $self->draw_values() or return; $self->draw_legend(); return $self->{graph} } sub set { my $self = shift; my %args = @_; for (keys %args) { /^tick_length$/ and do { $self->{x_tick_length} = $self->{y_tick_length} = $args{$_}; delete $args{$_}; next; }; /^long_ticks$/ and do { $self->{x_long_ticks} = $self->{y_long_ticks} = $args{$_}; delete $args{$_}; next; }; /^overwrite$/ and do { $self->{cumulate} = 1 if $args{$_} == 2; $self->{overwrite} = $args{$_}; delete $args{$_}; next; }; /^cumulate$/ and do { $self->{cumulate} = $args{$_}; # XXX And for now $self->{overwrite} = 2 if $args{$_}; delete $args{$_}; next; }; } return $self->SUPER::set(%args); } sub setup_text { my $self = shift; $self->{gdta_x_label}->set(colour => $self->{lci}); $self->{gdta_y_label}->set(colour => $self->{lci}); $self->{xlfh} = $self->{gdta_x_label}->get('height'); $self->{ylfh} = $self->{gdta_y_label}->get('height'); $self->{gdta_x_axis}->set(colour => $self->{alci}); $self->{gdta_y_axis}->set(colour => $self->{alci}); $self->{xafh} = $self->{gdta_x_axis}->get('height'); $self->{yafh} = $self->{gdta_x_axis}->get('height'); $self->{gdta_title}->set(colour => $self->{tci}); $self->{gdta_title}->set_align('top', 'center'); $self->{tfh} = $self->{gdta_title}->get('height'); $self->{gdta_legend}->set(colour => $self->{legendci}); $self->{gdta_legend}->set_align('top', 'left'); $self->{lgfh} = $self->{gdta_legend}->get('height'); $self->{gdta_values}->set(colour => $self->{valuesci}); unless ($self->{rotate_chart}) { if ($self->{values_vertical}) { $self->{gdta_values}->set_align('center', 'left'); } else { $self->{gdta_values}->set_align('bottom', 'center'); } } else { if ($self->{values_vertical}) { $self->{gdta_values}->set_align('top', 'center'); } else { $self->{gdta_values}->set_align('center', 'left'); } } return $self; } sub set_x_label_font # (fontname) { my $self = shift; $self->_set_font('gdta_x_label', @_); } sub set_y_label_font # (fontname) { my $self = shift; $self->_set_font('gdta_y_label', @_); } sub set_x_axis_font # (fontname) { my $self = shift; $self->_set_font('gdta_x_axis', @_); } sub set_y_axis_font # (fontname) { my $self = shift; $self->_set_font('gdta_y_axis', @_); } sub set_values_font { my $self = shift; $self->_set_font('gdta_values', @_); } sub set_legend # List of legend keys { my $self = shift; $self->{legend} = [@_]; } sub set_legend_font # (font name) { my $self = shift; $self->_set_font('gdta_legend', @_); } sub get_hotspot { my $self = shift; my $ds = shift; # Which data set my $np = shift; # Which data point? if (defined $np && defined $ds) { return @{$self->{_hotspots}->[$ds]->[$np]}; } elsif (defined $ds) { return @{$self->{_hotspots}->[$ds]}; } else { return @{$self->{_hotspots}}; } } sub _set_feature_coords { my $self = shift; my $feature = shift; my $type = shift; $self->{_feat_coords}->{$feature} = [ $type, @_ ]; } sub _set_text_feature_coords { my $self = shift; my $feature = shift; $self->_set_feature_coords($feature, "rect", @_[0,1,4,5]); } sub get_feature_coordinates { my $self = shift; my $feature = shift; if ($feature) { $self->{_feat_coords}->{$feature}; } else { $self->{_feat_coords}; } } # PRIVATE # inherit check_data from GD::Graph # # calculate the bottom of the bounding box for the graph # sub setup_bottom_boundary { my $self = shift; $self->{bottom} = $self->{height} - $self->{b_margin} - 1; if (! $self->{rotate_chart}) { # X label $self->{bottom} -= $self->{xlfh} + $self->{text_space} if $self->{xlfh}; # X axis tick labels $self->{bottom} -= $self->{x_label_height} + $self->{axis_space} if $self->{xafh}; } else { # Y1 label $self->{bottom} -= $self->{ylfh} + $self->{text_space} if $self->{y1_label}; # Y1 axis labels $self->{bottom} -= $self->{y_label_height}[1] + $self->{axis_space} if $self->{y_label_height}[1]; } } # # Calculate the top of the bounding box for the graph # sub setup_top_boundary { my $self = shift; $self->{top} = $self->{t_margin}; # Chart title $self->{top} += $self->{tfh} + $self->{text_space} if $self->{tfh}; if (! $self->{rotate_chart}) { # Make sure the text for the y axis tick markers fits on the canvas $self->{top} = $self->{yafh}/2 if $self->{top} == 0; } else { if ($self->{two_axes}) { # Y2 label $self->{top} += $self->{ylfh} + $self->{text_space} if $self->{y2_label}; # Y2 axis labels $self->{top} += $self->{y_label_height}[2] + $self->{axis_space} if $self->{y_label_height}[2]; } } } # # calculate the left of the bounding box for the graph # sub setup_left_boundary { my $self = shift; $self->{left} = $self->{l_margin}; if (! $self->{rotate_chart}) { # Y1 label $self->{left} += $self->{ylfh} + $self->{text_space} if $self->{y1_label}; # Y1 axis labels $self->{left} += $self->{y_label_len}[1] + $self->{axis_space} if $self->{y_label_len}[1]; } else { # X label $self->{left} += $self->{xlfh} + $self->{text_space} if $self->{x_label}; # X axis labels $self->{left} += $self->{x_label_width} + $self->{axis_space} if $self->{x_label_width}; } } # # calculate the right of the bounding box for the graph # sub setup_right_boundary { my $self = shift; $self->{right} = $self->{width} - $self->{r_margin} - 1; if (! $self->{rotate_chart}) { if ($self->{two_axes}) { # Y2 label $self->{right} -= $self->{ylfh} + $self->{text_space} if $self->{y2_label}; # Y2 axis label $self->{right} -= $self->{y_label_len}[2] + $self->{axis_space} if $self->{y_label_len}[2]; } } else { # Adjust right margin to allow last label of y axes. Only do # this when the right margin doesn't have enough space # already. # # TODO Don't assume rightmost label is the same as the # longest label (stored in y_label_len) The worst that can # happen now is that we reserve too much space. my $max_len = $self->{y_label_len}[1]; if ($self->{two_axes}) { $max_len = $self->{y_label_len}[2] if $self->{y_label_len}[2] > $max_len; } $max_len = int ($max_len/2); if ($self->{right} + $max_len >= $self->{width} - $self->{r_margin}) { $self->{right} -= $max_len; } } } sub _setup_boundaries { my $self = shift; $self->setup_bottom_boundary(); $self->setup_top_boundary(); $self->setup_left_boundary(); $self->setup_right_boundary(); if ($self->correct_width && !$self->{x_tick_number}) { if (! $self->{rotate_chart}) { # Make sure we have a nice integer number of pixels $self->{r_margin} += ($self->{right} - $self->{left}) % ($self->{_data}->num_points + 1); $self->setup_right_boundary(); } else { # Make sure we have a nice integer number of pixels $self->{b_margin} += ($self->{bottom} - $self->{top}) % ($self->{_data}->num_points + 1); $self->setup_bottom_boundary(); } } return $self->_set_error('Vertical size too small') if $self->{bottom} <= $self->{top}; return $self->_set_error('Horizontal size too small') if $self->{right} <= $self->{left}; return $self; } # This method should return 1 if the width of the graph needs to be # corrected to whole integers, and 0 if not. The default behaviour is to # not correct the width. Individual classes should override this by # setting the $self->{correct_width} attribute in their initialise # method. Only in complex cases (see mixed.pm) should this method be # overridden sub correct_width { $_[0]->{correct_width} } sub setup_x_step_size_v { my $s = shift; # calculate the step size for x data # CONTRIB Changes by Scott Prahl if (defined $s->{x_tick_number}) { my $delta = ($s->{right} - $s->{left})/($s->{x_max} - $s->{x_min}); # 'True' numerical X axis addition # From: Gary Deschaines if (defined($s->{x_min_value}) && defined($s->{x_max_value})) { $s->{x_offset} = $s->{left}; $s->{x_step} = $delta; } else { $s->{x_offset} = ($s->{true_x_min} - $s->{x_min}) * $delta + $s->{left}; $s->{x_step} = ($s->{true_x_max} - $s->{true_x_min}) * $delta/($s->{_data}->num_points - 1); } } else { $s->{x_step} = ($s->{right} - $s->{left})/($s->{_data}->num_points + 1); $s->{x_offset} = $s->{left}; } } sub setup_x_step_size_h { my $s = shift; # calculate the step size for x data # CONTRIB Changes by Scott Prahl if (defined $s->{x_tick_number}) { my $delta = ($s->{bottom} - $s->{top})/($s->{x_max} - $s->{x_min}); # 'True' numerical X axis addition # From: Gary Deschaines if (defined($s->{x_min_value}) && defined($s->{x_max_value})) { $s->{x_offset} = $s->{top}; $s->{x_step} = $delta; } else { $s->{x_offset} = ($s->{true_x_min} - $s->{x_min}) * $delta + $s->{top}; $s->{x_step} = ($s->{true_x_max} - $s->{true_x_min}) * $delta/($s->{_data}->num_points - 1); } } else { $s->{x_step} = ($s->{bottom} - $s->{top})/($s->{_data}->num_points + 1); $s->{x_offset} = $s->{top}; } } sub setup_coords { my $s = shift; # Do some sanity checks $s->{two_axes} = 0 if $s->{_data}->num_sets < 2 || $s->{two_axes} < 0; $s->{two_axes} = 1 if $s->{two_axes} > 1; delete $s->{y_label2} unless $s->{two_axes}; # Set some heights for text $s->{tfh} = 0 unless $s->{title}; $s->{xlfh} = 0 unless $s->{x_label}; # Make sure the y1 axis has a label if there is one set for y in # general $s->{y1_label} = $s->{y_label} if !$s->{y1_label} && $s->{y_label}; # Set axis tick text heights and widths to 0 if they don't need to # be plotted. $s->{xafh} = 0, $s->{xafw} = 0 unless $s->{x_plot_values}; $s->{yafh} = 0, $s->{yafw} = 0 unless $s->{y_plot_values}; # Calculate minima and maxima for the axes $s->set_max_min() or return; # Create the labels for the axes, and calculate the max length $s->create_y_labels(); $s->create_x_labels(); # CONTRIB Scott Prahl # Calculate the boundaries of the chart $s->_setup_boundaries() or return; # CONTRIB Scott Prahl # make sure that we can generate valid x tick marks undef($s->{x_tick_number}) if $s->{_data}->num_points < 3; undef($s->{x_tick_number}) if !defined $s->{x_max} || !defined $s->{x_min} || $s->{x_max} == $s->{x_min}; $s->{rotate_chart} ? $s->setup_x_step_size_h() : $s->setup_x_step_size_v(); # get the zero axis level my ($zl, $zb) = $s->val_to_pixel(0, 0, 1); $s->{zeropoint} = $s->{rotate_chart} ? $zl : $zb; # More sanity checks $s->{x_label_skip} = 1 if $s->{x_label_skip} < 1; $s->{y_label_skip} = 1 if $s->{y_label_skip} < 1; $s->{y_tick_number} = 1 if $s->{y_tick_number} < 1; return $s; } sub create_y_labels { my $self = shift; # XXX This should really be y_label_width $self->{y_label_len}[$_] = 0 for 1, 2; $self->{y_label_height}[$_] = 0 for 1, 2; for my $t (0 .. $self->{y_tick_number}) { # XXX Ugh, why did I ever do it this way? How bloody obscure. for my $axis (1 .. ($self->{two_axes} + 1)) { my $label = $self->{y_min}[$axis] + $t * ($self->{y_max}[$axis] - $self->{y_min}[$axis]) / $self->{y_tick_number}; $self->{y_values}[$axis][$t] = $label; if (defined $self->{y_number_format}) { $label = ref $self->{y_number_format} eq 'CODE' ? &{$self->{y_number_format}}($label) : sprintf($self->{y_number_format}, $label); } $self->{gdta_y_axis}->set_text($label); my $len = $self->{gdta_y_axis}->get('width'); $self->{y_labels}[$axis][$t] = $label; # TODO Allow vertical y labels $self->{y_label_len}[$axis] = $len if $len > $self->{y_label_len}[$axis]; $self->{y_label_height}[$axis] = $self->{yafh}; } } } sub get_x_axis_label_length { my $self = shift; my @values = $self->{x_tick_number} ? @{$self->{x_values}} : $self->{_data}->x_values; my $maxlen = 0; foreach my $label (@values) { $self->{gdta_x_axis}->set_text($label); my $len = $self->{gdta_x_axis}->get('width'); $maxlen = $len if $maxlen < $len; } return $maxlen; } # CONTRIB Scott Prahl sub create_x_labels { my $self = shift; my $maxlen = 0; $self->{x_label_height} = 0; $self->{x_label_width} = 0; if (defined $self->{x_tick_number}) { # We want to emulate numerical x axes foreach my $t (0..$self->{x_tick_number}) { my $label = $self->{x_min} + $t * ($self->{x_max} - $self->{x_min})/$self->{x_tick_number}; $self->{x_values}[$t] = $label; if (defined $self->{x_number_format}) { $label = ref $self->{x_number_format} eq 'CODE' ? &{$self->{x_number_format}}($label) : sprintf($self->{x_number_format}, $label); } $self->{gdta_x_label}->set_text($label); my $len = $self->{gdta_x_label}->get('width'); $self->{x_labels}[$t] = $label; $maxlen = $len if $len > $self->{x_label_height}; } } else { $maxlen = $self->get_x_axis_label_length; } $self->{x_label_height} = $self->{x_labels_vertical} ? $maxlen : $self->{xafh}; $self->{x_label_width} = $self->{x_labels_vertical} ? $self->{xafh} : $maxlen; } # # The drawing of labels for the axes. This is split up in the four # positions a label can appear in, depending on a few settings. These # settings are all dealt with in the draw_x_labels and draw_y_labels # subroutines, which in turn call the approriate directional label # drawer # sub draw_left_label { my ($self, $label, $align) = @_; $label->set_align('top', 'left'); my $tx = $self->{l_margin}; my $ty = $self->{bottom} - $align * ($self->{bottom} - $self->{top}) + $align * $label->get('width'); $label->draw($tx, $ty, PI/2); } sub draw_bottom_label { my ($self, $label, $align) = @_; $label->set_align('bottom', 'left'); my $tx = $self->{left} + $align * ($self->{right} - $self->{left}) - $align * $label->get('width'); my $ty = $self->{height} - $self->{b_margin}; $label->draw($tx, $ty, 0); } sub draw_top_label { my ($self, $label, $align) = @_; $label->set_align('top', 'left'); my $tx = $self->{left} + $align * ($self->{right} - $self->{left}) - $align * $label->get('width'); my $ty = $self->{t_margin}; $ty += $self->{tfh} + $self->{text_space} if $self->{tfh}; $label->draw($tx, $ty, 0); } sub draw_right_label { my ($self, $label, $align) = @_; $label->set_align('bottom', 'left'); my $tx = $self->{width} - $self->{r_margin}; my $ty = $self->{bottom} - $align * ($self->{bottom} - $self->{top}) + $align * $label->get('width'); $label->draw($tx, $ty, PI/2); } sub draw_x_label { my $self = shift; my ($tx, $ty, $a); my @coords; # coordinates of the label drawn return unless $self->{x_label}; $self->{gdta_x_label}->set_text($self->{x_label}); if ($self->{rotate_chart}) { @coords = $self->draw_left_label($self->{gdta_x_label}, $self->{x_label_position}); } else { @coords = $self->draw_bottom_label($self->{gdta_x_label}, $self->{x_label_position}); } $self->_set_text_feature_coords("x_label", @coords); } sub draw_y_labels { my $self = shift; my @coords; # coordinates of the labels drawn if (defined $self->{y1_label}) { $self->{gdta_y_label}->set_text($self->{y1_label}); if ($self->{rotate_chart}) { @coords = $self->draw_bottom_label($self->{gdta_y_label}, $self->{y_label_position}); } else { @coords = $self->draw_left_label($self->{gdta_y_label}, $self->{y_label_position}); } $self->_set_text_feature_coords("y1_label", @coords); $self->_set_text_feature_coords("y_label", @coords); } if ( $self->{two_axes} && defined $self->{y2_label} ) { $self->{gdta_y_label}->set_text($self->{y2_label}); if ($self->{rotate_chart}) { @coords = $self->draw_top_label($self->{gdta_y_label}, $self->{y_label_position}); } else { @coords = $self->draw_right_label($self->{gdta_y_label}, $self->{y_label_position}); } $self->_set_text_feature_coords("y2_label", @coords); } } sub draw_text { my $self = shift; if ($self->{title}) { my $xc = $self->{left} + ($self->{right} - $self->{left})/2; $self->{gdta_title}->set_align('top', 'center'); $self->{gdta_title}->set_text($self->{title}); my @coords = $self->{gdta_title}->draw($xc, $self->{t_margin}); $self->_set_text_feature_coords("title", @coords); } $self->draw_x_label(); $self->draw_y_labels(); } sub draw_axes { my $self = shift; my ($l, $r, $b, $t) = ( $self->{left}, $self->{right}, $self->{bottom}, $self->{top} ); # Sanity check for zero_axis and zero_axis_only unless ($self->{y_min}[1] < 0 && $self->{y_max}[1] > 0) { $self->{zero_axis} = 0; $self->{zero_axis_only} = 0; } if ( $self->{box_axis} ) { $self->{graph}->filledRectangle($l+1, $t+1, $r-1, $b-1, $self->{boxci}) if $self->{boxci}; $self->{graph}->rectangle($l, $t, $r, $b, $self->{fgci}); } else { $self->{graph}->line($l, $t, $l, $b, $self->{fgci}); $self->{graph}->line($l, $b, $r, $b, $self->{fgci}) unless ($self->{zero_axis_only}); $self->{graph}->line($r, $b, $r, $t, $self->{fgci}) if ($self->{two_axes}); } if ($self->{zero_axis} or $self->{zero_axis_only}) { my ($x, $y) = $self->val_to_pixel(0, 0, 1); $self->{graph}->line($l, $y, $r, $y, $self->{fgci}); } $self->_set_feature_coords("axes", "rect", $l, $b, $r, $t); } # # Ticks and values for y axes # sub draw_y_ticks_h { my $self = shift; for my $t (0 .. $self->{y_tick_number}) { for my $axis (1 .. ($self->{two_axes} + 1)) { my $value = $self->{y_values}[$axis][$t]; my $label = $self->{y_labels}[$axis][$t]; my ($x, $y) = $self->val_to_pixel(0, $value, $axis); $y = ($axis == 1) ? $self->{bottom} : $self->{top}; if ($self->{y_long_ticks}) { $self->{graph}->line( $x, $self->{bottom}, $x, $self->{top}, $self->{fgci} ) unless ($axis-1); } else { $self->{graph}->line( $x, $y, $x, $y - $self->{y_tick_length}, $self->{fgci} ); } next if $t % ($self->{y_label_skip}) || ! $self->{y_plot_values}; $self->{gdta_y_axis}->set_text($label); if ($axis == 1) { $self->{gdta_y_axis}->set_align('top', 'center'); $y += $self->{axis_space}; } else { $self->{gdta_y_axis}->set_align('bottom', 'center'); $y -= $self->{axis_space}; } $self->{gdta_y_axis}->draw($x, $y); } } return $self; } sub draw_y_ticks_v { my $self = shift; for my $t (0 .. $self->{y_tick_number}) { # XXX Ugh, why did I ever do it this way? How bloody obscure. for my $axis (1 .. ($self->{two_axes} + 1)) { my $value = $self->{y_values}[$axis][$t]; my $label = $self->{y_labels}[$axis][$t]; my ($x, $y) = $self->val_to_pixel(0, $value, $axis); $x = ($axis == 1) ? $self->{left} : $self->{right}; if ($self->{y_long_ticks}) { $self->{graph}->line( $x, $y, $x + $self->{right} - $self->{left}, $y, $self->{fgci} ) unless ($axis-1); } else { $self->{graph}->line( $x, $y, $x + (3 - 2 * $axis) * $self->{y_tick_length}, $y, $self->{fgci} ); } next if $t % ($self->{y_label_skip}) || ! $self->{y_plot_values}; $self->{gdta_y_axis}->set_text($label); if ($axis == 1) { $self->{gdta_y_axis}->set_align('center', 'right'); $x -= $self->{axis_space}; } else { $self->{gdta_y_axis}->set_align('center', 'left'); $x += $self->{axis_space}; } $self->{gdta_y_axis}->draw($x, $y); } } return $self; } sub draw_y_ticks { #TODO Clean this up! $_[0]->{rotate_chart} ? goto &draw_y_ticks_h : goto &draw_y_ticks_v; } # # Ticks and values for x axes # sub draw_x_ticks_h { my $self = shift; for (my $i = 0; $i < $self->{_data}->num_points; $i++) { my ($x, $y) = $self->val_to_pixel($i + 1, 0, 1); $x = $self->{left} unless $self->{zero_axis_only}; # CONTRIB Damon Brodie for x_tick_offset next if (!$self->{x_all_ticks} and ($i - $self->{x_tick_offset}) % $self->{x_label_skip} and $i != $self->{_data}->num_points - 1 ); if ($self->{x_ticks}) { if ($self->{x_long_ticks}) { $self->{graph}->line($self->{left}, $y, $self->{right}, $y, $self->{fgci}); } else { $self->{graph}->line( $x, $y, $x + $self->{x_tick_length}, $y, $self->{fgci}); } } # CONTRIB Damon Brodie for x_tick_offset next if ($i - $self->{x_tick_offset}) % ($self->{x_label_skip}) and $i != $self->{_data}->num_points - 1; $self->{gdta_x_axis}->set_text($self->{_data}->get_x($i)); my $angle = 0; if ($self->{x_labels_vertical}) { $self->{gdta_x_axis}->set_align('bottom', 'center'); $angle = PI/2; } else { $self->{gdta_x_axis}->set_align('center', 'right'); } $self->{gdta_x_axis}->draw($x - $self->{axis_space}, $y, $angle); } return $self; } sub draw_x_ticks_v { my $self = shift; for (my $i = 0; $i < $self->{_data}->num_points; $i++) { my ($x, $y) = $self->val_to_pixel($i + 1, 0, 1); $y = $self->{bottom} unless $self->{zero_axis_only}; # CONTRIB Damon Brodie for x_tick_offset next if (!$self->{x_all_ticks} and ($i - $self->{x_tick_offset}) % $self->{x_label_skip} and $i != $self->{_data}->num_points - 1 ); if ($self->{x_ticks}) { if ($self->{x_long_ticks}) { $self->{graph}->line($x, $self->{bottom}, $x, $self->{top}, $self->{fgci}); } else { $self->{graph}->line($x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci}); } } # CONTRIB Damon Brodie for x_tick_offset next if ($i - $self->{x_tick_offset}) % ($self->{x_label_skip}) and $i != $self->{_data}->num_points - 1; $self->{gdta_x_axis}->set_text($self->{_data}->get_x($i)); my $angle = 0; if ($self->{x_labels_vertical}) { $self->{gdta_x_axis}->set_align('center', 'right'); $angle = PI/2; } else { $self->{gdta_x_axis}->set_align('top', 'center'); } $self->{gdta_x_axis}->draw($x, $y + $self->{axis_space}, $angle); } return $self; } sub draw_x_ticks { #TODO Clean this up! $_[0]->{rotate_chart} ? goto &draw_x_ticks_h : goto &draw_x_ticks_v; } # CONTRIB Scott Prahl # Assume x array contains equally spaced x-values # and generate an appropriate axis # #### # 'True' numerical X axis addition # From: Gary Deschaines # # These modification to draw_x_ticks_number pass x-tick values to the # val_to_pixel subroutine instead of x-tick indices when ture numerical # x-axis mode is detected. Also, x_tick_offset and x_label_skip are # processed differently when true numerical x-axis mode is detected to # allow labeled major x-tick marks and un-labeled minor x-tick marks. # # For example: # # x_tick_number => 14, # x_ticks => 1, # x_long_ticks => 1, # x_tick_length => -4, # x_min_value => 100, # x_max_value => 800, # x_tick_offset => 2, # x_label_skip => 2, # # # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # | | | | | | | | | | | | | # 1 -| | | | | | | | | | | | | # | | | | | | | | | | | | | # 0 _|_________|____|____|____|____|____|____|____|____|____|____|_________| # | | | | | | | | | | | # 200 300 400 500 600 700 sub draw_x_ticks_number { my $self = shift; for my $i (0 .. $self->{x_tick_number}) { my ($value, $x, $y); if (defined($self->{x_min_value}) && defined($self->{x_max_value})) { next if ($i - $self->{x_tick_offset}) < 0; next if ($i + $self->{x_tick_offset}) > $self->{x_tick_number}; $value = $self->{x_values}[$i]; ($x, $y) = $self->val_to_pixel($value, 0, 1); } else { $value = ($self->{_data}->num_points - 1) * ($self->{x_values}[$i] - $self->{true_x_min}) / ($self->{true_x_max} - $self->{true_x_min}); ($x, $y) = $self->val_to_pixel($value + 1, 0, 1); } $y = $self->{bottom} unless $self->{zero_axis_only}; if ($self->{x_ticks}) { if ($self->{x_long_ticks}) { # XXX This mod needs to be done everywhere ticks are # drawn if ( $self->{x_tick_length} >= 0 ) { $self->{graph}->line($x, $self->{bottom}, $x, $self->{top}, $self->{fgci}); } else { $self->{graph}->line( $x, $self->{bottom} - $self->{x_tick_length}, $x, $self->{top}, $self->{fgci}); } } else { $self->{graph}->line($x, $y, $x, $y - $self->{x_tick_length}, $self->{fgci} ); } } # If we have to skip labels, we'll do it here. # Make sure to always draw the last one. next if $i % $self->{x_label_skip} && $i != $self->{x_tick_number}; $self->{gdta_x_axis}->set_text($self->{x_labels}[$i]); if ($self->{x_labels_vertical}) { $self->{gdta_x_axis}->set_align('center', 'right'); my $yt = $y + $self->{text_space}/2; $self->{gdta_x_axis}->draw($x, $yt, PI/2); } else { $self->{gdta_x_axis}->set_align('top', 'center'); my $yt = $y + $self->{text_space}/2; $self->{gdta_x_axis}->draw($x, $yt); } } return $self; } sub draw_ticks { my $self = shift; $self->draw_y_ticks() or return; return $self unless $self->{x_plot_values}; if (defined $self->{x_tick_number}) { $self->draw_x_ticks_number() or return; } else { $self->draw_x_ticks() or return; } return $self; } sub draw_data { my $self = shift; # Calculate bar_spacing from bar_width if ($self->{bar_width}) { my $chart_width = $self->{rotate_chart} ? $self->{right} - $self->{left} : $self->{bottom} - $self->{top}; my $n_bars = $self->{_data}->num_points; my $n_sets = $self->{_data}->num_sets; my $bar_space = $chart_width/($n_bars + 1) / ($self->{overwrite} ? 1 : $n_sets); $self->{bar_spacing} = $bar_space - $self->{bar_width}; $self->{bar_spacing} = 0 if $self->{bar_spacing} < 0; } # XXX is this comment still pertinent? # The drawing of 'cumulated' sets needs to be done in reverse, # for area and bar charts. This is mainly because of backward # compatibility for (my $dsn = 1; $dsn <= $self->{_data}->num_sets; $dsn++) { $self->draw_data_set($dsn) or return; } return $self } # # Draw the values of the data point with the bars, lines or markers sub draw_values { my $self = shift; return $self unless $self->{show_values}; my $text_angle = $self->{values_vertical} ? PI/2 : 0; for (my $dsn = 1; $dsn <= $self->{_data}->num_sets; $dsn++) { my @values = $self->{_data}->y_values($dsn) or return $self->_set_error("Impossible illegal data set: $dsn", $self->{_data}->error); my @display = $self->{show_values}->y_values($dsn) or next; for (my $i = 0; $i < @values; $i++) { next unless defined $display[$i]; my ($xp, $yp); if (defined($self->{x_min_value}) && defined($self->{x_max_value})) { ($xp, $yp) = $self->val_to_pixel( $self->{_data}->get_x($i), $values[$i], $dsn); } else { ($xp, $yp) = $self->val_to_pixel($i+1, $values[$i], $dsn); } $yp -= $self->{values_space}; my $value = $display[$i]; if (defined $self->{values_format}) { $value = ref $self->{values_format} eq 'CODE' ? &{$self->{values_format}}($value) : sprintf($self->{values_format}, $value); } $self->{gdta_values}->set_text($value); $self->{gdta_values}->draw($xp, $yp, $text_angle); } } return $self } # # draw_data_set is in sub classes # sub draw_data_set { # ABSTRACT my $self = shift; $self->die_abstract( "sub draw_data missing, ") } # # This method corrects the minimum and maximum y values for chart # types that need to always include a zero point. # This is supposed to be called before the methods that pick # good-looking values. # # Input: current minimum and maximum. # Output: new minimum and maximum. # sub _correct_y_min_max { my $self = shift; my ($min, $max) = @_; # Make sure bars and area always have a zero offset # Only bars and areas need return ($min, $max) unless $self->isa("GD::Graph::bars") or $self->isa("GD::Graph::area"); # If either $min or $max are 0, we can return return ($min, $max) if $max == 0 or $min == 0; # If $min and $max on opposite end of zero axis, no work needed return ($min, $max) unless $min/$max > 0; if ($min > 0) { $min = 0; } else { $max = 0; } return ($min, $max); } # # Figure out the maximum values for the vertical exes, and calculate # a more or less sensible number for the tops. # sub set_max_min { my $self = shift; # XXX fix to calculate min and max for each data set # independently, and store in an array. Then, based on use_axis, # pick the minimust and maximust for each axis, and use those. # First, calculate some decent values if ( $self->{two_axes} ) { my $min_range_1 = defined($self->{min_range_1}) ? $self->{min_range_1} : $self->{min_range}; my $min_range_2 = defined($self->{min_range_2}) ? $self->{min_range_2} : $self->{min_range}; ( $self->{y_min}[1], $self->{y_max}[1], $self->{y_min}[2], $self->{y_max}[2], $self->{y_tick_number} ) = _best_dual_ends( $self->_correct_y_min_max($self->{_data}->get_min_max_y(1)), $min_range_1, $self->_correct_y_min_max($self->{_data}->get_min_max_y(2)), $min_range_2, $self->{y_tick_number} ); } else { my ($y_min, $y_max); if ($self->{cumulate}) { my $data_set = $self->{_data}->copy(); $data_set->cumulate; ($y_min, $y_max) = $data_set->get_min_max_y($data_set->num_sets); } else { ($y_min, $y_max) = $self->{_data}->get_min_max_y_all; } ($y_min, $y_max) = $self->_correct_y_min_max($y_min, $y_max); ($self->{y_min}[1], $self->{y_max}[1], $self->{y_tick_number}) = _best_ends($y_min, $y_max, @$self{'y_tick_number','y_min_range'}); } if (defined($self->{x_tick_number})) { if (defined($self->{x_min_value}) && defined($self->{x_max_value})) { $self->{true_x_min} = $self->{x_min_value}; $self->{true_x_max} = $self->{x_max_value}; } else { ($self->{true_x_min}, $self->{true_x_max}) = $self->{_data}->get_min_max_x; ($self->{x_min}, $self->{x_max}, $self->{x_tick_number}) = _best_ends($self->{true_x_min}, $self->{true_x_max}, @$self{'y_tick_number','y_min_range'}); } } # Overwrite these with any user supplied ones $self->{y_min}[1] = $self->{y_min_value} if defined $self->{y_min_value}; $self->{y_min}[2] = $self->{y_min_value} if defined $self->{y_min_value}; $self->{y_max}[1] = $self->{y_max_value} if defined $self->{y_max_value}; $self->{y_max}[2] = $self->{y_max_value} if defined $self->{y_max_value}; $self->{y_min}[1] = $self->{y1_min_value} if defined $self->{y1_min_value}; $self->{y_max}[1] = $self->{y1_max_value} if defined $self->{y1_max_value}; $self->{y_min}[2] = $self->{y2_min_value} if defined $self->{y2_min_value}; $self->{y_max}[2] = $self->{y2_max_value} if defined $self->{y2_max_value}; $self->{x_min} = $self->{x_min_value} if defined $self->{x_min_value}; $self->{x_max} = $self->{x_max_value} if defined $self->{x_max_value}; if ($self->{two_axes}) { # If we have two axes, we need to make sure that the zero is at # the same spot. # And we need to change the number of ticks on the axes my $l_range = $self->{y_max}[1] - $self->{y_min}[1]; my $r_range = $self->{y_max}[2] - $self->{y_min}[2]; my $l_top = $self->{y_max}[1]/$l_range; my $r_top = $self->{y_max}[2]/$r_range; my $l_bot = $self->{y_min}[1]/$l_range; my $r_bot = $self->{y_min}[2]/$r_range; if ($l_top > $r_top) { $self->{y_max}[2] = $l_top * $r_range; $self->{y_min}[1] = $r_bot * $l_range; $self->{y_tick_number} *= 1 + abs $r_bot - $l_bot; } else { $self->{y_max}[1] = $r_top * $l_range; $self->{y_min}[2] = $l_bot * $r_range; $self->{y_tick_number} *= 1 + abs $r_top - $l_top; } } # Check to see if we have sensible values if ($self->{two_axes}) { for my $i (1 .. 2) { my ($min, $max) = $self->{_data}->get_min_max_y($i); return $self->_set_error("Minimum for y" . $i . " too large") if $self->{y_min}[$i] > $min; return $self->_set_error("Maximum for y" . $i . " too small") if $self->{y_max}[$i] < $max; } } return $self; } # CONTRIB Scott Prahl # # Calculate best endpoints and number of intervals for an axis and # returns ($nice_min, $nice_max, $n), where $n is the number of # intervals and # # $nice_min <= $min < $max <= $nice_max # # Usage: # ($nmin,$nmax,$nint) = _best_ends(247, 508); # ($nmin,$nmax) = _best_ends(247, 508, 5); # use 5 intervals # ($nmin,$nmax,$nint) = _best_ends(247, 508, [4..7]); # best of 4,5,6,7 intervals # ($nmin,$nmax,$nint) = _best_ends(247, 508, 'auto'); # best of 3,4,5,6 intervals # ($nmin,$nmax,$nint) = _best_ends(247, 508, [2..5]); # best of 2,3,4,5 intervals sub _best_ends { my ($min, $max, $n_ref, $min_range) = @_; # Adjust for the min range if need be ($min, $max) = _fit_vals_range($min, $max, $min_range); my ($best_min, $best_max, $best_num) = ($min, $max, 1); # mgjv - Sometimes, for odd values, and only one data set, this will be # necessary _after_ the previous step, not before. Data sets of one # long with negative values were causing infinite loops later on. ($min, $max) = ($max, $min) if ($min > $max); # Check that min and max are not the same, and not 0 ($min, $max) = ($min) ? ($min * 0.5, $min * 1.5) : (-1,1) if ($max == $min); my @n = ref($n_ref) ? @$n_ref : $n_ref; if (@n <= 0) { @n = (3..6); } else { @n = map { ref($_) ? @$_ : /(\d+)/i ? $1 : (3..6) } @n; } my $best_fit = 1e30; my $range = $max - $min; # create array of interval sizes my $s = 1; while ($s < $range) { $s *= 10 } while ($s > $range) { $s /= 10 } my @step = map {$_ * $s} (0.2, 0.5, 1, 2, 5); for my $n (@n) { # Try all numbers of intervals next if ($n < 1); for my $step (@step) { next if ($n != 1) && ($step < $range/$n); # $step too small my ($nice_min, $nice_max, $fit) = _fit_interval($min, $max, $n, $step); next if $best_fit <= $fit; $best_min = $nice_min; $best_max = $nice_max; $best_fit = $fit; $best_num = $n; } } return ($best_min, $best_max, $best_num) } # CONTRIB Ben Tilly # # Calculate best endpoints and number of intervals for a pair of axes # where it is trying to line up the scale of the two intervals. It # returns ($nice_min_1, $nice_max_1, $nice_min_2, $nice_max_2, $n), # where $n is the number of intervals and # # $nice_min_1 <= $min_1 < $max_1 <= $nice_max_1 # $nice_min_2 <= $min_2 < $max_2 <= $nice_max_2 # # and 0 will appear at the same point on both axes. # # Usage: # ($nmin_1,$nmax_1,$nmin_2,$nmax_2,$nint) = _best_dual_ends(247, 508, undef, -1, 5, undef, [2..5]); # etc. (The usage of the last arguments just parallels _best_ends.) # sub _best_dual_ends { my ($min_1, $max_1) = _fit_vals_range(splice @_, 0, 3); my ($min_2, $max_2) = _fit_vals_range(splice @_, 0, 3); my @rem_args = @_; # Fix the situation where both min_1 and max_1 are 0, which makes it # loop forever ($min_1, $max_1) = (0, 1) unless $min_1 or $max_1; my $scale_1 = _max(abs($min_1), abs($max_1)); my $scale_2 = _max(abs($min_2), abs($max_2)); $scale_1 = defined($scale_2) ? $scale_2 : 1 unless defined($scale_1); $scale_2 = $scale_1 unless defined($scale_2); my $ratio = $scale_1 / ($scale_2 || 1); my $fact_1 = my $fact_2 = 1; while ($ratio < sqrt(0.1)) { $ratio *= 10; $fact_2 *= 10; } while ($ratio > sqrt(10)) { $ratio /= 10; $fact_1 *= 10; } my ($best_min_1, $best_max_1, $best_min_2, $best_max_2, $best_n, $best_fit) = ($min_1, $max_1, $min_2, $max_2, 1, 1e10); # Now try all of the ratios of "simple numbers" in the right size-range foreach my $frac ( [1,1], [1,2], [1,3], [2,1], [2,3], [2,5], [3,1], [3,2], [3,4], [3,5], [3,8], [3,10], [4,3], [4,5], [5,2], [5,3], [5,4], [5,6], [5,8], [6,5], [8,3], [8,5], [10,3] ) { my $bfact_1 = $frac->[0] * $fact_1; my $bfact_2 = $frac->[1] * $fact_2; my $min = _min( $min_1/$bfact_1, $min_2/$bfact_2 ); my $max = _max( $max_1/$bfact_1, $max_2/$bfact_2 ); my ($bmin, $bmax, $n) = _best_ends($min, $max, @rem_args); my ($bmin_1, $bmax_1) = ($bfact_1*$bmin, $bfact_1*$bmax); my ($bmin_2, $bmax_2) = ($bfact_2*$bmin, $bfact_2*$bmax); my $fit = _measure_interval_fit($bmin_1, $min_1, $max_1, $bmax_1) + _measure_interval_fit($bmin_2, $min_2, $max_2, $bmax_2); next if $best_fit < $fit; ( $best_min_1, $best_max_1, $best_min_2, $best_max_2, $best_n, $best_fit ) = ( $bmin_1, $bmax_1, $bmin_2, $bmax_2, $n, $fit ); } return ($best_min_1, $best_max_1, $best_min_2, $best_max_2, $best_n); } # Takes $min, $max, $step_count, $step_size. Assumes $min <= $max and both # $step_count and $step_size are positive. Returns the fitted $min, $max, # and a $fit statistic (where smaller is better). Failure to fit the # interval results in a poor fit statistic. :-) sub _fit_interval { my ($min, $max, $step_count, $step_size) = @_; my $nice_min = $step_size * int($min/$step_size); $nice_min -= $step_size if ($nice_min > $min); my $nice_max = ($step_count == 1) ? $step_size * int($max/$step_size + 1) : $nice_min + $step_count * $step_size; my $fit = _measure_interval_fit($nice_min, $min, $max, $nice_max); # Prevent division by zero errors further up return ($min, $max, 0) if ($step_size == 0); return ($nice_min, $nice_max, $fit); } # Takes 2 values and a minimum range. Returns a min and max which holds # both values and is at least that minimum size sub _fit_vals_range { my ($min, $max, $min_range) = @_; ($min, $max) = ($max, $min) if $max < $min; if (defined($min_range) and $min_range > $max - $min) { my $nice_min = $min_range * int($min/$min_range); $nice_min = $nice_min - $min_range if $min < $nice_min; my $nice_max = $max < $nice_min + $min_range ? $nice_min + $min_range : $max; ($min, $max) = ($nice_min, $nice_max); } return ($min, $max); } # Takes $bmin, $min, $max, $bmax and returns a fit statistic for how well # ($bmin, $bmax) encloses the interval ($min, $max). Smaller is better, # and failure to fit will be a very bad fit. Assumes that $min <= $max # and $bmin < $bmax. sub _measure_interval_fit { my ($bmin, $min, $max, $bmax) = @_; return 1000 if $bmin > $min or $bmax < $max; my $range = $max - $min; my $brange = $bmax - $bmin; return $brange < 10 * $range ? ($brange / $range) : 10; } sub _get_bottom { my $self = shift; my ($ds, $np) = @_; my $bottom = $self->{zeropoint}; if ($self->{cumulate} && $ds > 1) { my $left; my $pvalue = $self->{_data}->get_y_cumulative($ds - 1, $np); ($left, $bottom) = $self->val_to_pixel($np + 1, $pvalue, $ds); $bottom = $left if $self->{rotate_chart}; } return $bottom; } # # Convert value coordinates to pixel coordinates on the canvas. # TODO Clean up all the rotate_chart stuff # sub val_to_pixel # ($x, $y, $i) in real coords ($Dataspace), { # return [x, y] in pixel coords my $self = shift; my ($x, $y, $i) = @_; # XXX use_axis my $y_min = ($self->{two_axes} && $i == 2) ? $self->{y_min}[2] : $self->{y_min}[1]; my $y_max = ($self->{two_axes} && $i == 2) ? $self->{y_max}[2] : $self->{y_max}[1]; my $y_step = $self->{rotate_chart} ? abs(($self->{right} - $self->{left})/($y_max - $y_min)) : abs(($self->{bottom} - $self->{top})/($y_max - $y_min)); my $ret_x; my $origin = $self->{rotate_chart} ? $self->{top} : $self->{left}; if (defined($self->{x_min_value}) && defined($self->{x_max_value})) { $ret_x = $origin + ($x - $self->{x_min}) * $self->{x_step}; } else { $ret_x = ($self->{x_tick_number} ? $self->{x_offset} : $origin) + $x * $self->{x_step}; } my $ret_y = $self->{rotate_chart} ? $self->{left} + ($y - $y_min) * $y_step : $self->{bottom} - ($y - $y_min) * $y_step; return $self->{rotate_chart} ? (_round($ret_y), _round($ret_x)) : (_round($ret_x), _round($ret_y)); } # # Legend # sub setup_legend { my $self = shift; return unless defined $self->{legend}; my $maxlen = 0; my $num = 0; # Save some variables $self->{r_margin_abs} = $self->{r_margin}; $self->{b_margin_abs} = $self->{b_margin}; foreach my $legend (@{$self->{legend}}) { if (defined($legend) and $legend ne "") { $self->{gdta_legend}->set_text($legend); my $len = $self->{gdta_legend}->get('width'); $maxlen = ($maxlen > $len) ? $maxlen : $len; $num++; } last if $num >= $self->{_data}->num_sets; } $self->{lg_num} = $num; # calculate the height and width of each element my $legend_height = _max($self->{lgfh}, $self->{legend_marker_height}); $self->{lg_el_width} = $maxlen + $self->{legend_marker_width} + 3 * $self->{legend_spacing}; $self->{lg_el_height} = $legend_height + 2 * $self->{legend_spacing}; my ($lg_pos, $lg_align) = split(//, $self->{legend_placement}); if ($lg_pos eq 'R') { # Always work in one column $self->{lg_cols} = 1; $self->{lg_rows} = $num; # Just for completeness, might use this in later versions $self->{lg_x_size} = $self->{lg_cols} * $self->{lg_el_width}; $self->{lg_y_size} = $self->{lg_rows} * $self->{lg_el_height}; # Adjust the right margin for the rest of the graph $self->{r_margin} += $self->{lg_x_size}; # Set the x starting point $self->{lg_xs} = $self->{width} - $self->{r_margin}; # Set the y starting point, depending on alignment if ($lg_align eq 'T') { $self->{lg_ys} = $self->{t_margin}; } elsif ($lg_align eq 'B') { $self->{lg_ys} = $self->{height} - $self->{b_margin} - $self->{lg_y_size}; } else # default 'C' { my $height = $self->{height} - $self->{t_margin} - $self->{b_margin}; $self->{lg_ys} = int($self->{t_margin} + $height/2 - $self->{lg_y_size}/2) ; } } else # 'B' is the default { # What width can we use my $width = $self->{width} - $self->{l_margin} - $self->{r_margin}; (!defined($self->{lg_cols})) and $self->{lg_cols} = int($width/$self->{lg_el_width}); $self->{lg_cols} = _min($self->{lg_cols}, $num); $self->{lg_rows} = int($num / $self->{lg_cols}) + (($num % $self->{lg_cols}) ? 1 : 0); $self->{lg_x_size} = $self->{lg_cols} * $self->{lg_el_width}; $self->{lg_y_size} = $self->{lg_rows} * $self->{lg_el_height}; # Adjust the bottom margin for the rest of the graph $self->{b_margin} += $self->{lg_y_size}; # Set the y starting point $self->{lg_ys} = $self->{height} - $self->{b_margin}; # Set the x starting point, depending on alignment if ($lg_align eq 'R') { $self->{lg_xs} = $self->{width} - $self->{r_margin} - $self->{lg_x_size}; } elsif ($lg_align eq 'L') { $self->{lg_xs} = $self->{l_margin}; } else # default 'C' { $self->{lg_xs} = int($self->{l_margin} + $width/2 - $self->{lg_x_size}/2); } } } sub draw_legend { my $self = shift; return unless defined $self->{legend}; my $xl = $self->{lg_xs} + $self->{legend_spacing}; my $y = $self->{lg_ys} + $self->{legend_spacing} - 1; my $i = 0; my $row = 1; my $x = $xl; # start position of current element foreach my $legend (@{$self->{legend}}) { $i++; last if $i > $self->{_data}->num_sets; my $xe = $x; # position within an element next unless defined($legend) && $legend ne ""; $self->draw_legend_marker($i, $xe, $y); $xe += $self->{legend_marker_width} + $self->{legend_spacing}; my $ys = int($y + $self->{lg_el_height}/2 - $self->{lgfh}/2); $self->{gdta_legend}->set_text($legend); $self->{gdta_legend}->draw($xe, $ys); $x += $self->{lg_el_width}; if (++$row > $self->{lg_cols}) { $row = 1; $y += $self->{lg_el_height}; $x = $xl; } } } # # This will be virtual; every sub class should define their own # if this one doesn't suffice # sub draw_legend_marker # data_set_number, x, y { my $s = shift; my $n = shift; my $x = shift; my $y = shift; my $g = $s->{graph}; my $ci = ($n<=2) ? $s->set_clr($s->pick_data_clr($n)) : $s->set_clr($s->_darken($s->_darken($s->pick_data_clr($n)))); return unless defined $ci; $y += int($s->{lg_el_height}/2 - $s->{legend_marker_height}/2); $g->filledRectangle( $x, $y, $x + $s->{legend_marker_width}, $y + $s->{legend_marker_height}, $ci ); $g->rectangle( $x, $y, $x + $s->{legend_marker_width}, $y + $s->{legend_marker_height}, $s->{acci} ); } "Just another true value"; calamaris-2.99.4.7/TODO0000644000175000017500000000347214161616434013064 0ustar cordcordWhat will happen next? ---------------------- I think that Calamaris v3 is nearly finished. (except for bugs, that maybe were not found yet.) But if you have an idea what is still missing in a software for parsing proxy log-files, let me know. --> . I'll will build it in, or add it to the wish-list below :-) * adding a Makefile or some other installation-routine, so fixing lib-paths isn't nessecary anymore. (Help wanted) * I suggest that the '-P' option has a option, like all other analyses. So the time step would be something like = / . (Ahmad Kamal ) Comment: As I cumulate the Performance-Data in the Mainloop, when i don't know which timerange i get, i don't have at the time i'd need it, so i don't think that i can implement this without a major rewrite. * rewrite peak-measurement. The new calculation method is very time intensive and slows down Calamaris by 30 or more percent, but it is faster than the old way. However: i'm not really satisfied with it, so i put it out of the -a -option. You'll have to add a '-p (old|new)' -option to get old or new peak-statistic. HELP REQUEST: If someone has an idea how to build an efficient AND fast method to work it out... let me know! * try 'use integer'. This can result in a less memory-hungry, but faster version of Calamaris. (idea by Gerold Meerkoetter) * make Calamaris faster. see above. If someone wants to rewrite Calamaris in a faster language: Feel Free! (But respect the GNU-License) It would be nice if you drop me a line about it, I'll mention it in the README. And please please please don't use the name 'Calamaris' for it without asking me! Version of the TODO ------------------- $Id: TODO,v 3.1 2006-03-19 16:11:25 cord Exp $ calamaris-2.99.4.7/COPYRIGHT0000644000175000017500000005766714161616434013706 0ustar cordcordCalamaris itself is licensed under the GPL V2 or later. The Perl-Modules are dual-licensed under the GPL V1 or later and the Perl Artistic License ----------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End calamaris-2.99.4.7/calamaris.10000644000175000017500000004145214161616434014412 0ustar cordcord.TH "CALAMARIS" "1" "$Date: 2006-03-19 17:52:48 $" "Handmade" "Calamaris Manual" .SH "NAME" .B calamaris - generate text and graphical statistics out of log files from Proxy-Cache-Servers .SH "SYNOPSIS" cat log | .B calamaris [ \--config-file .../calamaris.conf ] [ switches ] .SH "DESCRIPTION" .B Calamaris is used to produce statistical output from \fBSquid\fR, \fBNetCache\fR, \fBInktomi Traffic Server\fR, \fBOops! proxy server\fR, \fBCompaq Tasksmart\fR, \fBCisco Content Engines\fR or related Proxy log files. The resulting output can be ascii or html with or without graphic and with or without frames. It is possible to cache calculated data in a file to use them in later runs. This manual page describes the options of \fBCalamaris\fR and gives a few examples. .SH "OPTIONS" .SS Configuration File .TP .I --config-file file Not all reports and modification can be made through command-line-switches. To use all options of Calamaris you\'ll have to use the configuration file. You'll find the configuration-directives below, always inside of braces. Examples are in the calamaris.conf which should come with this package. .SS Reports .TP .I --all-useful-reports|-a extracts all useful reports available, .I --all-useful-reports equals .I --size-distribution-report 10 .I --domain-report 20 .I --performance-report 60 .I --requester-report 20 .I --status-report .I --type-report 20 .I --response-time-report .I --errorcode-distribution-report . .TP .I --domain-report|-d n ($domain_report) switches the top level and the second level report on. The data is derived from the URL. The output is limited by n. (\-1 is unlimited) .TP .I --domain-report-limit n ($domain_report_limit) limit the domain-report to lines which have n or more requests. .TP .I --domain-report-n-level|-N n ($domain_report_n_level) All URL-Host reports will be switched from 2nd-level to n-level-reports. (\-1 shows a full urlhost-report) .B Note: This option is only useful with activated domain-report. .TP .I --errorcode-distribution-report ($errorcode_distribution_report) shows the Response code distribution over all objects .TP .I ($object_freshness_report) shows the freshness of objects in your cache. .B Calamaris looks for freshness tags like 'TCP_HIT', 'TCP_REFRESH_MISS', ... and make statistics on it. With this information you can optimize the caching behaviour of your cache depending on the objects content type. E.g. squid admins could use this information to configure the refresh_pattern. This option needs more configuration in the configuration-file. .TP .I --peak-report|-p type ($peak_report) Measures the peaks of the Proxy usage in requests per second, per minute and per hour. It reports peaks for TCP, UDP and ALL requests. If set to .I 'old' these values were calculated with the old slow method, if set to .I 'new' the new faster (but still slow) method is used. .TP .I --performance-report|-P n ($performance_report) Shows the throughput of TCP requests for every n minutes. .TP .I --performance-report-adjust|-T n ($performance_report_adjust) Time: Adjust the Performancereport in minutes for non GMT-Timezoners. .TP .I --requester-report|-r n ($requester_report) Switches the UDP and TCP requester reports on. The output is limited by n. (\-1 is unlimited) .TP .I --requester-report-no-dns-lookup|-n ($requester_report_no_dns_lookup) Switches the IP lookup for the requesters off. .TP .I --requester-report-use-user-info|-u ($requester_report_use_user_info) Switches the usage of eventually available ident information for requester reports on. .B Warning: This breaks the privacy of your users! (see PRIVACY-Section below) .TP .I --requester-report-with-targets|-R n ($requester_report_with_targets) adds to each line of the requester report the requested URLs. The output is limited by n. (\-1 is unlimited, and can result in very very long reports.) .B Warning: Using this option breaks the privacy of your users! (see PRIVACY-Section below) .TP .I --response-time-report ($response_time_report) sums up the time distribution over all objects .TP .I (@response_time_report_interval) This array defines the time steps, which should be reported in the response-time-report. .TP .I --size-distribution-report|-D n ($size_distribution_report) shows size-based distribution of requested objects, smaller numbers result in more verbose reports. (choose 2, 10 or 100 for useful output.) .TP .I --status-report|-s ($status_report) alters the default behaviour of .B Calamaris and makes the status reports more verbose. .TP .I --type-report|-t n ($type_report) switches the content type and the file extension report on. The output is limited by n. (\-1 is unlimited) .TP .I --type-report-ignore-case|-c ($type_report_ignore_case) Switch to case-insensitive. This is useful for the 'Requested extensions' report. .SS Input .TP .I --input-format|-f type ($input_format) sets the type of input logfiles. If set to .I 'auto' .B Calamaris tries to guess the input file format. This is the Default. .B Note: If the first line of your input file is corrupted, .B Calamaris will stop with an error. .I 'squid' .B Calamaris expects native logfile derived from .B Squid V1.1.beta26-V2.x or .B OOPS. .I 'squid-extended' .B Calamaris expects native logfile derived from .B Squid V1.1.alpha1-V2.x with .I log_mime_hdrs enabled or .B Squid with .B Smartfilter-Patch or squid-style logfiles out of .B Cisco Content Engines. (This only enables parsing of these kind of logfile, the additional data will be ignored.) (Logging of MIME-Headers breaks the privacy of your users! (see PRIVACY-Section below) .I 'squid-old' .B Calamaris expects native logfile derived from .B Squid V1.1.alpha1-V1.1.beta25. .I 'nc' .B Calamaris expects Logfiles from .B NetCache up to V4.x. (Please see the README on this.) .I 'its' .B Calamaris expects Logfiles from .B Inktomi Traffic Server. .I 'elff' .B Calamaris expects Logfiles in Extended Logfile Format (i.e. from .B Compaq Tasksmart, .B Novell Internet Caching System or .B NetCache V5.x) .I 'nse' .B Calamaris expects Logfiles in Netscape Extended-1 or Netscape Extended-2 Logfile Format (from .B Netscape/iPlanet/SunOne Proxy-Server ) .TP .I --ipfilter-exclude IP/range ($ipfilter_exclude) all IPs are analyzed, except IP/range. Format: 1.1.1.1/32:1.1.2.0/24 or 1.1.1.1/255.255.255.255:1.1.2.0/255.255.255.0 IP list separated by ':' This switch needs the perl Module NetAddr::IP. .B Warning: This breaks the privacy of your users! (see PRIVACY-Section below) .TP .I --ipfilter-include IP/range ($ipfilter_include) no IPs are analyzed, except IP/range. Format: see \--ipfilter-exclude .B Warning: This breaks the privacy of your users! (see PRIVACY-Section below) .TP .I --no-input|-z ($no_input) Switches reading from standard input off. You can use this to merge many cache files to one (see .I --cache-input-file and .I --cache-output-file) or to generate a report out of cache files. .TP .I --time-interval|-I t-t ($time_interval) defines which time-interval should be parsed. t has to be the format yyyymmddhhmmss (localtime) .B Note: omitting the beginning or ending date is allowed. .SS Output Standard output format is plain ascii with 80 chars width. .TP .I ($column1_color) .I ($column2_color) defines the colors for the columns in graphics. (only useful with .I --output-format graph) .TP .I ($formats[n]) Through the config-file you are able to modify the width of the report and alter the culomns that are displayed in the reports. n is the number of the report, as displayed by \--help in the \--show-reports-option. .TP .I --hostname|-H name ($hostname) The name for the title or subject of the output. If set to .I 'lookup' .B Calamaris looks up the host name of the system its been run on. .TP .I --image-type ($image_type) Sets the image type to gif, png, jpeg, gd or gd2. Only useful when .I \--output-format graph is set. The available images types are depending on your GD::Graph installation. Default is 'png'. .TP .I --logo|-l string ($logo) add a custom string to a HTML-Report. It'll be added to a table on the top of the output. .I -l 'Cord' will add my logo with a link to the Report. .B Note: .I --logo works only in combination with .I --output-format html or html-frame .TP .I --meta|-M string ($meta) Meta: adds a custom string or the content of a file into the of a HTML-Report. Useful if you want to add Stylesheets or something to the Report. .B Note: .I --meta works only in combination with .I --output-format html or html-frame .TP .I --output-format|-F type[,type[,type[,...]]] ($output_format) Format: sets the format of the output-report. If set to .I 'mail' adds a subject header to the beginning of the report. .I 'html' all output is given in html with tables. Can be combined with .I 'mail' to send html mails. .I 'html-frame' all output is given in html frames with tables. .I 'html-embed' all output is given in html with tables without HTML-Headers. Useful for Server-Side-Includes. .I 'graph' enables graphics for html, html-embed or html-frame. .I 'unformatted' gives out the raw numbers separated by spaces. Useful for re-using the output in other scripts. If you use this along with .I -U, the byte values are calculated in the given Unit, and displayed without indication along with the numbers. the indication moves up to the header of the report. .TP .I --output-path ($output_path) output calamaris statistics to /path. In case of graph output, the graphics destination is /path and the filename is index.html, else it is calamaris.txt. If .I --output-path is not given, all graphics are written to the working directory. .TP .I --output-file ($output_file) alter the filename of \--output-path. .TP .I --output-file-prefix ($output_file_prefix) adds a prefix to .I --output-file . .I %t is replaced by the timerange of the report, .I %h by the hostname (see .I --hostname ) .TP .I --show-reports|-S n[,n[,n[,...]]] ($show_reports) Show: Shows only the defined reports in the specified order. Default is to display the reports as they are defined through the report-switches above. The following numbers are defined: .RS 0 Summary .RE .RS 1 Incoming request peak per protocol .RE .RS 2 Incoming transfer volume peak per protocol .RE .RS 3 Incoming requests by method .RE .RS 4 Incoming UDP-requests by status .RE .RS 5 Incoming TCP-requests by status .RE .RS 6 Outgoing requests by status .RE .RS 7 Outgoing requests by destination .RE .RS 8 Request-destinations by 2ndlevel-domain .RE .RS 9 Request-destinations by toplevel-domain .RE .RS 10 TCP-Request-protocol .RE .RS 11 Requested content-type .RE .RS 12 Requested extensions .RE .RS 13 Incoming UDP-requests by host .RE .RS 14 Incoming TCP-requests by host .RE .RS 15 Size Distribution Diagram .RE .RS 16 Performance in n minute steps .RE .RS 17 UDP-Request duration distribution in msec .RE .RS 18 TCP-Request duration distribution in msec .RE .RS 19 UDP Response code distribution .RE .RS 20 TCP Response code distribution .RE .B Note: Using this doesn't make .B Calamaris any faster, the internal calculations will be done as the report-switches were set (see above). .TP .I --sort-order|-O ($sort_order) Changes the sort order in the reports to request size, default is sorting by number of requests. .TP .I ($text_color) defines the colors for text/axis/legend/labels in graphics. (only useful with .I --output-format graph ) .TP .I --unit|-U string ($unit) You can define this to K(ilo), M(ega), G(iga) or T(era) for the Byte-units. .TP .I ($width) defines the width of the graphics. height is calculated from this with a 3:2-ratio. (only useful with .I --output-format graph ) .TP .I ($x_scale) defines how many datasets should be drawn on the graph. 30 is a good value, but you can play with this. if $x_scale gets to big, you're on your own ;-) .TP .I --generate-index ($generate_index) generates an index for all reports that match .I --output-file-prefix. .SS Caching .TP .I --cache-input-file|-i file ($cache_input_file) You can reuse a cache file generated with .I --cache-output-file file to add old data to a new report. Several files can be separated with a ':'. .B Note: if you use more than one cache file, make sure they are chronologicaly ordered (oldest first). .B Note: if you reuse cache-files, which were not created with .I -d -1 -r -1 -t -1 -R -1 the number of 'others' would be wrong everywhere. In this case the number of 'others' are omitted. .TP .I --cache-output-file|-o file ($cache_output_file) .B Calamaris stores a summary of the computed information in .I file and you can reuse it at a later time with .I --cache-input-file . .B Note: The output file can be the same as the input file: it is simply overwritten after reading the data. It is not recommended to change the options between different runs if you include older data as this can result in strange measurements. .SS Misc .TP .I --benchmark|-b n ($benchmark) benchmark: A switch for the impatient as it prints a '#' for every n parsed lines. .TP .I --copyright|-C Prints the copyright information of .B Calamaris . .TP .I --help|-h Prints a brief description of the command line options. .TP .I --version|-V Prints out the Version-Number. .SS Debug .TP .I --dump-loop|-L prints the internal loop to STDERR. (for Debugging) .TP .I ($test) activates some small tests for the programmer. .TP .I --verbose|-v ($verbose) print more information about what is Calamaris is doing and believing. .SH "EXAMPLES" .TP This example mails the daily statistics to root: cat /var/log/squid/access.log | nice \-39 .B calamaris .I --all-useful-reports .I --hostname "daily worf" .I --output-format mail | mail root .TP This one only caches a summary for later use: cat /var/log/squid/access.log | .B calamaris \--all-useful-reports \--cache-output-file daily.`date +"%w"` > /dev/null .TP You can then use the caches to have weekly statistics: .TP if [ $DAYOFWEEK = "0" ]; then .B calamaris \--all-useful-reports \--cache-input-file daily.1:daily.2:daily.3:daily.4:daily.5:daily.6:daily.0 \--no-input \--output-format mail \--hostname "weekly worf" | mail root ; .TP fi .SH "BUGS" If you have a problem with .B Calamaris , please make sure that you use the recent version of .B Calamaris (see VERSION below). Also check that your proxy works correctly and doesn't produce invalid Logfiles. (see the README for buglist and pointers.) If you're sure that you've encountered a bug in .B Calamaris please report it to Calamaris-bug@cord.de. This also applies if .B Calamaris itself says 'please report this'. .SH "PRIVACY" .B Calamaris can be (mis-)used to track what users are requesting. So please read the following and think about it, before using .B Calamaris to be the .I Big Brother. .TP - If you don't trust your users than there is something more wrong than the loss of productivity. .TP - Squid has some nice acl-mechanisms. If you think that your users don't use the net properly, don't let them use it. (You can also open the net at specific times or to specific sites, if you want.) .TP - If you still want to use .B Calamaris that way, let your vict^Wusers know, that they'll be monitored. (in Germany you have to let them know!) .SH "SEE ALSO" .B squid(8) .SH "AUTHOR" Cord Beermann , Michael Pophal . There are also a lot of people who contributed code, gave ideas or requested features. Look them up in the executable. This man page was written by Philipp Frauenfelder , maintainer of the Debian package. Maintenance is now taken over by Cord Beermann. .SH "VERSION" Version of this manpage: $Id: calamaris.1,v 3.1 2006-03-19 17:52:48 cord Exp $ It describes the usage of Calamaris V3.0 and later. Information about new releases, mailing lists, and other related issues can be found from the .B Calamaris home page at URL https://Calamaris.Cord.de/ .SH "WARRANTY" .B Calamaris comes with "absolutely no warranty". .SH "COPYRIGHT" Copyright (C) 1997-2006, 2013, 2015, 2017, 2021 Cord Beermann This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. (If you modify and want to publish it under the name .B Calamaris , please ask me. I don't want to confuse the 'audience' with many different versions of the same name and/or Version number. (This is not part of the license, it is only a favour i asked of you.)) This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. calamaris-2.99.4.7/INSTALL0000644000175000017500000000556014161616434013425 0ustar cordcordCalamaris Version 3 How to use it? -------------- * You'll need Perl Version 5 (see https://www.Perl.org/). Calamaris is reported to work with Perl 5.001 (maybe you have to remove the '-w' from the first line and comment out the 'use vars'-line), but it is highly recommended (especially for security of your computer) that you use a recent version (>=5.8.4) of it. * You'll also need one of the noted log-files: + Squid V1.1.alpha1-V1.1.beta25 Native log-files + Squid V1.1.beta26-V2.x Native log-files + Squid V1.1.beta26-V2.x Native log-files with log_mime_hdrs enabled + NetCache V??? Squid-style Log-files + NetCache V5.x Default Log-file-Format (Extended Log-file-Format) + Inktomi Traffic Server V??? Log-files + OOPS V??? Native log-files + Extended Log-file-Format + NetApp Default Log-file-Format (some kind of Extended Log-file-Format) + NetApps understanding of Squid Native log-files + Squid with SmartFilter-Patch Log-files + Cisco Content Engines If Calamaris can't parse the input, check your log-file format. + Squid-Log-files: http://www.squid-cache.org/Doc/FAQ/FAQ-6.html + Extended Log-file-Format: http://www.w3.org/TR/WD-logfile * You'll need GD::Graph package to get graphical html output. For some features you need also NetAddr::IP. Calamaris runs without both perl packages, but most of the new V3.x features won't work without them. * Installation: + get GD::Graph and NetAddr::IP from https://www.cpan.org and install them. (if your system has packages for these available, you should use them.) + cd /usr/local + tar -xzvf /path/to/calamaris-3.0.xxx.tgz + ln -s /usr/local/calamaris-3.0.xxx /usr/local/calamaris + Note: calamaris looks in /usr/local/ for needed calamaris perl modules. If you want to change this path, you have to change the 'use lib' directive in the calamaris code and perl modules. (still looking for a nicier solution for this, suggestions/patches welcome) + Maybe (if your Perl isn't located at /usr/bin/perl) you'll have to change the first line of Calamaris to point to your copy of Perl. + There is also a man-page for Calamaris. You should copy it to an appropriate place like /usr/local/man/man1, where your man(1) can find it. * Use it! 'cat access.log.1 access.log.0 | /usr/local/calamaris/calamaris' Calamaris by default generates by a brief ASCII report of incoming and outgoing requests. NOTE: If you pipe more than one log-file into Calamaris, make sure that they are chronologically ordered (oldest file first), else some reports can return wrong values. You can alter Calamaris' behaviour with switches. Start Calamaris with '-h' or check the man-page. You should also take a look at the EXAMPLES-File, for 'Real-Life'-usage-examples of Calamaris. Version of the INSTALL --------------------- $Id: INSTALL,v 3.1 2004-12-23 20:01:03 cord Exp $ calamaris-2.99.4.7/EXAMPLES.v30000644000175000017500000001012114161616434014051 0ustar cordcordI want to give the 'audience' some examples for using Calamaris. So if you build some Scripts, crontabs or else around Calamaris, please mail and describe them to . I'll probably add them to this file. Thank You. Pavel Malakhov first sends in a new Example. ----------------------------------------------------------------------- calam_rep.sh ============ #!/bin/bash # Script for calamaris 3 to generate reports for squid # # "Usage: calam_rep.sh [today|yesterday|week|month]" # # Pavel Malakhov 28.03.05 # 12.05.05 fixed yesterday date format, new vars CALAM_DIR='/etc/calamaris'; # where calamaris is SQUID_LOG_DIR='/usr/local/squid/var/logs'; # where the squid logs are # where to store reports. Root dir, all the other will be created by this script REP_PATH_PREFIX='/var/www/html/reports/squid'; CACHE_DIR='/etc/calamaris/cache'; # where to store cache files for every week YESTD=`date -d yesterday +%d`; # yesterday's day of month YESTW=`date -d yesterday +%V`; # yesterday's week of year YESTM=`date -d yesterday +%m_%B`; # yesterday's month number and name # ------------ You don't need to edit anything below --------------------------- # ------------------ [but welcome to analyze!] --------------------------------- # Check for dir for report.Create, if does not exist. function checkdir { if [ ! -e "$REPPATH" ];then echo -n `date +%c` "Dir \"$REPPATH\" is not created. Creating... "; mkdir -p $REPPATH; echo "Done."; fi; } # Check for parameter if [ "$1" = "" ]; then echo "Usage: calam_rep.sh [today|yesterday|week|month]" exit 1 fi # check for cache dir if [ ! -e "$CACHE_DIR" ];then echo -n `date +%c` "Cache dir \"$CACHE_DIR\" is not created. Creating... "; mkdir -p $CACHE_DIR; echo "Done."; fi; case "$1" in "today" ) REPPATH=$REP_PATH_PREFIX'/today'; checkdir; cd $CALAM_DIR; echo -n `date +%c` "Processing data for today... "; cat $SQUID_LOG_DIR/access.log | ./calamaris.pl --config-file ./calamaris.conf --output-path $REPPATH; ;; "yesterday" ) REPPATH=$REP_PATH_PREFIX'/days/'$YESTD; checkdir; cd $CALAM_DIR; echo -n `date +%c` "Processing data for yesterday... "; cat $SQUID_LOG_DIR/access.log.0 | ./calamaris.pl --config-file ./calamaris.conf --output-path $REPPATH --cache-output-file $CACHE_DIR/day.$YESTD; ;; "week" ) REPPATH=$REP_PATH_PREFIX'/weeks/'$YESTW; checkdir; cd $SQUID_LOG_DIR; echo -n `date +%c` "Processing data for week... "; cat access.log.6 access.log.5 access.log.4 access.log.3 access.log.2 access.log.1 access.log.0 | $CALAM_DIR/calamaris.pl --config-file $CALAM_DIR/calamaris.conf --output-path $REPPATH --cache-output-file $CACHE_DIR/week.$YESTW; ;; "month" ) REPPATH=$REP_PATH_PREFIX'/months/'$YESTM; checkdir; cd $CACHE_DIR; CACHEFILES=""; for ((i=1; i<=31; i++)); do FILE='day.'$i; if [ -e "$FILE" ]; then if ["$CACHEFILES" = ""]; then CACHEFILES=$FILE; else CACHEFILES=$CACHEFILES':'$FILE; fi fi done echo 'files to process '$CACHEFILES; echo -n `date +%c` "Processing data for month... "; $CALAM_DIR/calamaris.pl --config-file $CALAM_DIR/calamaris.conf --cache-input-file $CACHEFILES --no-input --output-path $REPPATH; echo "Done"; # clean up cache directory at the start of a month # delete only cached days, leave cached weeks DD=`date +%d`; if [ "$DD" = "01" ]; then echo -n `date +%c` "Cleaning up cache dir... "; rm -f $CACHE_DIR/day.*; fi ;; esac echo "Done"; echo `date +%c` "---Everything is done" exit 0 ----------------------------------------------------- Everyone who really uses while testing has to send me a postcard! ----------------------------------------------------------------------- Version of the EXAMPLES.v3 -------------------------- $Id: EXAMPLES.v3,v 3.1 2006-03-19 17:59:03 cord Exp $ calamaris-2.99.4.7/calamaris-cache-convert0000755000175000017500000000774414161616434017003 0ustar cordcord#!/usr/bin/perl -w # # $Id: calamaris-cache-convert,v 0.2 2004-09-17 21:03:50 cord Exp $ # # DESCRIPTION: calamaris-cache-convert - # convert old Calamaris-Caches to new ones. # # Copyright (C) 2004 Cord Beermann # # URL: https://Calamaris.Cord.de/ # Announcement-Mailing-list: send Mail with 'subscribe' in the Mail-Body to # Calamaris-announce-request@Cord.de # # AUTHOR: Cord Beermann # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # (If you modify and want to publish it under the name 'Calamaris', please ask # me. I don't want to confuse the 'audience' with many different versions of # the same name and/or Version number. (This is not part of the license, it # is only a favour i asked of you.)) # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 59 Temple # Place - Suite 330, Boston, MA 02111-1307, USA. # A Perl script is "correct" if it gets the job done before your boss fires # you. # -- 'Programming Perl Second Edition' use Switch; $count = $error_count = 0; unless ($#ARGV == 1) { print "Usage: $0 old-file new-file\n"; exit 255; } open( OLD, "$ARGV[0]" ) or die ("$0: can't open $ARGV[0] for reading: $!\n"); open( NEW, "> $ARGV[1]" ) or die ("$0: can't open $ARGV[1] for writing: $!\n"); while () { chomp; next if m#^$#; $count++; @cache = split 'µ'; switch ($cache[0]) { case 'A' { $cache[0] = 0; } case 'B' { $cache[0] = 1 if $#cache == 18; $cache[0] = 2 if $#cache == 24; } case 'C' { $cache[0] = 3; } case 'D' { $cache[0] = 4.1; } case 'E' { $cache[0] = 4.2; } case 'F' { $cache[0] = 5.1; } case 'G' { $cache[0] = 5.2; } case 'H' { $cache[0] = 5.3; } case 'I' { $cache[0] = 6.1; } case 'J' { $cache[0] = 6.2; } case 'K' { $cache[0] = 6.3; } case 'L' { $cache[0] = 7.1; } case 'M' { $cache[0] = 7.2; } case 'N' { $cache[0] = 8; push(@cache, 0, 0); $error{8} = 'Missing data in Request-destinations by 2ndlevel-domain - empty data inserted'; } case 'O' { $cache[0] = 9; push(@cache, 0, 0); $error{9} = 'Missing data in Request-destinations by toplevel-domain - empty data inserted'; } case 'P' { $cache[0] = 10; push(@cache, 0, 0); $error{10} = 'Missing data in TCP-Request-protocol - empty data inserted'; } case 'Q' { $cache[0] = 11; push(@cache, 0, 0); $error{11} = 'Missing data in Requested content-type - empty data inserted'; } case 'R' { $cache[0] = 12; push(@cache, 0, 0, 0, 0, 0, 0, 0); $error{12} = 'Missing data in Requested extensions - empty data inserted'; } case 'S' { $cache[0] = 13.1; } case 'V' { $cache[0] = 13.2; } case 'T' { $cache[0] = 14.1; } case 'W' { $cache[0] = 14.2; } case 'X' { $cache[0] = 15; } case 'U' { $cache[0] = 16; @cache = ($cache[0], $cache[1], $cache[2], $cache[3], 0, 0, $cache[5], $cache[6], $cache[7], $cache[8], $cache[9], $cache[10], $cache[11], $cache[12], $cache[13]) if $#cache == 13;; push(@cache, 0, 0); $error{16} = 'Missing data in Performance in n minute steps - empty data inserted'; } else { $error_count++; $error{99} = "$error_count lines couldn't be converted."; print "$cache[0] $cache[1]\n"; } } print NEW join('µ', @cache) . "\n"; } close (NEW); close (OLD); foreach $error (sort keys %error) { print "$error{$error}\n"; } print "$count lines successfully converted.\n"; calamaris-2.99.4.7/calBars3d.pm0000644000175000017500000002717114161616434014532 0ustar cordcord#========================================================================== # Module: calamaris::calBars3d.pm # # Copyright # # calBars3d.pm Copyright (c) 2004 Michael Pophal based on # GD::Graph Copyright (c) 1995-1999 Martien Verbruggen. # (https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm) # # All rights reserved. This package is free software; you can redistribute # it and/or modify it under the same terms as Perl itself. # # Acknowledgements # # Thanks to Martien Verbruggen's ingenious tool GD::Graph, which is basically # the same, except some small changes needed for calamaris. #========================================================================== # # Adapted to calamaris by: (c) 2004 Michael Pophal # # Based on: # GD::Graph::bars3d.pm,v 1.21 2000/04/15 08:59:36 mgjv # https://metacpan.org/release/MVERB/GDGraph-1.43/view/Graph.pm # Copyright (c) 1995-1998 Martien Verbruggen # #-------------------------------------------------------------------------- # # Name: # calamaris::calBars3d.pm # # $Id: calBars3d.pm,v 3.2 2004-09-15 21:02:13 cord Exp $ # #-------------------------------------------------------------------------- # Date Modification Author # ------------------------------------------------------------------------- # 2004AUG30 Adapted to calamaris staehler #========================================================================== package calamaris::calBars3d; use strict; use lib '/usr/local'; use calamaris::calAxestype3d; use GD::Graph::bars; use GD::Graph::utils qw(:all); use GD::Graph::colour qw(:colours); @calamaris::calBars3d::ISA = qw(calamaris::calAxestype3d); $calamaris::calBars3d::VERSION = '0.63'; use constant PI => 4 * atan2(1,1); my %Defaults = ( # Spacing between the bars bar_spacing => 0, # The 3-d extrusion depth of the bars bar_depth => 10, ); sub initialise { my $self = shift; my $rc = $self->SUPER::initialise(); $self->set(correct_width => 1); while( my($key, $val) = each %Defaults ) { $self->{$key} = $val } # end while return $rc; } # end initialise sub set { my $s = shift; my %args = @_; $s->{_set_error} = 0; for (keys %args) { /^bar_depth$/ and do { $s->{bar_depth} = $args{$_}; delete $args{$_}; next; }; } return $s->SUPER::set(%args); } # CONTRIB Jeremy Wadsack # This is a complete overhaul of the original GD::Graph::bars # design, because all versions (overwrite = 0, 1, 2) # require that the bars be drawn in a loop of point over sets sub draw_data { my $self = shift; my $g = $self->{graph}; my $bar_s = _round($self->{bar_spacing}/2); my $set_s = _round($self->{set_spacing}/2); my (%lset_space, %rset_space); for (1..2) { $lset_space{$_} = 0; $rset_space{$_} = 0; }; if ($self->{set_spacing}) { $lset_space{1} = $set_s; $lset_space{2} = 0; $rset_space{2} = $set_s; $rset_space{1} = 0; } my $zero = $self->{zeropoint}; my $i; my @iterate = (0 .. $self->{_data}->num_points()); for $i ($self->{rotate_chart} ? reverse(@iterate) : @iterate) { my ($xp, $t); my $overwrite = 0; $overwrite = $self->{overwrite} if defined $self->{overwrite}; my $j; my $num_sets = ($self->{_data}->num_sets() >= 2) ? 2 : $self->{_data}->num_sets(); my @iterate = (1 .. $num_sets); for $j (($self->{rotate_chart} && $self->{cumulate} == 0) ? reverse(@iterate) : @iterate) { my $value = $self->{_data}->get_y( $j, $i ); my $factor = ($self->{_data}->num_sets() > 2) ? $self->{_data}->get_y( $j+2, $i ) : 0; next unless defined $value; my $bottom = $self->_get_bottom($j, $i); $value = $self->{_data}->get_y_cumulative($j, $i) if ($self->{cumulate}); # Pick a data colour, calc shading colors too, if requested # cycle_clrs option sets the color based on the point, not the dataset. my @rgb; if( $self->{cycle_clrs} ) { @rgb = $self->pick_data_clr( $i + 1 ); } else { @rgb = $self->pick_data_clr( $j ); } # end if my $dsci = $self->set_clr( @rgb ); if( $self->{'3d_shading'} ) { $self->{'3d_highlights'}[$dsci] = $self->set_clr( $self->_brighten( @rgb ) ); $self->{'3d_shadows'}[$dsci] = $self->set_clr( $self->_darken( @rgb ) ); $self->{'3d_dshadows'}[$dsci] = $self->set_clr( $self->_darken($self->_darken( @rgb )) ); $self->{'3d_ddshadows'}[$dsci] = $self->set_clr( $self->_darken($self->_darken($self->_darken( @rgb ))) ); } # end if # contrib "Bremford, Mike" my $brci; if( $self->{cycle_clrs} > 1 ) { $brci = $self->set_clr($self->pick_data_clr($i + 1)); } else { $brci = $self->set_clr($self->pick_border_clr($j)); } # end if # get coordinates of top and center of bar ($xp, $t) = $self->val_to_pixel($i + 1, $value, $j); # calculate offsets of this bar my $x_offset = 0; my $y_offset = 0; if( $overwrite == 1 ) { # $x_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j); # $y_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j); $x_offset = $self->{bar_depth} * ($num_sets - $j); $y_offset = $self->{bar_depth} * ($num_sets - $j); } $t -= $y_offset; # calculate left and right of bar my ($l, $r); if ($self->{rotate_chart}) { $l = $bottom; ($r) = $self->val_to_pixel($i + 1, $value, $j); } if( (ref $self eq 'GD::Graph::mixed') || ($overwrite >= 1) ) { if ($self->{rotate_chart}) { $bottom = $t + $self->{x_step}/2 - $bar_s + $x_offset; $t = $t - $self->{x_step}/2 + $bar_s + $x_offset; } else { $l = $xp - $self->{x_step}/2 + $bar_s + $x_offset; $r = $xp + $self->{x_step}/2 - $bar_s + $x_offset; } } else { if ($self->{rotate_chart}) { warn "base is $t"; #$bottom = $t - $self->{x_step}/2 # + ($j) * $self->{x_step}/$self->{_data}->num_sets() # + $bar_s + $x_offset; #$t = $t - $self->{x_step}/2 # + ($j-1) * $self->{x_step}/$self->{_data}->num_sets() # - $bar_s + $x_offset; $bottom = $t - $self->{x_step}/2 + ($j) * $self->{x_step}/$num_sets + $bar_s + $x_offset; $t = $t - $self->{x_step}/2 + ($j-1) * $self->{x_step}/$num_sets - $bar_s + $x_offset; warn "top bottom is ($t, $bottom)"; } else { #$l = $xp # - $self->{x_step}/2 # + ($j - 1) * $self->{x_step}/$self->{_data}->num_sets() # + $bar_s + $x_offset; #$r = $xp # - $self->{x_step}/2 # + $j * $self->{x_step}/$self->{_data}->num_sets() # - $bar_s + $x_offset; $l = $xp - $self->{x_step}/2 + ($j - 1) * $self->{x_step}/$num_sets + $bar_s + $lset_space{$j} + $x_offset; $r = $xp - $self->{x_step}/2 + $j * $self->{x_step}/$num_sets - $bar_s - $rset_space{$j} + $x_offset; } } if ($value >= 0) { # draw the positive bar $self->draw_bar( $g, $l, $t, $r, $bottom-$y_offset, $dsci, $brci, 0, $factor ); } else { # draw the negative bar $self->draw_bar( $g, $l, $bottom-$y_offset, $r, $t, $dsci, $brci, -1, $factor ); } # end if } # end for } # end for # redraw the 'zero' axis, front and right if( $self->{zero_axis} ) { $g->line( $self->{left}, $self->{zeropoint}, $self->{right}, $self->{zeropoint}, $self->{fgci} ); $g->line( $self->{right}, $self->{zeropoint}, $self->{right}+$self->{depth_3d}, $self->{zeropoint}-$self->{depth_3d}, $self->{fgci} ); } # end if # redraw the box face if ( $self->{box_axis} ) { # Axes box $g->rectangle($self->{left}, $self->{top}, $self->{right}, $self->{bottom}, $self->{fgci}); $g->line($self->{right}, $self->{top}, $self->{right} + $self->{depth_3d}, $self->{top} - $self->{depth_3d}, $self->{fgci}); $g->line($self->{right}, $self->{bottom}, $self->{right} + $self->{depth_3d}, $self->{bottom} - $self->{depth_3d}, $self->{fgci}); } # end if return $self; } # end draw_data # CONTRIB Jeremy Wadsack # This function draws a bar at the given # coordinates. This is called in all three # overwrite modes. sub draw_bar { my $self = shift; my $g = shift; my( $l, $t, $r, $b, $dsci, $brci, $neg, $factor ) = @_; my $height = ($b - $t)*$factor; # get depth of the bar my $depth = $self->{bar_depth}; # get the bar shadow depth and color my $bsd = $self->{shadow_depth}; my $bsci = $self->set_clr(_rgb($self->{shadowclr})); my( $xi ); # shadow if( $bsd > 0 ) { my $sb = $b - $depth; my $st = $t - $depth + $bsd; if( $neg != 0 ) { $st -= $bsd; if( $self->{zero_axis_only} ) { $sb += $bsd; } else { $sb = _min($b-$depth+$bsd, $self->{bottom}-$depth); } # end if } # end if # ** If this isn't the back bar, then no side shadow should be # drawn or else the top should be lowered by # ($bsd * dataset_num), it should be drawn on the back surface, # and a shadow should be drawn behind the front bar if the # bar is positive and the back is negative. $g->filledRectangle($l+$depth+$bsd, $st, $r+$depth+$bsd, $sb, $bsci); # Only draw bottom shadow if at the bottom and has bottom # axis. Always draw top shadow if( ($neg == 0) || ($sb >= $self->{bottom}-$depth) ) { my $poly = new GD::Polygon; $poly->addPt( $r, $b ); $poly->addPt( $r+$bsd, $b ); $poly->addPt( $r+$depth+$bsd, $b-$depth ); $poly->addPt( $r+$depth, $b-$depth ); $g->filledPolygon( $poly, $bsci ); } # end if } # end if # side top my $poly = new GD::Polygon; $poly->addPt( $r, $b ); $poly->addPt( $r+$depth, $b-$depth ); $poly->addPt( $r+$depth, $b-$depth-$height ); $poly->addPt( $r, $b-$height ); if( $self->{'3d_shading'} ) { $g->filledPolygon( $poly, $self->{'3d_ddshadows'}[$dsci] ); } else { $g->filledPolygon( $poly, $dsci ); } # end if # side bottom $poly = new GD::Polygon; $poly->addPt( $r, $b-$height ); $poly->addPt( $r+$depth, $b-$depth-$height ); $poly->addPt( $r+$depth, $t-$depth ); $poly->addPt( $r, $t ); if( $self->{'3d_shading'} ) { $g->filledPolygon( $poly, $self->{'3d_shadows'}[$dsci] ); } else { $g->filledPolygon( $poly, $dsci ); } # end if $g->polygon( $poly, $brci ); # top # -- only draw negative tops if the bar starts at zero if( ($neg == 0) || ($t <= $self->{zeropoint}) ) { $poly = new GD::Polygon; $poly->addPt( $l, $t ); $poly->addPt( $l+$depth, $t-$depth ); $poly->addPt( $r+$depth, $t-$depth ); $poly->addPt( $r, $t ); if( $self->{'3d_shading'} ) { $g->filledPolygon( $poly, $self->{'3d_highlights'}[$dsci] ); } else { $g->filledPolygon( $poly, $dsci ); } # end if $g->polygon( $poly, $brci ); } # end if # face $g->filledRectangle( $l, $t, $r, $b-$height, $dsci ); # face top $g->filledRectangle( $l, $b-$height, $r, $b, $self->{'3d_dshadows'}[$dsci] ); # face bottom $g->rectangle( $l, $t, $r, $b-$height, $brci ); # frame face top $g->rectangle( $l, $b-$height, $r, $b, $brci ); # frame face bottom } # end draw_bar # [JAW] Overrides axestype's set_max_min. # Go through the parent's process then adjust the baseline to 0 for bar graphs. sub set_max_min { my $self = shift; $self->SUPER::set_max_min( @_ ); # This code is taken from Martien's axestype.pm for my $i (1..($self->{two_axes} ? 2 : 1)) { # If at the same side of the zero axis if( $self->{y_max}[$i] && $self->{y_min}[$i]/$self->{y_max}[$i] > 0 ) { $self->{y_min}[$i] > 0 ? $self->{y_min}[$i] = 0 : $self->{y_max}[$i] = 0 ; } # end if } # end for return $self; } # end set_max_min # [JW] Just use the one in GD::Graph::bars sub draw_values { return &GD::Graph::bars::draw_values( @_ ); } 1; calamaris-2.99.4.7/BUGS0000644000175000017500000001363614161616434013062 0ustar cordcordCalamaris Version 3 Are there known bugs or other problems? --------------------------------------- * The Content-Type-stats for some elff-logging-proxies are broken, i have to check why. * RedHat 8.0 has set the LANG-Variable to en_US.UTF-8, which caused Calamaris to crash with 'Split loop at (eval 1) line 21, <> line 1', maybe due to a perl-bug. (Investigation needed). You can workaround this problem by unsetting LANG. Please see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=77437 . * There is a problem if you parse Logfiles from accelerating proxies. In iPlanet Web Proxy Server there is only an 'unqualified' URL in the Logfiles, which confuses all reports that rely on that field. (reported by Pawel Worach ) * Calamaris can't resolve IPv6-IPs to DNS-Names yet. If you can tell me how i can do it in perl, let me know ;-) * the byte-histogram sometimes displays a 0-0-byte line. this is correct. the requests added there are really logged as 0-byte-sized in the Logfile. Note that empty byte-ranges as 1-9 (which is impossible because of protocol-overhead) are skipped and not displayed in the report, so you can end up with 0-0 followed by 10-99 in the report. (noted by Reagan Blundell through Debian-Bug-Tracking) * there were many requests to add something that enables Calamaris to track down who is using the Cache to get what. I added these with stomach-ache, because it breaks the privacy of the users. So please read the following and think about it, before using Calamaris to be the 'Big Brother': - If you don't trust your users than there is something more wrong than the loss of productivity. - Squid has some nice acl-mechanisms. If you think that your users don't use the net properly, don't let them use it. (You can also open the net at specific times or to specific sites, if you want.) If you still want to use Calamaris that way, let your vict^Wusers know that they'll be monitored. (in Germany you have to let them know!) After some discussion in a newsgroup i was 'accused' to not announce the spy-features of Calamaris. THIS IS INTENTIONAL. This is MY program, it can spy on users, because there are many people who want to have that feature, but what i write on the feature-sheet is MY decision. Don't annoy me, you might damage my motivation to maintain this FREE (as in speech) piece of software. * In Calamaris V3 I use a new Cache-File-Format, which is incompatible with the old V2-Format. You can convert V2-cache to V3-cache with the calamaris-convert-cache-script, but it will only make the old data readable for the new version. You'll notice that the missing data, which wasn't calculated in the old version will result in sometimes strange results in the output. * If you reuse a cache-file, which is not created with '-d -1 -r -1 -t -1 -R -1' the number of 'others' is likely wrong everywhere. (reported by Clare Lahiff ) If i store the number of 'others' somewhere i still don't know which data is ment there, and in the next run (if i sum up) the number of others is to high (if the number of occurrences is below the threshold) or the summed up data misses the occurrences of the last run (if the number of occurances is above the threshold). i think i can't fix this... * If you want to parse more than one logfile (i.e. from the 'logfilerotate') or want to use more than one input-cache-file you have to put them in chronological sorted order (oldest first), else you get wrong peak values. However: If you use the caching function the peak-values can be wrong, because peaks occurring during log-rotate-time can't be detected. Calamaris will add a warning to the report if it recognises unsorted input. * Squid with SmartFilter-Patch and Cisco Content Engines have the ability to block or allow requests by checking against a database, and write this to the Logfiles. I will not add a report to give an overview about the usage of the Categories. (see first point of this chapter.) * Squid doesn't log outgoing UDP-Requests, so i can't put them into the statistics without parsing squid.conf and the cache.log-file. (Javier Puche asked for this), but i don't think that i should put this into Calamaris... * Squid and NetCache also support some kind of 'Common Logfile-format'. I won't support that, because Common Log is missing some very important data i.e. the request-time and the hierarchie-information. If you're still stuck with that format, i recommend the 'analog'-software by Steven Turner. Other way round: change logging to 'native' and convert it to 'common'. There is software for that available, i.e. my shrimp.pl. This also applies for the Common-style Log-files which NetCache produces. * If you use Calamaris at UNIX-epoch-date 2147483648 or later (~19.Jan 2038) you might get wrong dates on 32bit-systems. (I just added this to delight the people who really read this ;-) and to make a statement on this... on Y2K they found many systems which wasn't expected to run in that year. If you read this while checking if this package is Y2K038-compatible, then this is probably a really old system ;-) Y2038-Statement: Calamaris is as buggy as the used perl-version. * It is written in Perl. Yea, Perl is a great language for something like this (also it is the only one I'm able to write something like this in ;-). Calamaris was first intended as demo for what i expect from a statistical software. (OK, it is fun to write it, and it is even more fun to recognise that many people use the script). For my Caches with about 150MB logfile per week it is OK, but for those people on a heavy loaded Parent-cache it is possibly to slow. How does it perform with the perlcc coming in Perl5.6 or Perl6? Version of the BUGS ------------------- $Id: BUGS,v 3.1 2006-03-19 16:10:53 cord Exp $ calamaris-2.99.4.7/EXAMPLES0000644000175000017500000002623414161616434013536 0ustar cordcordNOTE: This file hasn't updated yet and reflects the (still working) Calamaris V2-Usage. New/Updated Examples welcome ;-) I want to give the 'audience' some examples for using Calamaris. So if you build some Scripts, crontabs or else around Calamaris, please mail and describe them to . I'll probably add them to this file. Thank You. Philipp Frauenfelder added this to run Calamaris automagically in Debian: ----------------------------------------------------------------------- /etc/cron.daily/calamaris ========================= #! /bin/sh set -e # calamaris: daily cron script. # This script should be run before the one for squid. According to the # man page of run-parts this is okay: squid comes after calamaris in the # alphabet. # Date: 1998-10-07 CONFFILE=/etc/calamaris.conf CALAMARIS=/usr/bin/calamaris if [ ! -x /usr/bin/calamaris ]; then exit 0 fi CALAMARISOPTIONS=-a ME=/etc/cron.daily/calamaris WEEKFILES=daily.1:daily.2:daily.3:daily.4:daily.5:daily.6:daily.0 SQUIDLOGDIR=/var/log/squid cd $SQUIDLOGDIR || exit 1 if [ ! -r access.log ]; then exit 0 fi LOGDIR=/var/log/calamaris cd $LOGDIR || exit 1 # today DAYOFWEEK=`date +"%w"` # read configuration file: /etc/calamaris.conf # is there a more elegant way to do this? DAYMAIL=`awk -F: '(!/¨#/) && ($1 == "daily") { print $2; }' $CONFFILE` DAYWEB=`awk -F: '(!/¨#/) && ($1 == "daily") { print $3; }' $CONFFILE` DAYDO=`awk -F: '(!/¨#/) && ($1 == "daily") { print $4; }' $CONFFILE` DAYTITLE=`awk -F: '(!/¨#/) && ($1 == "daily") { print $5; }' $CONFFILE` WEEKMAIL=`awk -F: '(!/¨#/) && ($1 == "weekly") { print $2; }' $CONFFILE` WEEKWEB=`awk -F: '(!/¨#/) && ($1 == "weekly") { print $3; }' $CONFFILE` WEEKDO=`awk -F: '(!/¨#/) && ($1 == "weekly") { print $4; }' $CONFFILE` WEEKTITLE=`awk -F: '(!/¨#/) && ($1 == "weekly") { print $5; }' $CONFFILE` # perhaps sometimes I will do this, # but as weekends and ends of months don't meet always... # MONTHMAIL=`awk -F: '(!/¨#/) && ($1 == "monthly") { print $2; }' $CONFFILE` # MONTHWEB=`awk -F: '(!/¨#/) && ($1 == "monthly") { print $3; }' $CONFFILE` # MONTHDO=`awk -F: '(!/¨#/) && ($1 == "monthly") { print $4; }' $CONFFILE` # MONTHTITLE=`awk -F: '(!/¨#/) && ($1 == "monthly") { print $5; }' $CONFFILE` # if we need monthly or weekly reports save a summary if [ $WEEKDO != "nothing" ]; then CALAMARISOPTIONSOLD="$CALAMARISOPTIONS" CALAMARISOPTIONS="$CALAMARISOPTIONS -o daily.$DAYOFWEEK" fi # do the daily report case $DAYDO in nothing) if [ $WEEKDO != "nothing" ]; then cat $SQUIDLOGDIR/access.log | \ nice -39 $CALAMARIS $CALAMARISOPTIONS > /dev/null fi ;; mail) ( echo "To: $DAYMAIL" cat $SQUIDLOGDIR/access.log | \ nice -39 $CALAMARIS $CALAMARISOPTIONS -F mail -H "$DAYTITLE" ) | /usr/lib/sendmail -t ;; web) cat $SQUIDLOGDIR/access.log | \ nice -39 $CALAMARIS $CALAMARISOPTIONS -F html -H "$DAYTITLE" > $DAYWEB ;; both) cat $SQUIDLOGDIR/access.log | \ nice -39 $CALAMARIS $CALAMARISOPTIONS -F html -H "$DAYTITLE" > $DAYWEB ( echo "To: $DAYMAIL" cat $SQUIDLOGDIR/access.log | \ nice -39 $CALAMARIS $CALAMARISOPTIONS -F mail -H "$DAYTITLE" ) | /usr/lib/sendmail -t ;; *) echo "the 'todo' for the daily Squid report in $CONFFILE" echo -n "is '$DAYDO' instead of one out of " echo "(nothing, mail, web, both)." >&2 exit 1 ;; esac # do the weekly report on Sunday <=> $DAYOFWEEK==0 if [ -n "$CALAMARISOPTIONSOLD" ]; then CALAMARISOPTIONS="$CALAMARISOPTIONSOLD" fi if [ $DAYOFWEEK = "0" ]; then case $WEEKDO in nothing) ;; mail) ( echo "To: $WEEKMAIL" nice -39 $CALAMARIS $CALAMARISOPTIONS -i $WEEKFILES \ -zH "$WEEKTITLE" -F mail ) | /usr/lib/sendmail -t ;; web) nice -39 $CALAMARIS $CALAMARISOPTIONS -i $WEEKFILES \ -zH "$WEEKTITLE" -F html > $WEEKWEB ;; both) nice -39 $CALAMARIS $CALAMARISOPTIONS -i $WEEKFILES \ -zH "$WEEKTITLE" -F html > $WEEKWEB ( echo "To: $WEEKMAIL" nice -39 $CALAMARIS $CALAMARISOPTIONS -i $WEEKFILES \ -zH "$WEEKTITLE" -F mail ) | /usr/lib/sendmail -t ;; *) echo "the 'todo' for the weekly Squid report in $CONFFILE" echo -n "is '$WEEKDO' instead of one out of " echo "(nothing, mail, web, both)." >&2 exit 1 ;; esac # if [ $MONTHDP != "nothing" ]; then # nice -39 $CALAMARIS $CALAMARISOPTIONS -i $WEEKFILES -z -o weekly.$WEEKWHAT > /dev/null # fi fi # do the monthly report and rotate the monthly logs: nothing to do :-) exit 0 /etc/calamaris.conf =================== # configuration file for calamaris # by Philipp Frauenfelder # 1998-10-09 # there are three categories: daily, weekly and monthly. For each of these # one line is responsible. There must be a line for each category but only # one. # cat: [daily|weekly|monthly] # mailto: mailaddress, eg. root # webto: path incl. file name, eg. /var/www/daily.html. The script does # currently not check wether the directory exists and # fail with a rather ugly error. # todo: [nothing|mail|web|both] # title: try it :-) # cat:mailto:webto:todo:title daily:root:/var/www/calamaris/daily.html:both:'Squid daily' weekly:root:/var/www/calamaris/weekly.html:both:'Squid weekly' # monthly does not work right now. #monthly:root:/var/www/monthly.html:both:'Squid monthly' # how many months of calamaris logs should be kept: integer #monthstokeep 2 ----------------------------------------------------------------------- Matthew King squidreport.cron: ----------------------------------------------------------------------- #!/bin/sh # SquidReport Script by Matthew King # Last update: 27-03-99. # This script will remove the current Squid HTML report, and will replace # it with a fresh one. The report will include all available squid access # log files.. Roughly 7 days worth. The report will then be dumped into # /home/httpd/html/ to be viewed via a web browser. # Remove the current report! cd /home/httpd/html/ rm -f squidreport.html echo > squidreport.html cd / # Create the new report and place it into the /home/httpd/html/ dir.. cd /var/log/squid/ cat access.log.7 access.log.6 access.log.5 access.log.4 access.log.3 \ access.log.2 access.log.1 access.log \ | /usr/local/bin/calamaris.pl -a -F html > /home/httpd/html/squidreport.html # Phew! It is done :) 60 odd seconds later :) ----------------------------------------------------------------------- Alain Williams suggested to make the above long line with all access.log-Files easier (and shorter): ----------------------------------------------------------------------- ( zcat $( ls -tr access.log.*.gz ) cat access.log ) | calamaris -a -F html > /var/www/html/calamaris.html Gottfried Hamm idea of using calamaris for reporting: (thanks to Hanno 'Rince' Wagner for bugfixing.) ----------------------------------------------------------------------- squid.conf ========== [...] logfile_rotate 7 [...] crontab ======= [...] 0 0 * * * /usr/local/squid/bin/squidrep [...] /usr/local/squid/bin/squidrep ============================= #!/bin/sh # SquidReport by Gottfried Hamm # Created 07.01.2000 # Updated BINDIR=/usr/local/squid/bin LOGDIR=/usr/local/squid/logs DAYOFWEEK=`date +"%w"` DATE=`date +"%Y%m%d"` ## Rotate the logs # $BINDIR/squid -k rotate sleep 300 ## Daily report via mail to webmaster # cd $LOGDIR cat access.log.0 | \ $BINDIR/calamaris -aH 'Daily' -F mail | \ mailx -s "Daily Proxy-Report `date`" squidmaster@cord.de ## Weekly report will be stored as web page # if [ $DAYOFWEEK = "0" ]; then cat access.log.? | $BINDIR/calamaris -a -F html -l 'GHKS' > \ /data/www/ghks.de/admin/proxy/report-$DATE.html fi exit 0 ----------------------------------------------------------------------- Thomas Wahyudi method: ----------------------------------------------------------------------- #!/bin/sh # SquidReport Script by Matthew King # rewriten by Thomas Wahyudi # Last update: 15-05-2000. # Sample Crontab # 0 0 * * * /cache/squid/bin/squid -k rotate # 30 0 * * * /cache/squid/bin/squidreport ################################################## dailyreport="/www/htdocs/Squid/report/daily/" weeklyreport="/www/htdocs/Squid/report/weekly/" programpath="/cache/squid/bin/calamaris" squidlog="/cache/squid/logs" hef1=`/bin/date | /usr/bin/awk '{print $2}'` hef2=`/bin/date | /usr/bin/awk '{print $3}'` hef3=`/bin/date | /usr/bin/awk '{print $1}'` hef4=`/bin/date | /usr/bin/awk '{print $6}'` # Convert date if less then 10 ############################## if [ "$hef2" -lt "10" ] then hef2="0$hef2" fi # Create the new report and place it into the report location # report in file ex. Mar.28.Tue.2000.htm will contain yesterday performance ########################################################################### cat $squidlog/access.log.0 | nice -39 $programpath -aH 'Yesterday worf' -F mail,html > "$dailyreport$hef1.$hef2.$hef3.$hef4.htm" # This script will remove the outdated Squid HTML report, # The report will include all available squid access log files.. # Roughly 31 days worth. The report will then be dumped into # report location to be viewed via a web browser. ################################################################ totalreport=`/bin/ls $dailyreport | /usr/bin/wc | /usr/bin/awk '{print $1}'` if [ $totalreport -gt 31 ] then get1file=`/bin/ls $dailyreport | /usr/bin/head -n 1` /bin/rm $dailyreport$get1file fi # Every Monday will create report for weekly report ################################################### totalreport=`/bin/ls $weeklyreport | /usr/bin/wc | /usr/bin/awk '{print $1}'` if [ "$hef3" = "Mon" ] then cat $squidlog/access.log.6 $squidlog/access.log.5 $squidlog/access.log.4 $squidlog/access.log.3 \ $squidlog/access.log.2 $squidlog/access.log.1 $squidlog/access.log.0 \ | $programpath -aH 'Weekly worf' -F mail,html > "$weeklyreport$hef1.$hef2.$hef3.$hef4.htm" if [ $totalreport -gt 5 ] then get1file=`/bin/ls $weeklyreport | /usr/bin/head -n 1` /bin/rm $weeklyreport$get1file fi fi ----------------------------------------------------------------------- My method: ----------------------------------------------------------------------- squid.conf: ----------------------------------------------------- [...] logfile_rotate 7 [...] ----------------------------------------------------- crontab: ----------------------------------------------------- 0 0 * * * /usr/local/squid/bin/squid -k rotate 30 0 * * * cat /var/log/squid/access.log.0 | \ nice -39 /usr/local/squid/bin/calamaris -aH 'daily worf' -F mail | \ mail Squidmaster@Cord.de 0 3 * * 7 (cd /var/log/squid/; cat access.log.6 access.log.5 \ access.log.4 access.log.3 access.log.2 access.log.1 \ access.log.0) | \ nice -39 /usr/local/squid/bin/calamaris -aH 'weekly worf' -F mail | \ mail Squidmaster@Cord.de ----------------------------------------------------- Everyone who really uses while testing has to send me a postcard! ----------------------------------------------------------------------- Version of the EXAMPLES ----------------------- $Id: EXAMPLES,v 2.13 2004-09-15 20:41:58 cord Exp $