#!/usr/bin/perl -wT
use strict;
$| = 1;
#
# named-report.pl - summarize ISC BIND 9 log messages
#
# Copyright (C) 2002,2003 John Kristoff
#
# 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 any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even 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.
#
# Author: John Kristoff <jtk@depaul.edu>
#         DePaul University
#         1 E. Jackson Blvd.
#         Chicago, IL USA
#
# Usage: ./named-report.pl named.log
#    or: ./named-report.pl < named.log
#    or: STDOUT | ./named-report.pl
#
# Needs a ISC BIND 9 named log file as an argument or as input
# via STDIN.  This will produce a summary of the log messages.
# View the README file for further information and instructions.
#
# 2002-12-05,jtk: Initial coding and testing
# 2003-01-21,jtk: bcq_ and ztd_ reporting, regexps ignore case, minor edits,
#                 enabled warnings/strict, zts_target_count/vsd_source bugs,
#                 disabled output buffering
# 2003-04-01,jtk: qrrc_, qrtc_, fe_ and rnna_ reporting, ls_servzone_count,
#                 cqd_ and cqcd_, log_count, hourly bargraph, PRINT_TIME
#                 option, localtime, getcwd, taint mode, report loop $TOPx
#                 bug, @ARGV usage bug, elimination of $_, for loops replace
#                 foreach, minor edits
# 2003-07-22,jtk: bug in bcq regexp, bug in vsd regexp, bug in cqd regexp,
#                 category_count, severity_count, generic cqd regexp,
#                 print_time auto-detect, logs_per_hour is now a hash,
#                 s_, slc_, snif_, sr_, se_, ssd_, sscc_, sloi_, snll_, zl_,
#                 zt_, zrfto_, zrrle_, sn_, snf_, ic_, esr_, jfc_ and iu_
#                 reporting, minor edits
# 2003-12-01,jtk: handle messages in syslog format, minor edits

my $DEBUG  = 0;     # 0 = disabled, 1 = enabled

my $DEBUG_start_time = 0;
if ($DEBUG) {
    $DEBUG_start_time = localtime;
    print "[DEBUG] debug mode enabled\n\n";
}

use Socket;         # for gethostbyaddr (resolving IPs to names)
use Cwd;            # for getcwd (getting current working directory)

my $PRIVACY = 1;    # 0 = off, 1 = on (/24 versus /32 in cq report)
my $RESOLVE = 1;    # 0 = off, 1 = on (resolve IPs to hostname)
my $TOPx = 10;      # max no. of rows for each report (5-25 recommended)

# initialize 24-hour log usage statistics
my %logs_per_hour = ();

# initialize category and severity log message detail hash arrays
my %category_count = ();
my %severity_count = ();

# initialize log message totals
my $log_total = 0;          # total log messages
my $s_total = 0;            # total server (status) messages
my $slc_total = 0;          # total server loading configurationss
my $snif_total = 0;         # total server no interface finds
my $sr_total = 0;           # total server runs
my $se_total = 0;           # total server exits
my $ssd_total = 0;          # total server shut downs
my $sscc_total = 0;         # total server stop command channel messages
my $sloi_total = 0;         # total server listening on interface messages
my $snll_total = 0;         # total server no longer listening messages
my $ic_total = 0;           # total invalid commands
my $jfc_total = 0;          # total journal file creations
my $cq_total = 0;           # total client queries
my $cqd_total = 0;          # total client query denies
my $cqcd_total = 0;         # total client query cache denies
my $zl_total = 0;           # total zone loads
my $sf_total = 0;           # total server fetches
my $zt_total = 0;           # total zones transfered
my $zts_total = 0;          # total zone transfers started
my $ztr_total = 0;          # total zone transfers received
my $ztf_total = 0;          # total zone transfer failures
my $ztd_total = 0;          # total zone transfers denied
my $bzt_total = 0;          # total bad zone transfers
my $zrfto_total = 0;        # total zone refresh failure time outs
my $zrrle_total = 0;        # total zone refresh retry limits exceeded
my $zu_total = 0;           # total zone updates
my $zuf_total = 0;          # total zone update failures
my $ls_total = 0;           # total lame servers
my $vs_total = 0;           # total version scans
my $vsd_total = 0;          # total version scans denied
my $bcq_total = 0;          # total broken client queries
my $qrrc_total = 0;         # total quota reached recursive clients
my $qrtc_total = 0;         # total quota reached TCP clients
my $fe_total = 0;           # total format errors
my $sn_total = 0;           # total send notifies
my $snf_total = 0;          # total send notify failures
my $rnna_total = 0;         # total receive notify not authoritative errors
my $esr_total = 0;          # total error sending responses
my $iu_total = 0;           # total insecure updates
my $other_total = 0;        # total other (unknown) log messages

# initialize log data hash arrays 
my %slc_file_count = ();    # server loading configuration file
my %sscc_ip_count = ();     # server stop command channel ip
my %sloi_int_count = ();    # server listening on interface interface
my %sloi_ip_count = ();     # server listening on interface ip
my %snll_ip_count = ();     # server no longer listening ip
my %ic_source_count = ();   # invalid command ip
my %ic_desc_count = ();     # invalid command description
my %jfc_file_count = ();    # journal file creation file
my %cq_source_count = ();   # client query source
my %cq_data_count = ();     # client query data 
my %cq_type_count = ();     # client query type
my %cqd_source_count = ();  # client query deny source
my %cqd_data_count = ();    # client query deny data
my %cqcd_source_count = (); # client query cache deny source
my %zl_zone_count = ();     # zone load zone
my %sf_target_count = ();   # server fetch target
my %sf_type_count = ();     # server fetch type
my %zt_zone_count = ();     # zone transfered zone
my %zt_serial_count = ();   # zone transfered serial
my %zts_target_count = ();  # zone transfer started target
my %zts_zone_count = ();    # zone transfer started zone
my %zts_type_count = ();    # zone transfer started type
my %ztr_zone_count = ();    # zone transfer received zone
my %ztr_source_count = ();  # zone transfer received source
my %ztf_zone_count = ();    # zone transfer failure zone
my %ztf_source_count = ();  # zone transfer failure source
my %ztf_error_count = ();   # zone transfer failure error
my %ztd_source_count = ();  # zone transfer deny source
my %ztd_zone_count = ();    # zone transfer deny zone
my %bzt_source_count = ();  # bad zone transfer source
my %bzt_zone_count = ();    # bad zone transfer zone
my %bzt_desc_count = ();    # bad zone transfer description
my %zrfto_zone_count = ();  # zone refresh failure timed out zone
my %zrfto_master_count = ();# zone refresh failure timed out master
my %zrrle_zone_count = ();  # zone refresh retry limit exceeded zone
my %zrrle_master_count = ();# zone refresh retry limit exceeded master
my %zu_source_count = ();   # zone update source
my %zu_zone_count = ();     # zone update zone
my %zu_desc_count = ();     # zone update description
my %zuf_source_count = ();  # zone update failure source
my %zuf_zone_count = ();    # zone update failure zone
my %zuf_desc_count = ();    # zone update failure description
my %ls_record_count = ();   # lame server record
my %ls_zone_count = ();     # lame server zone
my %ls_server_count = ();   # lame server server
my %ls_servzone_count = (); # lame server/zone
my %vs_source_count = ();   # version scan source
my %vsd_source_count = ();  # version scan deny source
my %bcq_source_count = ();  # broken client query source
my %bcq_class_count = ();   # broken client query class
my %qrrc_source_count = (); # quota reached recursive client source
my %qrtc_source_count = (); # quota reached TCP client source
my %fe_source_count = ();   # format error source
my %sn_zone_count = ();     # send notify zone
my %sn_serial_count = ();   # send notify serial
my %snf_zone_count = ();    # send notify failure zones
my %snf_dst_count = ();     # send notify failure destinations
my %snf_desc_count = ();    # send notify failure descriptions
my %rnna_zone_count = ();   # receive notify not authoritative zone
my %esr_dst_count = ();     # error sending response destination
my %esr_desc_count = ();    # error sending response description
my %iu_zone_count = ();     # insecure update zones

