X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=tools%2Fprivoxy-log-parser.pl;h=0963993898e05f4447eeb68b996b8398d03d9265;hp=ca9df7b9d94ac0ac280ae9c794109af405298774;hb=2616e38ac513d1e4fc439fbca1197135f69e186b;hpb=8dd62cb4ac4dbdf030e38d60c804bdc6e8c102b1 diff --git a/tools/privoxy-log-parser.pl b/tools/privoxy-log-parser.pl index ca9df7b9..09639938 100755 --- a/tools/privoxy-log-parser.pl +++ b/tools/privoxy-log-parser.pl @@ -6,9 +6,7 @@ # A parser for Privoxy log messages. For incomplete documentation run # perldoc privoxy-log-parser(.pl), for fancy screenshots see: # -# http://www.fabiankeil.de/sourcecode/privoxy-log-parser/ -# -# $Id: privoxy-log-parser.pl,v 1.158 2013/01/16 16:30:00 fabiankeil Exp $ +# https://www.fabiankeil.de/sourcecode/privoxy-log-parser/ # # TODO: # - LOG_LEVEL_CGI, LOG_LEVEL_ERROR, LOG_LEVEL_WRITE content highlighting @@ -25,7 +23,7 @@ # hash key as input. # - Add --compress and --decompress options. # -# Copyright (c) 2007-2013 Fabian Keil +# Copyright (c) 2007-2020 Fabian Keil # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -45,7 +43,7 @@ use warnings; use Getopt::Long; use constant { - PRIVOXY_LOG_PARSER_VERSION => '0.8', + PRIVOXY_LOG_PARSER_VERSION => '0.9.1', # Feel free to mess with these ... DEFAULT_BACKGROUND => 'black', # Choose registered colour (like 'black') DEFAULT_TEXT_COLOUR => 'white', # Choose registered colour (like 'black') @@ -113,7 +111,7 @@ my $no_msecs_mode; # XXX: should probably be removed my $shorten_thread_ids; my $line_end; -sub prepare_our_stuff () { +sub prepare_our_stuff() { # Syntax Higlight hash @all_colours = ( @@ -221,7 +219,7 @@ sub prepare_our_stuff () { init_stats(); } -sub paint_it ($) { +sub paint_it($) { ############################################################### # Takes a colour string and returns an ANSI escape sequence # (unless --no-syntax-highlighting is used). @@ -298,7 +296,7 @@ sub paint_it ($) { return $colour_code; } -sub get_semantic_html_markup ($) { +sub get_semantic_html_markup($) { ############################################################### # Takes a string and returns a span element ############################################################### @@ -316,7 +314,7 @@ sub get_semantic_html_markup ($) { return $code; } -sub cli_option_is_set ($) { +sub cli_option_is_set($) { our %cli_options; my $cli_option = shift; @@ -326,7 +324,7 @@ sub cli_option_is_set ($) { return $cli_options{$cli_option}; } -sub get_html_title () { +sub get_html_title() { our %cli_options; return $cli_options{'title'}; @@ -356,7 +354,7 @@ sub init_css_colours() { ); } -sub get_css_colour ($) { +sub get_css_colour($) { our %css_colours; my $colour = shift; @@ -366,7 +364,7 @@ sub get_css_colour ($) { return '#' . $css_colours{$colour}; } -sub get_css_line ($) { +sub get_css_line($) { my $class = shift; my $css_line; @@ -380,7 +378,7 @@ sub get_css_line ($) { return $css_line; } -sub get_css_line_for_colour ($) { +sub get_css_line_for_colour($) { my $colour = shift; my $css_line; @@ -394,7 +392,7 @@ sub get_css_line_for_colour ($) { } # XXX: Wrong solution -sub get_missing_css_lines () { +sub get_missing_css_lines() { my $css_line; @@ -406,7 +404,7 @@ sub get_missing_css_lines () { return $css_line; } -sub get_css () { +sub get_css() { our %css_colours; #XXX: Wrong solution @@ -435,7 +433,7 @@ sub get_css () { return $css; } -sub print_intro () { +sub print_intro() { my $intro = ''; @@ -453,7 +451,7 @@ sub print_intro () { } } -sub print_outro () { +sub print_outro() { my $outro = ''; @@ -465,11 +463,11 @@ sub print_outro () { } } -sub get_line_end () { +sub get_line_end() { return cli_option_is_set('html-output') ? "
\n" : "\n"; } -sub get_colour_html_markup ($) { +sub get_colour_html_markup($) { ############################################################### # Takes a colour string a span element. XXX: WHAT? # XXX: This function shouldn't be necessary, the @@ -488,21 +486,21 @@ sub get_colour_html_markup ($) { return $code; } -sub default_colours () { +sub default_colours() { # XXX: Properly our $bg_code; return reset_colours(); } -sub show_colours () { +sub show_colours() { # XXX: Implement } -sub reset_colours () { +sub reset_colours() { return ESCAPE . "0m"; } -sub set_background ($){ +sub set_background($) { my $colour = shift; our $bg_code; @@ -525,11 +523,11 @@ sub set_background ($){ } } -sub get_background (){ +sub get_background() { return our $bg_code; } -sub prepare_highlight_hash ($) { +sub prepare_highlight_hash($) { my $ref = shift; foreach my $key (keys %$ref) { @@ -539,7 +537,7 @@ sub prepare_highlight_hash ($) { } } -sub prepare_colour_array ($) { +sub prepare_colour_array($) { my $ref = shift; foreach my $i (0 ... @$ref - 1) { @@ -549,7 +547,7 @@ sub prepare_colour_array ($) { } } -sub found_unknown_content ($) { +sub found_unknown_content($) { my $unknown = shift; my $message; @@ -568,7 +566,7 @@ sub found_unknown_content ($) { die "Unworthy content parser" if PUNISH_MISSING_LOG_KNOWLEDGE_WITH_DEATH; } -sub log_parse_error ($) { +sub log_parse_error($) { my $message = shift; @@ -579,7 +577,7 @@ sub log_parse_error ($) { } } -sub debug_message (@) { +sub debug_message(@) { my @message = @_; print $h{'debug'} . "@message" . $h{'Standard'} . "\n"; @@ -589,7 +587,7 @@ sub debug_message (@) { # highlighter functions that aren't loglevel-specific ################################################################################ -sub h ($) { +sub h($) { # Get highlight marker my $highlight = shift; # XXX: Stupid name; @@ -611,7 +609,7 @@ sub h ($) { return $result; } -sub highlight_known_headers ($) { +sub highlight_known_headers($) { my $content = shift; @@ -626,7 +624,7 @@ sub highlight_known_headers ($) { return $content; } -sub highlight_matched_request_line ($$) { +sub highlight_matched_request_line($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; @@ -636,7 +634,7 @@ sub highlight_matched_request_line ($$) { return $result; } -sub highlight_request_line ($) { +sub highlight_request_line($) { my $rl = shift; my ($method, $url, $http_version); @@ -646,7 +644,7 @@ sub highlight_request_line ($) { $rl = h('invalid-request') . $rl . h('Standard'); - } elsif ($rl =~ m/^([-\w]+) (.*) (HTTP\/\d\.\d)/) { + } elsif ($rl =~ m/^([-\w]+) (.*) (HTTP\/\d+\.\d+)/) { # XXX: might not match in case of HTTP method fuzzing. # XXX: save these: ($method, $path, $http_version) = ($1, $2, $3); @@ -677,7 +675,7 @@ sub highlight_request_line ($) { return $rl; } -sub highlight_response_line ($) { +sub highlight_response_line($) { my $rl = shift; my ($http_version, $status_code, $status_message); @@ -704,7 +702,7 @@ sub highlight_response_line ($) { return $rl; } -sub highlight_matched_url ($$) { +sub highlight_matched_url($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; @@ -719,7 +717,7 @@ sub highlight_matched_url ($$) { return $result; } -sub highlight_matched_host ($$) { +sub highlight_matched_host($$) { my ($result, $regex) = @_; # XXX: result ist stupid name; @@ -730,7 +728,7 @@ sub highlight_matched_host ($$) { return $result; } -sub highlight_matched_pattern ($$$) { +sub highlight_matched_pattern($$$) { my $result = shift; # XXX: Stupid name; my $key = shift; @@ -745,7 +743,7 @@ sub highlight_matched_pattern ($$$) { return $result; } -sub highlight_matched_path ($$) { +sub highlight_matched_path($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; @@ -757,7 +755,7 @@ sub highlight_matched_path ($$) { return $result; } -sub highlight_url ($) { +sub highlight_url($) { my $url = shift; @@ -774,7 +772,7 @@ sub highlight_url ($) { return $url; } -sub update_header_highlight_regex ($) { +sub update_header_highlight_regex($) { my $header = shift; my $headers = join ('|', keys %header_colours); @@ -787,7 +785,7 @@ sub update_header_highlight_regex ($) { # loglevel-specific highlighter functions ################################################################################ -sub handle_loglevel_header ($) { +sub handle_loglevel_header($) { my $c = shift; @@ -1039,7 +1037,7 @@ sub handle_loglevel_header ($) { return $c; } -sub handle_loglevel_re_filter ($) { +sub handle_loglevel_re_filter($) { my $content = shift; my $c = $content; @@ -1063,7 +1061,7 @@ sub handle_loglevel_re_filter ($) { return ''; } - $c =~ s@(?<=\(size )(\d+)\)(?= with)@$h{'Number'}$1$h{'Standard'}@; + $c =~ s@(?<=\(size )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=\(new size )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=produced )(\d+)(?= hits)@$h{'Number'}$1$h{'Standard'}@; @@ -1221,7 +1219,7 @@ sub handle_loglevel_re_filter ($) { return $content; } -sub handle_loglevel_redirect ($) { +sub handle_loglevel_redirect($) { my $c = shift; @@ -1287,7 +1285,7 @@ sub handle_loglevel_redirect ($) { return $c; } -sub handle_loglevel_gif_deanimate ($) { +sub handle_loglevel_gif_deanimate($) { my $content = shift; @@ -1333,7 +1331,7 @@ sub handle_loglevel_gif_deanimate ($) { return $content; } -sub handle_loglevel_request ($) { +sub handle_loglevel_request($) { my $content = shift; @@ -1368,7 +1366,7 @@ sub handle_loglevel_request ($) { return $content; } -sub handle_loglevel_crunch ($) { +sub handle_loglevel_crunch($) { my $content = shift; @@ -1392,7 +1390,7 @@ sub handle_loglevel_crunch ($) { return $content; } -sub handle_loglevel_connect ($) { +sub handle_loglevel_connect($) { my $c = shift; @@ -1612,7 +1610,10 @@ sub handle_loglevel_connect ($) { # Connection from 81.163.28.218 dropped due to ACL # Rejecting connection from 178.63.152.227. Maximum number of connections reached. - $c =~ s@(?<=onnection from )((?:\d+\.?){3}\d+)@$h{'Number'}$1$h{'Standard'}@; + # Connection from 192.168.2.1 on 127.0.1.1:8118 (socket 3) dropped due to ACL + $c = highlight_matched_host($c, '(?<=onnection from )[\d.:]+'); + $c = highlight_matched_host($c, '(?<=on )[\d.:]+'); + $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^(?:Reusing|Closing) server socket / or $c =~ m/^No additional client request/) { @@ -1737,6 +1738,32 @@ sub handle_loglevel_connect ($) { $c =~ s@(?<=Shifting )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=by )(\d+)@$h{'Number'}$1$h{'Standard'}@; + } elsif ($c =~ m/^Flushed (\d+) bytes of request body while expecting (\d+)/) { + + # Flushed 30 bytes of request body while expecting 30 + $c =~ s@(?<=Flushed )(\d+)@$h{'Number'}$1$h{'Standard'}@; + $c =~ s@(?<=expecting )(\d+)@$h{'Number'}$1$h{'Standard'}@; + + } elsif ($c =~ m/^Performing the TLS\/SSL handshake with client. Hash of host:/) { + + # Performing the TLS/SSL handshake with client. Hash of host: bab5296b25e256c7b06b92b17b56bcae + $c = highlight_matched_host($c, '(?<=Hash of host: ).+'); + + } elsif ($c =~ m/^Forwarding \d+ bytes of encrypted POST data/) { + + # Forwarding 1954 bytes of encrypted POST data + $c =~ s@(?<=Forwarding )(\d+)@$h{'Number'}$1$h{'Standard'}@; + + } elsif ($c =~ m/^Forwarded the last \d+ bytes/) { + + # Forwarded the last 1954 bytes + $c =~ s@(?<=the last )(\d+)@$h{'Number'}$1$h{'Standard'}@; + + } elsif ($c =~ m/^Waiting for the next client connection. Currently active threads:/) { + + # Waiting for the next client connection. Currently active threads: 30 + $c =~ s@(?<=threads: )(\d+)@$h{'Number'}$1$h{'Standard'}@; + } elsif ($c =~ m/^Looks like we / or $c =~ m/^Unsetting keep-alive flag/ or $c =~ m/^No connections to wait/ or @@ -1778,7 +1805,7 @@ sub handle_loglevel_connect ($) { } -sub handle_loglevel_info ($) { +sub handle_loglevel_info($) { my $c = shift; @@ -1904,7 +1931,7 @@ sub handle_loglevel_info ($) { return $c; } -sub handle_loglevel_cgi ($) { +sub handle_loglevel_cgi($) { my $c = shift; @@ -1926,7 +1953,7 @@ sub handle_loglevel_cgi ($) { return $c; } -sub handle_loglevel_force ($) { +sub handle_loglevel_force($) { my $c = shift; @@ -1950,7 +1977,7 @@ sub handle_loglevel_force ($) { return $c; } -sub handle_loglevel_error ($) { +sub handle_loglevel_error($) { my $c = shift; @@ -1978,11 +2005,49 @@ sub handle_loglevel_error ($) { } -sub handle_loglevel_ignore ($) { +sub handle_loglevel_ignore($) { return shift; } -sub gather_loglevel_request_stats ($$) { +sub gather_loglevel_clf_stats($) { + + my $content = shift; + my ($method, $resource, $http_version, $status_code, $size); + our %stats; + our %cli_options; + + # +0200] "GET https://www.youtube.com/watch?v=JmcA9LIIXWw HTTP/1.1" 200 68004 + # +0200] "VERSION-CONTROL http://p.p/ HTTP/1.1" 200 2787 + $content =~ m/^[+-]\d{4}\] "([^ ]+) (.+) (HTTP\/\d\.\d)" (\d+) (\d+)/; + $method = $1; + $resource = $2; + $http_version = $3; + $status_code = $4; + $size = $5; + + $stats{requests_clf}++; + + unless (defined $method) { + # +0200] "Invalid request" 400 0 + return if ($content =~ m/^[+-]\d{4}\] "Invalid request"/); + print("Failed to parse: $content\n"); + return; + } + $stats{'method'}{$method}++; + if ($cli_options{'url-statistics-threshold'} != 0) { + $stats{'resource'}{$resource}++; + } + $stats{'http-version'}{$http_version}++; + + if ($cli_options{'host-statistics-threshold'} != 0) { + $resource =~ m@(?:https?://)?([^/]+)/?@; + $stats{'hosts'}{$1}++; + } + $stats{'content-size-total'} += $size; + $stats{'status-code'}{$status_code}++; +} + +sub gather_loglevel_request_stats($$) { my $c = shift; my $thread = shift; our %stats; @@ -1990,12 +2055,11 @@ sub gather_loglevel_request_stats ($$) { $stats{requests}++; } -sub gather_loglevel_crunch_stats ($$) { +sub gather_loglevel_crunch_stats($$) { my $c = shift; my $thread = shift; our %stats; - $stats{requests}++; $stats{crunches}++; if ($c =~ m/^Redirected:/) { @@ -2005,11 +2069,19 @@ sub gather_loglevel_crunch_stats ($$) { } elsif ($c =~ m/^Blocked:/) { # Blocked: blogger.googleusercontent.com:443 $stats{'blocked'}++; + + } elsif ($c =~ m/^Connection timeout:/) { + # Connection timeout: http://c.tile.openstreetmap.org/18/136116/87842.png + $stats{'connection-timeout'}++; + + } elsif ($c =~ m/^Connection failure:/) { + # Connection failure: http://127.0.0.1:8080/ + $stats{'connection-failure'}++; } } -sub gather_loglevel_error_stats ($$) { +sub gather_loglevel_error_stats($$) { my $c = shift; my $thread = shift; @@ -2028,7 +2100,7 @@ sub gather_loglevel_error_stats ($$) { } } -sub gather_loglevel_connect_stats ($$) { +sub gather_loglevel_connect_stats($$) { my ($c, $thread) = @_; our %thread_data; @@ -2070,10 +2142,11 @@ sub gather_loglevel_connect_stats ($$) { } } -sub gather_loglevel_header_stats ($$) { +sub gather_loglevel_header_stats($$) { my ($c, $thread) = @_; our %stats; + our %cli_options; if ($c =~ m/^A HTTP\/1\.1 response without/ or $c =~ m/^Keeping the server header 'Connection: keep-alive' around./) @@ -2081,24 +2154,13 @@ sub gather_loglevel_header_stats ($$) { # A HTTP/1.1 response without Connection header implies keep-alive. # Keeping the server header 'Connection: keep-alive' around. $stats{'server-keep-alive'}++; - - } elsif ($c =~ m/^scan: ((\w+) (.+) (HTTP\/\d\.\d))/) { - - # scan: HTTP/1.1 200 OK - $stats{'method'}{$2}++; - $stats{'resource'}{$3}++; - $stats{'http-version'}{$4}++; - - } elsif ($c =~ m/^scan: Host: ([^\s]+)/) { - - # scan: Host: p.p - $stats{'hosts'}{$1}++; } } -sub init_stats () { +sub init_stats() { our %stats = ( requests => 0, + requests_clf => 0, crunches => 0, 'server-keep-alive' => 0, 'reused-connections' => 0, @@ -2107,14 +2169,17 @@ sub init_stats () { 'empty-responses-on-reused-connections' => 0, 'fast-redirections' => 0, 'blocked' => 0, + 'connection-failure' => 0, + 'connection-timeout' => 0, 'reused-connections' => 0, 'server-keep-alive' => 0, 'closed-client-connections' => 0, + 'content-size-total' => 0, ); $stats{'client-requests-on-connection'}{1} = 0; } -sub get_percentage ($$) { +sub get_percentage($$) { my $big = shift; my $small = shift; @@ -2129,48 +2194,73 @@ sub get_percentage ($$) { return sprintf("%.2f%%", $small / $big * 100); } -sub print_stats () { +sub print_stats() { our %stats; our %cli_options; my $new_connections = $stats{requests} - $stats{crunches} - $stats{'reused-connections'}; - my $outgoing_requests = $stats{requests} - $stats{crunches}; my $client_requests_checksum = 0; + my $requests_total; + + if ($stats{requests_clf} && $stats{requests} + && $stats{requests_clf} != $stats{requests}) { + print "Inconsistent request counts: " . $stats{requests} . "/" . $stats{requests_clf} . "\n"; + } - if ($stats{requests} eq 0) { + # To get the total number of requests we can use either the number + # of Common-Log-Format lines or the number of "Request:" messages. + # We prefer the number of CLF lines if available because using + # it works when analysing old log files from Privoxy versions before 3.0.29. + # In Privoxy 3.0.28 and earlier "Request:" messages excluded + # crunched messages. + $requests_total = $stats{requests_clf} ? $stats{requests_clf} : $stats{requests}; + + if ($requests_total eq 0) { print "No requests yet.\n"; return; } - print "Client requests total: " . $stats{requests} . "\n"; - print "Crunches: " . $stats{crunches} . " (" . - get_percentage($stats{requests}, $stats{crunches}) . ")\n"; - print "Blocks: " . $stats{'blocked'} . " (" . - get_percentage($stats{requests}, $stats{'blocked'}) . ")\n"; - print "Fast redirections: " . $stats{'fast-redirections'} . " (" . - get_percentage($stats{requests}, $stats{'fast-redirections'}) . ")\n"; - print "Outgoing requests: " . $outgoing_requests . " (" . - get_percentage($stats{requests}, $outgoing_requests) . ")\n"; + print "Client requests total: " . $requests_total . "\n"; + if ($stats{crunches}) { + my $outgoing_requests = $requests_total - $stats{crunches}; + print "Crunches: " . $stats{crunches} . " (" . + get_percentage($requests_total, $stats{crunches}) . ")\n"; + print "Blocks: " . $stats{'blocked'} . " (" . + get_percentage($requests_total, $stats{'blocked'}) . ")\n"; + print "Fast redirections: " . $stats{'fast-redirections'} . " (" . + get_percentage($requests_total, $stats{'fast-redirections'}) . ")\n"; + print "Connection timeouts: " . $stats{'connection-timeout'} . " (" . + get_percentage($requests_total, $stats{'connection-timeout'}) . ")\n"; + print "Connection failures: " . $stats{'connection-failure'} . " (" . + get_percentage($requests_total, $stats{'connection-failure'}) . ")\n"; + print "Outgoing requests: " . $outgoing_requests . " (" . + get_percentage($requests_total, $outgoing_requests) . ")\n"; + } else { + print "No crunches detected. Is 'debug 1024' enabled?\n"; + } + print "Server keep-alive offers: " . $stats{'server-keep-alive'} . " (" . - get_percentage($stats{requests}, $stats{'server-keep-alive'}) . ")\n"; + get_percentage($requests_total, $stats{'server-keep-alive'}) . ")\n"; print "New outgoing connections: " . $new_connections . " (" . - get_percentage($stats{requests}, $new_connections) . ")\n"; + get_percentage($requests_total, $new_connections) . ")\n"; print "Reused connections: " . $stats{'reused-connections'} . " (" . - get_percentage($stats{requests}, $stats{'reused-connections'}) . + get_percentage($requests_total, $stats{'reused-connections'}) . "; server offers accepted: " . get_percentage($stats{'server-keep-alive'}, $stats{'reused-connections'}) . ")\n"; print "Empty responses: " . $stats{'empty-responses'} . " (" . - get_percentage($stats{requests}, $stats{'empty-responses'}) . ")\n"; + get_percentage($requests_total, $stats{'empty-responses'}) . ")\n"; print "Empty responses on new connections: " . $stats{'empty-responses-on-new-connections'} . " (" . - get_percentage($stats{requests}, $stats{'empty-responses-on-new-connections'}) + get_percentage($requests_total, $stats{'empty-responses-on-new-connections'}) . ")\n"; print "Empty responses on reused connections: " . $stats{'empty-responses-on-reused-connections'} . " (" . - get_percentage($stats{requests}, $stats{'empty-responses-on-reused-connections'}) . + get_percentage($requests_total, $stats{'empty-responses-on-reused-connections'}) . ")\n"; print "Client connections: " . $stats{'closed-client-connections'} . "\n"; - + if ($stats{'content-size-total'}) { + print "Bytes of content transfered to the client: " . $stats{'content-size-total'} . "\n"; + } my $lines_printed = 0; print "Client requests per connection distribution:\n"; foreach my $client_requests (sort { @@ -2188,19 +2278,32 @@ sub print_stats () { unless ($cli_options{'show-complete-request-distribution'}) { printf "Enable --show-complete-request-distribution to get less common numbers as well.\n"; } - printf "Unaccounted requests: ~%d\n", $stats{requests} - $client_requests_checksum; + # Due to log rotation we may not have a complete picture for all the requests + printf "Improperly accounted requests: ~%d\n", abs($requests_total - $client_requests_checksum); - if ($stats{method} eq 0) { - print "No response lines parsed yet yet.\n"; - return; + if (exists $stats{method}) { + print "Method distribution:\n"; + foreach my $method (sort {$stats{'method'}{$b} <=> $stats{'method'}{$a}} keys %{$stats{'method'}}) { + printf "%8d : %-8s\n", $stats{'method'}{$method}, $method; + } + } else { + print "Method distribution unknown. No CLF message parsed yet. Is 'debug 512' enabled?\n"; } - print "Method distribution:\n"; - foreach my $method (sort {$stats{'method'}{$b} <=> $stats{'method'}{$a}} keys %{$stats{'method'}}) { - printf "%8d : %-8s\n", $stats{'method'}{$method}, $method; + if (exists $stats{'http-version'}) { + print "Client HTTP versions:\n"; + foreach my $http_version (sort {$stats{'http-version'}{$b} <=> $stats{'http-version'}{$a}} keys %{$stats{'http-version'}}) { + printf "%8d : %-8s\n", $stats{'http-version'}{$http_version}, $http_version; + } + } else { + print "HTTP version distribution unknown. No CLF message parsed yet. Is 'debug 512' enabled?\n"; } - print "Client HTTP versions:\n"; - foreach my $http_version (sort {$stats{'http-version'}{$b} <=> $stats{'http-version'}{$a}} keys %{$stats{'http-version'}}) { - printf "%d : %s\n", $stats{'http-version'}{$http_version}, $http_version; + if (exists $stats{'status-code'}) { + print "HTTP status codes:\n"; + foreach my $status_code (sort {$stats{'status-code'}{$b} <=> $stats{'status-code'}{$a}} keys %{$stats{'status-code'}}) { + printf "%8d : %-8d\n", $stats{'status-code'}{$status_code}, $status_code; + } + } else { + print "Status code distribution unknown. No CLF message parsed yet. Is 'debug 512' enabled?\n"; } if ($cli_options{'url-statistics-threshold'} == 0) { @@ -2235,7 +2338,7 @@ sub print_stats () { # Functions that actually print stuff ################################################################################ -sub print_clf_message () { +sub print_clf_message() { our ($ip, $timestamp, $request_line, $status_code, $size); my $output = ''; @@ -2257,7 +2360,7 @@ sub print_clf_message () { print $output; } -sub print_non_clf_message ($) { +sub print_non_clf_message($) { my $content = shift; my $msec_string = $no_msecs_mode ? '' : '.' . $req{$t}{'msecs'}; @@ -2282,7 +2385,7 @@ sub print_non_clf_message ($) { . $line_end; } -sub shorten_thread_id ($) { +sub shorten_thread_id($) { my $thread_id = shift; @@ -2296,7 +2399,7 @@ sub shorten_thread_id ($) { return $short_thread_ids{$thread_id} } -sub parse_loop () { +sub parse_loop() { my ($day, $time_stamp, $thread, $log_level, $content, $c, $msecs); my $last_msecs = 0; @@ -2396,7 +2499,7 @@ sub parse_loop () { } } -sub stats_loop () { +sub stats_loop() { my ($day, $time_stamp, $msecs, $thread, $log_level, $content); my $strict_checks = cli_option_is_set('strict-checks'); @@ -2424,10 +2527,14 @@ sub stats_loop () { while (<>) { (undef, $time_stamp, $thread, $log_level, $content) = split(/ /, $_, 5); - # Skip LOG_LEVEL_CLF - next if ($time_stamp eq "-" or not defined($log_level)); - if (defined($log_level_handlers{$log_level})) { + next if (not defined($log_level)); + + if ($time_stamp eq "-") { + + gather_loglevel_clf_stats($content); + + } elsif (defined($log_level_handlers{$log_level})) { $content = $log_level_handlers{$log_level}($content, $thread); @@ -2469,12 +2576,12 @@ sub VersionMessage { my $version_message; $version_message .= 'Privoxy-Log-Parser ' . PRIVOXY_LOG_PARSER_VERSION . "\n"; - $version_message .= 'http://www.fabiankeil.de/sourcecode/privoxy-log-parser/' . "\n"; + $version_message .= 'https://www.fabiankeil.de/sourcecode/privoxy-log-parser/' . "\n"; print $version_message; } -sub get_cli_options () { +sub get_cli_options() { our %cli_options = ( 'html-output' => CLI_OPTION_DEFAULT_TO_HTML_OUTPUT, @@ -2516,7 +2623,7 @@ sub get_cli_options () { $line_end = get_line_end(); } -sub help () { +sub help() { our %cli_options; @@ -2547,7 +2654,7 @@ see "perldoc $0" for more information ################################################################################ # main ################################################################################ -sub main () { +sub main() { get_cli_options(); set_background(DEFAULT_BACKGROUND);