my @arguments = @ARGV;      # save arguments (files) from shift in <> loop

# Pass named.log (or whatever filenames) as script argument or send
# properly formatted log messages to the script via unix STDIN.

while (defined(my $log = <>)) {

    chomp $log;
    $log_total++;

    my $msg = $log;
    # peel out date/time if present - note: comes before category and severity
    if ($msg =~ /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+
                    [0-3]?[0-9]\s+             # day
                    [0-2][0-9]\:               # hour
                    [0-5][0-9]\:               # minute
                    [0-5][0-9]                 # second
                    ((\.\d{3})?|               # microsecond if present
                    (\s\S+\s+named\[\d+\]\:)?) # syslog id if present
                    \s+/x
       ) {

        my ($month, $day, $hour, $minute, $second ) =
           ("",     "",   "",    "",      "");

        ($month, $day, $hour, $minute, $second, $msg)
            = split (/\s+|\:/, $msg, 6);

        # strip out leading zero so we can use $hour in loops
        if ($hour =~ /^0(\d)$/) { $hour = $1; }

        # strip out syslog id if present
        if ($msg =~ /^\S+\snamed\[\d+\]\:\s(.*)$/) { $msg = $1; }

        $logs_per_hour{$hour}++;
    }

    # peel out category if present - note: colon differentiates between cq_
    if ( $msg =~ /^(client|config|database|default|dispatch|dnssec|general|
                    lame-servers|network|notify|queries|resolver|security|
                    unmatched|update|xfer-in|xfer-out)\:\s+/x
       ) {
        (my $category, $msg) = split (/\:\s+/, $msg, 2);
        $category_count{$category}++;
    }

    # peel out severity if present - note: severity comes after category
    if ( $msg =~ /^(critical|error|warning|notice|info|debug\s*\d*)\:\s+/x
       ) {
        # debug serverity may be followed by a level, strip out
        (my $severity, $msg) = split (/\:\s+/, $msg, 2);
        $severity_count{$severity}++;
    }
   
    # not a switch, but a group of if($msg =~ /<regexp>/i) {... next} evals
    SWITCH: {

        # server (status)
        #
        # loading configuration from '[/path/to/file]'
        # no IPv6 interfaces found
        # running
        # exiting
        # shutting down
        # stopping command channel on [ip]#[port]
        # listening on IPv[version] interface [interface], [ip]#[port]
        # no longer listening on [ip]#[port]

        if ($msg =~
            /^loading\s+configuration\s+from\s+\'\S+\'/i
           ) {

            $s_total++;
            $slc_total++;
            my ($slc_file) = (0);

            ($slc_file) = $msg =~
                /^loading\s+configuration\s+from\s+\'
                (\S+)                                   # slc_file
                \'/ix;

            $slc_file_count{$slc_file}++;

            next;
        }

        if ($msg =~
            /^running/i
           ) {

            $s_total++;
            $sr_total++;

            next;
        }

        if ($msg =~
            /^no\s+IPv6\s+interfaces\s+found/i
           ) {

            $s_total++;
            $snif_total++;

            next;
        }

        if ($msg =~
            /^exiting/i
           ) {

           $s_total++;
           $se_total++;

           next;
        }

        if ($msg =~
            /^shutting\s+down/i
           ) {

           $s_total++;
           $ssd_total++;

           next;
        }

        if ($msg =~
             /^stopping\s+command\s+channel\s+on\s+\d+\.\d+\.\d+\.\d+\#\d+/i
           ) {

            $s_total++;
            $sscc_total++;
            my ($sscc_ip) = (0);

            ($sscc_ip) = $msg =~
                /^stopping\s+command\s+channel
                \s+on\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # sscc_ip
                \#\d+/ix;

            $sscc_ip_count{$sscc_ip}++;

            next;
        }

        if ($msg =~
            /^listening\s+on\s+IPv4\s+interface\s+\S+\,\s+\d+\.\d+\.\d+\.\d+\#\d+/i
           ) {

            $s_total++;
            $sloi_total++;
            my ($sloi_int, $sloi_ip) = (0, 0);

            ($sloi_int, $sloi_ip) = $msg =~
                /^listening\s+on\s+IPv4\s+interface\s+
                (\S+)                                    # sloi_int
                \,\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # sloi_ip
                \#\d+/ix;

            $sloi_int_count{$sloi_int}++;
            $sloi_ip_count{$sloi_ip}++;

            next;
        }

        if ($msg =~
            /^no\s+longer\s+listening\s+on\s+\d+\.\d+\.\d+\.\d+\#\d+/i
           ) {

            $s_total++;
            $snll_total++;
            my ($snll_ip) = (0, 0);

            ($snll_ip) = $msg =~
                /^no\s+longer\s+listening\s+on\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})    # snll_ip
                \#\d+/ix;

            $snll_ip_count{$snll_ip}++;

            next;
        }

        # invalid command
        #
        # invalid command from [ip]#[port]: [description]

        if ($msg =~
            /^invalid\s+command\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+.*/i
           ) {

            $ic_total++;
            my ($ic_source, $ic_desc) = (0, 0);

            ($ic_source, $ic_desc) = $msg =~
                /^invalid\s+command\s+from\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})    # ic_source
                \#\d+\:\s+
                (.*)                                    # ic_desc
                /ix;

            $ic_source_count{$ic_source}++;
            $ic_desc_count{$ic_desc}++;

            next;
        }

        # journal file creation
        #
        # journal file [file] does not exist, creating it

        if ($msg =~
            /^journal\s+file\s+\S+\s+does\s+not\s+exist\,\s+creating\s+it/i
           ) {

             $jfc_total++;
             my ($jfc_file) = (0);

             ($jfc_file) = $msg =~
                 /^journal\s+file\s+
                 (\S+)                                 # jfc_file
                 \s+does\s+not\s+exist\,
                 \s+creating\s+it/ix;

            $jfc_file_count{$jfc_file}++;

            next;
        }

        # 
        # client query
        #
        # client [ip]#[port]: query: [record] [IN/ANY] [type]

        if ($msg =~ 
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\:\s+\S+\s+(IN|ANY)\s+\S+/i
	   ) {

	    $cq_total++;
            my ($cq_source, $cq_data, $cq_type) = (0, 0, 0);

            if ($PRIVACY) { 
                ($cq_source, $cq_data, $cq_type) = $msg =~
                    /^client\s+
                    (\d{1,3}\.\d{1,3}\.\d{1,3})      # cq_source 24-bit subnet 
                    \.\d{1,3}\S+\s+query\:\s+
                    (\S+)                            # cq_data
                    \s+\S+\s+
                    (\S+)                            # cq_type
                    /ix;
            }
            else {
                ($cq_source, $cq_data, $cq_type) = $msg =~
                    /^client\s+
                    (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) # cq_source 32-bit host
                    \S+\s+query\:\s+
                    (\S+)                                # cq_data
                    \s+\S+\s+
                    (\S+)                                # cq_type
                    /ix;
            }

	    $cq_source_count{$cq_source}++;
	    $cq_data_count{lc($cq_data)}++;
	    $cq_type_count{$cq_type}++;

            next;
        }

        # client queries denied
        #
        # client [ip]#[port]: query '[record]/[IN|ANY]' denied
        # client [ip]#[port]: query denied

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\'\S+\/(IN|ANY)\'\s+denied/i
           ) {

            $cqd_total++;
            my ($cqd_source, $cqd_data)  = (0, 0);

            ($cqd_source, $cqd_data) = $msg =~
                /^client\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # cqd_source
                \#\d+\:\s+query\s+\'
                (\S+)                                    # cqd_data
                \/(IN|ANY)\'\s+denied/ix;

            $cqd_source_count{$cqd_source}++;
            $cqd_data_count{lc($cqd_data)}++;

            next;
        }

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+denied/i
           ) {

            $cqd_total++;
            my ($cqd_source)  = (0);

            ($cqd_source) = $msg =~
                /^client\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # cqd_source
                \#\d+\:\s+query\s+denied/ix;

            $cqd_source_count{$cqd_source}++;

            next;
        }

        # client queries cache denied
        #
        # client [ip]#[port]: query (cache) denied

        if ($msg =~ 
	    /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\(cache\)\s+denied/i
	   ) {

	    $cqcd_total++;
            my ($cqcd_source) = (0);

	    ($cqcd_source) = $msg =~
		/^client\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # cqcd_source
		\#\d+\:\s+query\s+\(cache\)\s+denied/ix;

	    $cqcd_source_count{$cqcd_source}++;

	    next;
	}

        # zone loads
        #
        # zone [zone]/IN: loaded serial [serial]

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+loaded\s+serial\s+\d+/i
           ) {

            $zl_total++;
            my ($zl_zone) = (0);

            ($zl_zone) = $msg =~
                /^zone\s+
                (\S+)                               # zl_zone
                \/IN\:\s+loaded\s+serial\s+\d+/ix;

            $zl_zone_count{$zl_zone}++;

            next;
        }

	# server fetch requests
	#
	# createfetch: [target] [type]

	if ($msg =~
	    /^createfetch\:\s+\S+\s+\S+/i
	   ) {

	    $sf_total++;
            my ($sf_target, $sf_type) = (0, 0);

	    ($sf_target, $sf_type) = $msg =~
		/^createfetch\:\s+
		(\S+)                   # sf_target
		\s+
		(\S+)                   # sf_type
		/ix;

	    $sf_target_count{lc($sf_target)}++;
	    $sf_type_count{$sf_type}++;

	    next;
	}

        # zone transferred
        #
        # note: BIND 9.2.1 logging spells 'transferred' wrong
        # zone [zone]/IN: transferr?ed serial [serial]

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+transferr?ed\s+serial\s+\d+/i
           ) {

            $zt_total++;
            my ($zt_zone, $zt_serial) = (0, 0);

            ($zt_zone, $zt_serial) = $msg =~
                /^zone\s+
                (\S+)                                     # zt_zone
                \/IN\:\s+transferr?ed\s+serial\s+
                (\d+)                                     # zt_serial
                /ix;

            $zt_zone_count{$zt_zone}++;
            $zt_serial_count{$zt_serial}++;

            next;
        }

        # zone transfer started
        #
        # client [ip]#[port]: transfer of '[zone]/IN':
        # (AXFR|IXFR|AFXR-style IXFR) started

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+transfer\s+of\s+\'\S+\/IN\'\:\s+(AXFR|AXFR-style IXFR|IXFR)\s+started/i
           ) {

            $zts_total++;
            my ($zts_target, $zts_zone, $zts_type) = (0, 0, 0);

            ($zts_target, $zts_zone, $zts_type) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})       # zts_target
                \#\d+\:\s+transfer\s+of\s+\'
                (\S+)                                      # zts_zone
                \/IN\'\:\s+
                (AXFR|AXFR\-style\s+IXFR|IXFR)             # zts_type
                \s+started/ix;

            $zts_target_count{$zts_target}++;
            $zts_zone_count{$zts_zone}++;
            $zts_type_count{$zts_type}++;

            next;
        }

	# zone transfer received
	#
	# transfer of '[zone]/IN' from [ip]#[port]: end of transfer

	if ($msg =~
	    /^transfer\s+of\s+\'\S+\/IN\'\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+end\s+of\s+transfer/i
	   ) {

	    $ztr_total++;
            my ($ztr_zone, $ztr_source) = (0, 0);

	    ($ztr_zone, $ztr_source) = $msg =~
		/^transfer\s+of\s+\'
		(\S+)                                       # ztr_zone
		\/IN\'\s+from\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})        # ztr_source
		\#\d+\:\s+end\s+of\s+transfer/ix;

	    $ztr_zone_count{lc($ztr_zone)}++;
	    $ztr_source_count{$ztr_source}++;
   
	    next;
	}

	# zone transfer failure
	#
	# transfer of '[zone]/IN' from [ip]#[port:] failed while receiving \
	# responses: [error]

	if ($msg =~
	    /^transfer\s+of\s+\'\S+\/IN\'\s+from\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+failed\s+while\s+receiving\s+responses\:\s+\S+/i
	    ) {

	    $ztf_total++;
            my ($ztf_zone, $ztf_source, $ztf_error) = (0, 0, 0);

	    ($ztf_zone, $ztf_source, $ztf_error) = $msg =~
		/^transfer\s+of\s+\'
		(\S+)                                    # ztf_zone
		\/IN\'\s+from\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # ztf_source
		\#\d+\:\s+failed\s+while\s+
		receiving\s+responses\:\s+
		(\S+)                                    # ztf_error
		/ix;

	    $ztf_zone_count{lc($ztf_zone)}++;
	    $ztf_source_count{$ztf_source}++;
	    $ztf_error_count{$ztf_error}++;

	    next;
	}

        # zone transfer denied
        #
        # client [ip]#[port]: zone transfer '[zone]/IN' denied

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+zone\s+transfer\s+\'\S+\'\s+denied/i
           ) {

            $ztd_total++;
            my ($ztd_source, $ztd_zone) = (0, 0);

            ($ztd_source, $ztd_zone) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # ztd_source
                \#\d+\:\s+zone\s+transfer\s+\'
                (\S+)                                    # ztd_zone
                \/IN\'\s+denied/ix;

            $ztd_source_count{$ztd_source}++;
            $ztd_zone_count{lc($ztd_zone)}++;

            next;
        }

        # bad zone transfer
        #
        # client [ip]#[port]: bad zone transfer request: '[zone]/IN': [desc]

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+bad\s+zone\s+transfer\s+request\:\s+\'\S+\/IN\'\:\s+.*/i
           ) {

            $bzt_total++;
            my ($bzt_source, $bzt_zone, $bzt_desc) = (0, 0, 0);

            ($bzt_source, $bzt_zone, $bzt_desc) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})    # bzt_source
                \#\d+\:\s+bad\s+zone\s+transfer\s+
                request\:\s+\'
                (\S+)                                   # bzt_zone
                \/IN\'\:\s+
                (.*)                                    # bzt_desc
                /ix;

            $bzt_source_count{$bzt_source}++;
            $bzt_zone_count{$bzt_zone}++;
            $bzt_desc_count{$bzt_desc}++;

            next;

        }

        # zone refresh failure timed out
        #
        # zone [zone]/IN: refresh: failure trying master [ip]#[port]: timed out

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+refresh\:\s+failure\s+trying\s+master\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+timed\s+out/i
           ) {

            $zrfto_total++;
            my ($zrfto_zone, $zrfto_master) = (0, 0);

            ($zrfto_zone, $zrfto_master) = $msg =~
                /^zone\s+
                (\S+)                                    # zrfto_zone
                \/IN\:\s+refresh\:\s+failure\s+
                trying\s+master\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # zrfto_master
                \#\d+\:\s+timed\s+out/ix;

            $zrfto_zone_count{$zrfto_zone}++;
            $zrfto_master_count{$zrfto_master}++;

            next;
        }

        # zone refresh retry limit exceeded
        #
        # zone [zone]/IN: refresh: retry limit for master [ip]#[port] exceeded

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+refresh\:\s+retry\s+limit\s+for\s+master\s+\d+\.\d+\.\d+\.\d+\#\d+\s+exceeded/i
           ) {

            $zrrle_total++;
            my ($zrrle_zone, $zrrle_master) = (0, 0);

            ($zrrle_zone, $zrrle_master) = $msg =~
                /^zone\s+
                (\S+)                                   # zrrle_zone
                \/IN\:\s+refresh\:\s+retry\s+limit\s+
                for\s+master\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})    # zrrle_master
                \#\d+\s+exceeded/ix;

            $zrrle_zone_count{$zrrle_zone}++;
            $zrrle_master_count{$zrrle_master}++;

            next;
        }

        # zone update
        #
        # client [ip]#[port]: updating zone '[zone]/IN': (adding|deleting) an
        # (RR|rrset) 

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+updating\s+zone\s+\'\S+\/IN\'\:\s+(adding|deleting)\s+an\s+(RR|rrset)/i
           ) {

            $zu_total++;
            my ($zu_source, $zu_zone, $zu_desc) = (0, 0, 0);

            ($zu_source, $zu_zone, $zu_desc) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})   # zu_source
                \#\d+\:\s+updating\s+zone\s+\'
                (\S+)                                  # zu_zone
                \/IN\'\:\s+
                (.*)                                   # zu_desc
                /ix;

            $zu_source_count{$zu_source}++;
            $zu_zone_count{$zu_zone}++;
            $zu_desc_count{$zu_desc}++;

            next;
        }

        # zone update failure
        #
        # client [ip]#[port]: updating zone '[zone]/IN': update failed: [desc]
        # client [ip]#[port]: update '[zone]/IN' denied

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+updating\s+zone\s+\'\S+\/IN\'\:\s+update\s+failed\:\s+.*/i
           ) {

            $zuf_total++;
            my ($zuf_source, $zuf_zone, $zuf_desc) = (0, 0, 0);

            ($zuf_source, $zuf_zone, $zuf_desc) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})   # zuf_source
                \#\d+\:\s+updating\s+zone\s+\'
                (\S+)                                  # zuf_zone
                \/IN\'\:\s+update\s+failed\:\s+
                (.*)                                   # zuf_desc
                /ix;

            $zuf_source_count{$zuf_source}++;
            $zuf_zone_count{$zuf_zone}++;
            $zuf_desc_count{$zuf_desc}++;

            next;
        }

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+update\s+\'\S+\/IN\'\s+denied/i
           ) {

            $zuf_total++;
            my ($zuf_source, $zuf_zone) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})   # zuf_source
                \#\d+\:\s+update\s+\'
                (\S+)                                  # zuf_zone
                \/IN\'\s+denied/ix;

            $zuf_source_count{$zuf_source}++;
            $zuf_zone_count{$zuf_zone}++;

            next;
        }
 
	# lame server report
        #
        # note: bind 9.2.x changed 'on' to 'resolving'
	# lame server [on|resolving] '[record]' (in '[zone]'?): [ip]#[port]

	if ($msg =~
	    /^lame\s+server\s+(on|resolving)\s+\'\S+\'\s+\(in\s+\'\S+\'\?\)\:\s+\S+\#\S+/i
	   ) {

	    $ls_total++;
            my ($ls_record, $ls_zone, $ls_server) = (0, 0, 0);

	    ($ls_record, $ls_zone, $ls_server) = $msg =~
		/^lame\s+server\s+\S+\s+\'
		(\S+)                                    # ls_record
		\'\s+\(in\s+\'
		(\S+)                                    # ls_zone
		\'\?\)\:\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # ls_server 
		\#\d+/ix;

	    $ls_record_count{lc($ls_record)}++;
	    $ls_zone_count{lc($ls_zone)}++;
	    $ls_server_count{$ls_server}++;
            $ls_servzone_count{$ls_server . "\t" . lc($ls_zone)}++;

	    next;
	}

	# version scanning
	#
	# client [ip]#[port]: query: VERSION.BIND CH TXT 

	if ($msg =~
	    /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\:\s+VERSION.BIND\s+CH\s+TXT/i
	   ) {

	    $vs_total++;
            my $vs_source = 0;

	    ($vs_source) = $msg =~
		/^client\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # vs_source
		\S+\s+query\:\s+
                VERSION\.BIND\s+CH\s+TXT/ix;

	    $vs_source_count{$vs_source}++;

	    next;
	} 

	# version scanning denied
	#
	# client [ip]#[port]: query 'VERSION.BIND/CH' denied

	if ($msg =~
	    /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+query\s+\'VERSION.BIND\/CH\'\s+denied/i
	   ) {

	    $vsd_total++;
            my $vsd_source = 0;

	    ($vsd_source) = $msg =~
		/^client\s+
		(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # vsd_source
		\S+\s+query\s+\
		\'VERSION\.BIND\/CH\'\s+denied/ix;

	    $vsd_source_count{$vsd_source}++;

	    next;
	}

        # broken client queries
        #
        # client [ip]#[port]: no matching view in class 'CLASS[class]'
        # client [ip]#[port]: message class could not be determined

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+matching\s+view\s+in\s+class\s+\'CLASS\d+\'/i
           ) {

            $bcq_total++;
            my ($bcq_source, $bcq_class) = (0, 0);

            ($bcq_source, $bcq_class) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # bcq_source
                \S+\s+
                no\s+matching\s+view\s+in\s+class\s+
                \'CLASS
                (\d+)                                    # bcq_class
                \'/ix;

            $bcq_source_count{$bcq_source}++;
            $bcq_class_count{$bcq_class}++;

            next;
        }

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+message\s+class\s+could\s+not\s+be\s+determined/i
           ) {

            $bcq_total++;
            my ($bcq_source) = (0);

            ($bcq_source) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # bcq_source
                \#\d+\:\s+message\s+class\s+could
                \s+not\s+be\s+determined/ix;

            $bcq_source_count{$bcq_source}++;

            next;
        }

        # quota reached - recursive clients
        #
        # client [ip]#[port]: no more recursive clients: quota reached

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+more\s+recursive\s+clients\:\s+quota\s+reached/i
           ) {

            $qrrc_total++;
            my ($qrrc_source) = (0);

            ($qrrc_source) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # qrrc_source
                \#\d+\:\s+no\s+more\s+recursive
                \s+clients\:\s+quota\s+reached/ix;

            $qrrc_source_count{$qrrc_source}++;

            next;
        }

        # quota reached - TCP clients
        #
        # client [ip]#[port]: no more TCP clients: quota reached

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+no\s+more\s+TCP\s+clients\:\s+quota\s+reached/i
           ) {

            $qrtc_total++;
            my ($qrtc_source) = (0);

            ($qrtc_source) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # qrtc_source
                \#\d+\:\s+no\s+more\s+TCP\s+clients
                \s\:\s+quota\s+reached/ix;

            $qrtc_source_count{$qrtc_source}++;

            next;
        }

        # format error
        #
        # client [ip]#[port]: possible error packet loop, FORMERR dropped

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+possible\s+error\s+packet\s+loop\,\s+FORMERR\s+dropped/i
           ) {

            $fe_total++;
            my ($fe_source) = (0);

            ($fe_source) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})     # fe_source
                \#\d+\:\s+possible\s+error\s+packet
                \s+loop\,\s+FORMERR\s+dropped/ix;

            $fe_source_count{$fe_source}++;

            next;
        }

        # sending notify
        #
        # zone [zone]/IN: sending notifies (serial [serial])

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+sending\s+notifies\s+\(serial\s+\d+\)/i
           ) {

            $sn_total++;
            my ($sn_zone, $sn_serial) = (0, 0);

            ($sn_zone, $sn_serial) = $msg =~
                /^zone\s+
                (\S+)                                  # sn_zone
                \/IN\:\s+sending\s+notifies\s+
                \(serial\s+
                (\d+)                                  # sn_serial
                \)/ix;

            $sn_zone_count{$sn_zone}++;
            $sn_serial_count{$sn_serial}++;

            next;
        }

        # sending notify failed
        #
        # zone [zone]/IN: notify to [ip]#[port]: retries exceeded
        # zone [zone]/IN: notify to [ip]#[port] failed: [description]

        if ($msg =~
            /^zone\s+\S+\/IN\:\s+notify\s+to\s+\d+\.\d+\.\d+\.\d+\#\d+(\s+failed)?\:\s+.*/i
           ) {

            $snf_total++;
            my ($snf_zone, $snf_dst, $snf_desc) = (0, 0, 0);

            ($snf_zone, $snf_dst, $snf_desc) = $msg =~
                /^zone\s+
                (\S+)                                  # snf_zone
                \/IN\:\s+notify\s+to\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})   # snf_dst
                \#\d+.*\:\s+
                (.*)                                   # snf_desc
                /ix;

            $snf_zone_count{$snf_zone}++;
            $snf_dst_count{$snf_dst}++;
            $snf_desc_count{$snf_desc}++;

            next;
        }

        # received notify - not authoritative
        #
        # received notify for zone '[zone]': not authoritative

        if ($msg =~
            /^received\s+notify\s+for\s+zone\s+\'\S+\'\:\s+not\s+authoritative/i
           ) {
            $rnna_total++;
            my ($rnna_zone) = (0);

            ($rnna_zone) = $msg =~
                /^received\s+notify\s+for\s+zone\s+\'
                (\S+)                                    # rnna_zone
                \'\:\s+not\s+authoritative/ix;

            $rnna_zone_count{$rnna_zone}++;

            next;
        }

        # error sending response
        #
        # client [ip]#[port]: error sending response: [description]

        if ($msg =~
            /^client\s+\d+\.\d+\.\d+\.\d+\#\d+\:\s+error\s+sending\s+response\:\s+.*/i
           ) {

            $esr_total++;
            my ($esr_dst, $esr_desc) = (0, 0);

            ($esr_dst, $esr_desc) = $msg =~
                /^client\s+
                (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})        # esr_dst
                \#\d+\:\s+error\s+sending\s+response\:\s+
                (.*)                                        # esr_desc
                /ix;

            $esr_dst_count{$esr_dst}++;
            $esr_desc_count{$esr_desc}++;

            next;
        }

        # insecure updates
        #
        # zone '[zone]' allows updates by IP address, which is insecure

        if ($msg =~
            /^zone\s+\'\S+\'\s+allows\s+updates\s+by\s+IP\s+address\,\s+which\s+is\s+insecure/i
           ) {

            $iu_total++;
            my ($iu_zone) = (0);

            ($iu_zone) = $msg =~
                /^zone\s+\'
                (\S+)                                     # iu_zone
                \'\s+allows\s+updates\s+by\s+IP\s+
                address\,\s+which\s+is\s+insecure/ix;

            $iu_zone_count{$iu_zone}++;

            next;
        }
 
	# other (unknown log messages) - DEFAULT CASE

	$other_total++;

	if ($DEBUG) { print "[DEBUG] UNKNOWN LOG MESSAGE: $log\n"; }

    } # END SWITCH

} # END WHILE

#
# generate output
#

# If there are unknown log messages and DEBUG is disabled, issue warning
if ($other_total && !$DEBUG) {
    print "WARNING: unknown log messages detected, enable DEBUG to view.\n\n";
}

print "-----------------------------------\n";
print " ISC BIND named log summary report \n";
print "-----------------------------------\n";
print "Total log messages: $log_total\n";
if ($s_total) { print "Total server status messages: $s_total\n"; }
if ($slc_total) { print "Total server config loads: $slc_total\n"; }
if ($snif_total) { print "Total IPv6 interfaces not found: $snif_total\n"; }
if ($sr_total) { print "Total server runs: $sr_total\n"; }
if ($se_total) { print "Total server exits: $se_total\n"; }
if ($ssd_total) { print "Total server shut downs: $ssd_total\n"; }
if ($sscc_total) { print "Total server command channel stops: $sscc_total\n"; }
if ($snll_total) { print "Total server run stops: $snll_total\n"; }
if ($ic_total) { print "Total invalid commands: $ic_total\n"; }
if ($jfc_total) { print "Total journal file creations: $jfc_total\n"; }
if ($cq_total) { print "Total client queries: $cq_total\n"; }
if ($cqd_total){  print "Total client denies: $cqd_total\n"; }
if ($cqcd_total) { print "Total client cache denies: $cqcd_total\n"; }
if ($zl_total) { print "Total zone loads: $zl_total\n"; }
if ($sf_total) { print "Total server fetches: $sf_total\n"; }
if ($zts_total) { print "Total zone transfers started: $zts_total\n"; }
if ($ztr_total) { print "Total zone transfers received: $ztr_total\n"; }
if ($ztf_total) { print "Total zone transfer failures: $ztf_total\n"; }
if ($ztd_total) { print "Total zone transfer denies: $ztd_total\n"; }
if ($bzt_total) { print "Total bad zone transfers: $bzt_total\n"; }
if ($zrfto_total) { print "Total zone refresh time outs: $zrfto_total\n"; }
if ($zrrle_total) { print "Total zone refresh retry exceeds: $zrrle_total\n"; }
if ($zu_total) { print "Total zone update messages: $zu_total\n"; }
if ($zuf_total) { print "Total zone update failure messages: $zuf_total\n"; }
if ($ls_total) { print "Total lame server reports: $ls_total\n"; }
if ($vs_total) { print "Total version scans: $vs_total\n"; }
if ($vsd_total) { print "Total version scans denied: $vsd_total\n"; }
if ($bcq_total) { print "Total broken client queries: $bcq_total\n"; }
if ($qrrc_total || $qrtc_total) { print "Total quota reached attempts: "
                                   . ($qrrc_total + $qrtc_total) . "\n"; }
if ($fe_total) { print "Total format errors: $fe_total\n"; }
if ($sn_total) { print "Total notifies sent: $sn_total\n"; }
if ($snf_total) { print "Total notify send failures: $snf_total\n"; }
if ($rnna_total) { print "Total receive notify not auth errs: $rnna_total\n"; }
if ($esr_total) { print "Total error sending responses: $esr_total\n"; }
if ($other_total) { print "Total other (unknown) messages: $other_total\n"; }

## BEGIN $TOPx reports below  ###

# slc_file_count - server load configuration file count
if ($slc_total) {
    print "\nTop $TOPx server config loads\n";
    print "Count\tFile\n"; 
    my $counter = 1;
    for my $item (sort{$slc_file_count{$b} -
                       $slc_file_count{$a}}
                  keys %slc_file_count) {

        print "$slc_file_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# sscc_ip_count - server stop command channel ip count
if ($sscc_total) {
    print "\nTop $TOPx server command channel IP stops\n";
    print "Count\tIP\n"; 
    my $counter = 1;
    for my $item (sort{$sscc_ip_count{$b} -
                       $sscc_ip_count{$a}}
                  keys %sscc_ip_count) {

        print "$sscc_ip_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# sloi_int_count - server listening on interface interface count
if ($sloi_total) {
    print "\nTop $TOPx server interfaces listening\n";
    print "Count\tInterface\n";
    my $counter = 1;
    for my $item (sort{$sloi_int_count{$b} -
                       $sloi_int_count{$a}}
                  keys %sloi_int_count) {

        print "$sloi_int_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# sloi_ip_count - server listening on interface ip count
if ($sloi_total) {
    print "\nTop $TOPx server IPs listening\n";
    print "Count\tIP\n";
    my $counter = 1;
    for my $item (sort{$sloi_ip_count{$b} -
                       $sloi_ip_count{$a}}
                  keys %sloi_ip_count) {

        print "$sloi_ip_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# snll_ip_count - server no longer running ip count
if ($snll_total) {
    print "\nTop $TOPx server run stop\n";
    print "Count\tIP\n";
    my $counter = 1;
    for my $item (sort{$snll_ip_count{$b} -
                       $snll_ip_count{$a}}
                  keys %snll_ip_count) {

        print "$snll_ip_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# ic_source_count - invalid command source count
if ($ic_total) {
    print "\nTop $TOPx IPs sourcing invalid commands\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$ic_source_count{$b} -
                       $ic_source_count{$a}}
                  keys %ic_source_count) {

        # don't bother trying to resolve a loopback IP
        if ($RESOLVE && $item !~ /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
            print "$ic_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$ic_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# ic_desc_count - invalid command description count
if ($ic_total) {
    print "\nTop $TOPx invalid command responses\n";
    print "Count\tResponse\n";
    my $counter = 1;
    for my $item (sort{$ic_desc_count{$b} -
                       $ic_desc_count{$a}}
                  keys %ic_desc_count) {

        print "$ic_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# jfc_file_count - journal file creation file count
if ($jfc_total) {
    print "\nTop $TOPx journal files created\n";
    print "Count\tFile\n";
    my $counter = 1;
    for my $item (sort{$jfc_file_count{$b} -
                       $jfc_file_count{$a}}
                  keys %jfc_file_count) {

        print "$jfc_file_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# cq_source_count - client query source count
if ($cq_total) {
    print "\nTop $TOPx IP clients\n";
    print "Count\tSource ";
        if ($PRIVACY) { print "(/24 subnet)\n"; }
        else { print "(/32 host)\n"; }
    my $counter = 1;
    for my $item (sort{$cq_source_count{$b} -
                       $cq_source_count{$a}}
                  keys %cq_source_count) {

        if (!$PRIVACY && $RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$cq_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$cq_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# cq_data_count - client query data count
if ($cq_total) {
    print "\nTop $TOPx Queries\n";
    print "Count\tQuery\n";
    my $counter = 1;
    for my $item (sort{$cq_data_count{$b} -
                       $cq_data_count{$a}}
                  keys %cq_data_count) {
 
	print "$cq_data_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# cq_type_count - client query type count
if ($cq_total) {
    print "\nTop $TOPx Query Types\n";
    print "Count\tType\n";
    my $counter = 1;
    for my $item (sort{$cq_type_count{$b} -
                       $cq_type_count{$a}}
                  keys %cq_type_count) {

	print "$cq_type_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# cqd_data_count - client query denied data count
if ($cqd_total) {
    print "\nTop $TOPx queries denied\n";
    print "Count\tQuery\n";
    my $counter = 1;
    for my $item (sort{$cqd_data_count{$b} -
                       $cqd_data_count{$a}}
                  keys %cqd_data_count) {

        print "$cqd_data_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# cqcd_source_count - client query cache denied source count
if ($cqcd_total) {
    print "\nTop $TOPx IP client query cache denies\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$cqcd_source_count{$b} -
                       $cqcd_source_count{$a}}
                  keys %cqcd_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$cqcd_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$cqcd_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# zl_zone_count - zone load zone count
if ($zl_total) {
    print "\nTop $TOPx zones loaded\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zl_zone_count{$b} -
                       $zl_zone_count{$a}}
                  keys %zl_zone_count) {

        print "$zl_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# sf_target_count - server fetch target count
if ($sf_total) {
    print "\nTop $TOPx fetches\n";
    print "Count\tTarget\n";
    my $counter = 1;
    for my $item (sort{$sf_target_count{$b} -
                       $sf_target_count{$a}}
                  keys %sf_target_count) {

	print "$sf_target_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# sf_type_count - server fetch type count
if ($sf_total) {
    print "\nTop $TOPx fetch types\n";
    print "Count\tType\n";
    my $counter = 1;
    for my $item (sort{$sf_type_count{$b} -
                       $sf_type_count{$a}}
                  keys %sf_type_count) {

	print "$sf_type_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# zt_zone_count - zone transferred zone count
if ($zt_total) {
    print "\nTop $TOPx zones transferred\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zt_zone_count{$b} -
                       $zt_zone_count{$a}}
                  keys %zt_zone_count) {

	print "$zt_zone_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# zt_serial_count - zone transferred serial count
if ($zt_total) {
    print "\nTop $TOPx zone transferred serials\n";
    print "Count\tSerial\n";
    my $counter = 1;
    for my $item (sort{$zt_serial_count{$b} -
                       $zt_serial_count{$a}}
                  keys %zt_serial_count) {

	print "$zt_serial_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# zts_zone_count - zone transfer started zone count
if ($zts_total) {
    print "\nTop $TOPx zone transfers started\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zts_zone_count{$b} -
                       $zts_zone_count{$a}}
                  keys %zts_zone_count) {

	print "$zts_zone_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# zts_target_count - zone transfer started target count
if ($zts_total) {
    print "\nTop $TOPx zone transfer started targets\n";
    print "Count\tTarget\n";
    my $counter = 1;
    for my $item (sort{$zts_target_count{$b} -
                       $zts_target_count{$a}}
                  keys %zts_target_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$zts_target_count{$item}\t$item\t$name\n";
        }
        else {
            print "$zts_target_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# zts_type_count - zone transfer started type count
if ($zts_total) {
    print "\nTop $TOPx zone transfers started types\n";
    print "Count\tType\n";
    my $counter = 1;
    for my $item (sort{$zts_type_count{$b} -
                       $zts_type_count{$a}}
                  keys %zts_type_count) {

	print "$zts_type_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ztr_zone_count - zone transfer received zone count
if ($ztr_total) {
    print "\nTop $TOPx zone transfers received\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$ztr_zone_count{$b} -
                       $ztr_zone_count{$a}}
                  keys %ztr_zone_count) {

	print "$ztr_zone_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ztr_source_count - zone transfer received source count
if ($ztr_total) {
    print "\nTop $TOPx zone transfer receive sources\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$ztr_source_count{$b} -
                       $ztr_source_count{$a}}
                  keys %ztr_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$ztr_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$ztr_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# ztf_zone_count - zone transfer failure zone count
if ($ztf_total) {
    print "\nTop $TOPx zones transferred unsuccessfully\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$ztf_zone_count{$b} -
                       $ztf_zone_count{$a}}
                  keys %ztf_zone_count) {

	print "$ztf_zone_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ztf_source_count - zone transfer failure source count
if ($ztf_total) {
    print "\nTop $TOPx sources of failed zone transfers\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$ztf_source_count{$b} -
                       $ztf_source_count{$a}}
                  keys %ztf_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$ztf_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$ztf_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# ztf_error_count - zone transfer failure error count
if ($ztf_total) {
    print "\nTop $TOPx zone transfer errors\n";
    print "Count\tError\n";
    my $counter = 1;
    for my $item (sort{$ztf_error_count{$b} -
                       $ztf_error_count{$a}}
                  keys %ztf_error_count) {

	print "$ztf_error_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ztd_source_count - zone transfer denied source count
if ($ztd_total) {
    print "\nTop $TOPx zone transfer clients denied\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$ztd_source_count{$b} -
                       $ztd_source_count{$a}}
                  keys %ztd_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$ztd_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$ztd_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# ztd_zone_count - zone transfer denied zone count
if ($ztd_total) {
    print "\nTop $TOPx zone transfer zones denied\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$ztd_zone_count{$b} -
                       $ztd_zone_count{$a}}
                  keys %ztd_zone_count) {

        print "$ztd_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# bzt_source_count - bad zone transfer source count
if ($bzt_total) {
    print "\nTop $TOPx bad zone transfer sources\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$bzt_source_count{$b} -
                       $bzt_source_count{$a}}
                  keys %bzt_source_count) {

        print "$bzt_source_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# bzt_zone_count - bad zone transfer zone count
if ($bzt_total) {
    print "\nTop $TOPx bad zones attempted transfer\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$bzt_zone_count{$b} -
                       $bzt_zone_count{$a}}
                  keys %bzt_zone_count) {

        print "$bzt_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# bzt_desc_count - bad zone transfer description count
if ($bzt_total) {
    print "\nTop $TOPx bad zone attempt reasons\n";
    print "Count\tReasons\n";
    my $counter = 1;
    for my $item (sort{$bzt_desc_count{$b} -
                       $bzt_desc_count{$a}}
                  keys %bzt_desc_count) {

        print "$bzt_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zrfto_zone_count - zone refresh failure timed out zone count
if ($zrfto_total) {
    print "\nTop $TOPx refresh failed, timed out zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zrfto_zone_count{$b} -
                       $zrfto_zone_count{$a}}
                  keys %zrfto_zone_count) {

        print "$zrfto_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zrfto_master_count - zone refresh failure timed out master count
if ($zrfto_total) {
    print "\nTop $TOPx refresh failed, timed out masters\n";
    print "Count\tMaster\n";
    my $counter = 1;
    for my $item (sort{$zrfto_master_count{$b} -
                       $zrfto_master_count{$a}}
                  keys %zrfto_master_count) {

        print "$zrfto_master_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zrrle_zone_count - zone refresh retry limit exceeded zone count
if ($zrrle_total) {
    print "\nTop $TOPx refresh retry limit exceeded zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zrrle_zone_count{$b} -
                       $zrrle_zone_count{$a}}
                  keys %zrrle_zone_count) {

        print "$zrrle_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zrrle_master_count - zone refresh retry limit exceeded master count
if ($zrrle_total) {
    print "\nTop $TOPx refresh retry limit exceeded masters\n";
    print "Count\tMaster\n";
    my $counter = 1;
    for my $item (sort{$zrrle_master_count{$b} -
                       $zrrle_master_count{$a}}
                  keys %zrrle_master_count) {

        print "$zrrle_master_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zu_source_count - zone update source count
if ($zu_total) {
    print "\nTop $TOPx zone update sources\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$zu_source_count{$b} -
                       $zu_source_count{$a}}
                  keys %zu_source_count) {

        print "$zu_source_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zu_zone_count - zone update zone count
if ($zu_total) {
    print "\nTop $TOPx zones in zone update messages\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zu_zone_count{$b} -
                       $zu_zone_count{$a}}
                  keys %zu_zone_count) {

        print "$zu_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zu_desc_count - zone update description count
if ($zu_total) {
    print "\nTop $TOPx zone update message types\n";
    print "Count\tMessage\n";
    my $counter = 1;
    for my $item (sort{$zu_desc_count{$b} -
                       $zu_desc_count{$a}}
                  keys %zu_desc_count) {

        print "$zu_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zuf_source_count - zone update failure source count
if ($zuf_total) {
    print "\nTop $TOPx zone update failure sources\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$zuf_source_count{$b} -
                       $zuf_source_count{$a}}
                  keys %zuf_source_count) {

        print "$zuf_source_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zuf_zone_count - zone update failure zone count
if ($zuf_total) {
    print "\nTop $TOPx zone update failure zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$zuf_zone_count{$b} -
                       $zuf_zone_count{$a}}
                  keys %zuf_zone_count) {

        print "$zuf_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# zuf_desc_count - zone update failure description count
if ($zuf_total) {
    print "\nTop $TOPx zone update failure reasons\n";
    print "Count\tReasons\n";
    my $counter = 1;
    for my $item (sort{$zuf_desc_count{$b} -
                       $zuf_desc_count{$a}}
                  keys %zuf_desc_count) {

        print "$zuf_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# ls_zone_count - lame server zone count
if ($ls_total) {
    print "\nTop $TOPx lame zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$ls_zone_count{$b} -
                       $ls_zone_count{$a}}
                  keys %ls_zone_count) {

	print "$ls_zone_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ls_server_count - lame server server count
if ($ls_total) {
    print "\nTop $TOPx lame servers\n";
    print "Count\tServer\n";
    my $counter = 1;
    for my $item (sort{$ls_server_count{$b} -
                       $ls_server_count{$a}}
                  keys %ls_server_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$ls_server_count{$item}\t$item\t$name\n";
        }
        else {
            print "$ls_server_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# ls_record_count - lame server record count
if ($ls_total) {
    print "\nTop $TOPx lame records\n";
    print "Count\tRecord\n";
    my $counter = 1;
    for my $item (sort{$ls_record_count{$b} -
                       $ls_record_count{$a}}
                  keys %ls_record_count) {

	print "$ls_record_count{$item}\t$item\n";
	last if ++$counter > $TOPx;
    }
}

# ls_servzone_count - lame server server/zone tuple count
if ($ls_total) {
    print "\nTop $TOPx lame server/zone tuples\n";
    print "Count\tServer [(name)] / Zone\n";
    my $counter = 1;
    for my $item (sort{$ls_servzone_count{$b} -
                       $ls_servzone_count{$a}}
                  keys %ls_servzone_count) {

        print "$ls_servzone_count{$item}\t";
        my $ip = "";
        my $zone = "";
        ($ip, $zone) = split( /\t/, $item, 2);
        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($ip), AF_INET)
                  or $name = "[lookup failed]";
            print "$ip ($name) / $zone\n";
        }
        else {
            print "$ip / $zone\n";
        }
        last if ++$counter > $TOPx;
    }
}

# vs_source_count - version scanning source count
if ($vs_total) {
    print "\nTop $TOPx version scanning sources\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$vs_source_count{$b} -
                       $vs_source_count{$a}}
                  keys %vs_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$vs_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$vs_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    } 
}

# vsd_source_count - version scanning denied source count
if ($vsd_total) {
    print "\nTop $TOPx version scanning denies\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$vsd_source_count{$b} -
                       $vsd_source_count{$a}}
                  keys %vsd_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                  or $name = "[lookup failed]";
	    print "$vsd_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$vsd_source_count{$item}\t$item\n";
        }
	last if ++$counter > $TOPx;
    }
}

# bcq_source_count - broken client query source count
if ($bcq_total) {
    print "\nTop $TOPx broken clients\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$bcq_source_count{$b} -
                       $bcq_source_count{$a}}
                  keys %bcq_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$bcq_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$bcq_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# bcq_class_count - broken client query class count
if ($bcq_total) {
    print "\nTop $TOPx invalid class views\n";
    print "Count\tClass\n";
    my $counter = 1;
    for my $item (sort{$bcq_class_count{$b} -
                       $bcq_class_count{$a}}
                  keys %bcq_class_count) {

        print "$bcq_class_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# qrrc_source_count - quota reached recursive client source count
if ($qrrc_total) {
    print "\nTop $TOPx quota reached recursive clients\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$qrrc_source_count{$b} -
                       $qrrc_source_count{$a}}
                  keys %qrrc_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$qrrc_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$qrrc_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# qrtc_source_count - quota reached TCP client source count
if ($qrtc_total) {
    print "\nTop $TOPx quota reached TCP clients\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$qrtc_source_count{$b} -
                       $qrtc_source_count{$a}}
                  keys %qrtc_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$qrtc_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$qrtc_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# fe_source_count - format error source count
if ($fe_total) {
    print "\nTop $TOPx format error clients\n";
    print "Count\tSource\n";
    my $counter = 1;
    for my $item (sort{$fe_source_count{$b} -
                       $fe_source_count{$a}}
                  keys %fe_source_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$fe_source_count{$item}\t$item\t$name\n";
        }
        else {
            print "$fe_source_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# sn_zone_count - send notify zone count
if ($sn_total) {
    print "\nTop $TOPx zones sent notifies\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$sn_zone_count{$b} -
                       $sn_zone_count{$a}}
                  keys %sn_zone_count) {

        print "$sn_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# sn_serial_count - send notify serial count
if ($sn_total) {
    print "\nTop $TOPx serials in notifies sent\n";
    print "Count\tSerial\n";
    my $counter = 1;
    for my $item (sort{$sn_serial_count{$b} -
                       $sn_serial_count{$a}}
                  keys %sn_serial_count) {

        print "$sn_serial_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# snf_zone_count - send notify failure zone count
if ($snf_total) {
    print "\nTop $TOPx notify failure zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$snf_zone_count{$b} -
                       $snf_zone_count{$a}}
                  keys %snf_zone_count) {

        print "$snf_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# snf_dst_count - send notify failure destination count
if ($snf_total) {
    print "\nTop $TOPx notify failure destinations\n";
    print "Count\tDestination\n";
    my $counter = 1;
    for my $item (sort{$snf_dst_count{$b} -
                       $snf_dst_count{$a}}
                  keys %snf_dst_count) {

        print "$snf_dst_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# snf_desc_count - send notify failure description count
if ($snf_total) {
    print "\nTop $TOPx notify failure reasons\n";
    print "Count\tReason\n";
    my $counter = 1;
    for my $item (sort{$snf_desc_count{$b} -
                       $snf_desc_count{$a}}
                  keys %snf_desc_count) {

        print "$snf_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# rnna_zone_count - receive notify not authoritative zone count
if ($rnna_total) {
    print "\nTop $TOPx receive notify not authoritative errors\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$rnna_zone_count{$b} -
                       $rnna_zone_count{$a}}
                  keys %rnna_zone_count) {

        print "$rnna_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# esr_dst_count - error sending response destination count
if ($esr_total) {
    print "\nTop $TOPx error sending responses\n";
    print "Count\tDestination\n";
    my $counter = 1;
    for my $item (sort{$esr_dst_count{$b} -
                       $esr_dst_count{$a}}
                  keys %esr_dst_count) {

        if ($RESOLVE) {
            my $name = "";
            $name = gethostbyaddr(inet_aton($item), AF_INET)
                or $name = "[lookup failed]";
            print "$esr_dst_count{$item}\t$item\t$name\n";
        }
        else {
            print "$esr_dst_count{$item}\t$item\n";
        }
        last if ++$counter > $TOPx;
    }
}

# esr_desc_count - error sending response description
if ($esr_total) {
    print "\nTop $TOPx error sending response reasons\n";
    print "Count\tReason\n";
    my $counter = 1;
    for my $item (sort{$esr_desc_count{$b} -
                       $esr_desc_count{$a}}
                  keys %esr_desc_count) {

        print "$esr_desc_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# iu_zone_count - insecure update zone count
if ($iu_total) {
    print "\nTop $TOPx insecure update zones\n";
    print "Count\tZone\n";
    my $counter = 1;
    for my $item (sort{$iu_zone_count{$b} -
                       $iu_zone_count{$a}}
                  keys %iu_zone_count) {

        print "$iu_zone_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# category_count - total categories in log message detail
if (%category_count) {
    print "\nTop $TOPx categories of log messages\n";
    print "Count\tCategory\n";
    my $counter = 1;
    for my $item (sort{$category_count{$b} -
                       $category_count{$a}}
                  keys %category_count) {

        print "$category_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

# severity_count - total categories in log message detail
if (%severity_count) {
    print "\nTop $TOPx severities of log messages\n";
    print "Count\tSeverity\n";
    my $counter = 1;
    for my $item (sort{$severity_count{$b} -
                       $severity_count{$a}}
                  keys %severity_count) {

        print "$severity_count{$item}\t$item\n";
        last if ++$counter > $TOPx;
    }
}

## END $TOPx reports  ###

# logs_per_hour
if (%logs_per_hour && $log_total) {
    print "\nHourly log summary\n";
    print "Hour\tLogs \(count\/percent\)\n";
    my $counter = 0;
    for ($counter = 0; $counter < 24; $counter++) {
        print "$counter\t";

        # if no logs this hour, print (0/0.00%) and loop to next
        if(!$logs_per_hour{$counter}) { print "\(0\/0.00\%\)\n"; next; }

        # bargraph limited to 50 chars
        # helps ensure output fits on a single lin w/o wrap
        #
        my $bargraph = 0;
        while ($bargraph < 50) {

	    sub round {
		my($number) = shift;
		return int($number + .5 * ($number <=> 0));
	    }

            # stop bargraph printing if % of hourly logs < 1%
            #
            last if ($logs_per_hour{$counter} / $log_total) * 100 < 1 ||
                    ++$bargraph >

                        # percentage of logs = 100% / 2
                        #
                        round($logs_per_hour{$counter} / $log_total * 50);

            print "#";  # grow bargraph by one mark
        }

        printf "\(%d\/%.2f%%\)\n", $logs_per_hour{$counter},
              ($logs_per_hour{$counter} / $log_total) * 100;
    }
}

if ($DEBUG) {
    my $current_dir = getcwd;
    my $DEBUG_end_time = localtime;
    print "\n[DEBUG] Script (approximate) start time: $DEBUG_start_time\n";
    print "[DEBUG] Script (approximate) stop time: $DEBUG_end_time\n";
    print "[DEBUG] Total log messages: $log_total\n";
    print "[DEBUG] Resolution: ";
        if ($RESOLVE) { print "ENABLED\n"; } else { print "DISABLED\n"; }
    print "[DEBUG] Privacy: ";
        if ($PRIVACY) { print "ENABLED\n"; } else { print "DISABLED\n"; }
    print "[DEBUG] Rows per report: $TOPx\n";
    print "[DEBUG] Working directory: $current_dir\n";
    print "[DEBUG] Command line: $0";
        if (@arguments) { print " @arguments\n";} else { print "\n"; }
}

### EOF
