]> granicus.if.org Git - pgbadger/commitdiff
Add -w option to only report errors
authorDarold <gilles@darold.net>
Sat, 9 Jun 2012 11:57:33 +0000 (13:57 +0200)
committerDarold <gilles@darold.net>
Sat, 9 Jun 2012 11:57:33 +0000 (13:57 +0200)
README
doc/pgBadger.pod
pgbadger

diff --git a/README b/README
index 10c2bac1e925204b75f77c9a37ad82e4974b5866..ab498267af4d7c6fe02ce8c987104f26e23af94c 100644 (file)
--- a/README
+++ b/README
@@ -40,6 +40,7 @@ SYNOPSIS
         -p | --progress        : show a progress bar, quiet mode is enabled with this option.
         -v | --version         : show current version
         --pie-limit num        : do not show pie data lower that num%, show a sum of them instead.
+        -w | -watch-mode       : only report errors just like logwatch could do.
 
     Examples:
 
@@ -47,6 +48,13 @@ SYNOPSIS
             pgbadger -p -g /var/log/postgres.log.2.gz /var/log/postgres.log.1.gz /var/log/postgres.log
             pgbadger -p -g `ls /var/log/postgresql/postgresql-2012-05-*`
 
+    Reporting errors every week by cron job:
+
+        30 23 * * 1 /usr/bin/pgbadger -q -w /var/log/postgresql.log -o /var/reports/pg_errors.html
+
+    this suppose that your log file and HTML report are also rotated every
+    weeks.
+
 DESCRIPTION
     pgBadger is a PostgreSQL log analyzer build for speed with fully
     detailed reports from your PostgreSQL log file. It's a single and small
index 7afbb4a540543e11123fa6505e4d23bca0e5c5a6..64fc56789c85bbaa71599f3b3faa744b4f101dc9 100644 (file)
@@ -42,6 +42,7 @@ Options:
     -p | --progress        : show a progress bar, quiet mode is enabled with this option.
     -v | --version         : show current version
     --pie-limit num        : do not show pie data lower that num%, show a sum of them instead.
+    -w | -watch-mode       : only report errors just like logwatch could do.
 
 Examples:
 
@@ -49,6 +50,11 @@ Examples:
         pgbadger -p -g /var/log/postgres.log.2.gz /var/log/postgres.log.1.gz /var/log/postgres.log
         pgbadger -p -g `ls /var/log/postgresql/postgresql-2012-05-*`
 
+Reporting errors every week by cron job:
+
+    30 23 * * 1 /usr/bin/pgbadger -q -w /var/log/postgresql.log -o /var/reports/pg_errors.html
+
+this suppose that your log file and HTML report are also rotated every weeks.
 
 =head1 DESCRIPTION
 
index 5685d1e328708f182070632487fb249302a0d1a9..3c2ad9adb5617943d338853727347756fddc03b4 100755 (executable)
--- a/pgbadger
+++ b/pgbadger
@@ -61,6 +61,7 @@ my $regex_prefix_dbname = '';
 my $regex_prefix_dbuser = '';
 my $quiet = 0;
 my $progress = 0;
+my $error_only = 0;
 
 my $NUMPROGRESS = 10000;
 my @DIMENSIONS = (800,300);
@@ -97,7 +98,8 @@ my $result = GetOptions (
        "q|quiet!"      => \$quiet,
        "p|progress!"   => \$progress,
        "pie-limit=i"   => \$pie_percentage_limit,
-       "image-format=s"   => \$img_format,
+       "image-format=s"=> \$img_format,
+       "w|watch-mode!" => \$error_only,
 );
 
 if ($ver) {
@@ -432,9 +434,17 @@ if (not defined $fh) {
        die "FATAL: can't write to $outfile, $!\n";
 }
 if ( ($extension eq 'text') || ($extension eq 'txt') ) {
-       &dump_as_text();
+       if ($error_only) {
+               &dump_error_as_text();
+       } else {
+               &dump_as_text();
+       }
 } else {
-       &dump_as_html();
+       if ($error_only) {
+               &dump_error_as_html();
+       } else {
+               &dump_as_html();
+       }
 }
 $fh->close;
 
@@ -462,7 +472,7 @@ Options:
                             with the .gz extension. Note that this option is
                             DEPRECATED, set logfile as a command line argument
                             instead.
-    -f | --format logtype  : the value can be: syslog, stderr or csv. Default: stderr
+    -f | --format logtype  : possible values: syslog,stderr,csv. Default: stderr
     -o | --outfile filename: define the filename for the output. Default depends
                             of the output format: out.html or out.txt. To dump
                             output to stdout use - as filename.
@@ -478,15 +488,25 @@ Options:
     -g | --graph           : generate graphs using the Flotr2 javascript library
     -b | --begin datetime  : start date/time for the data to be parsed in log.
     -e | --end datetime    : end date/time for the data to be parsed in log.
-    -q | --quiet           : disable output to stderr and don't print debug informations.
-    -p | --progress        : show a progress bar, quiet mode is enabled with this option.
-    --pie-limit num        : do not show pie data lower that num%, show a sum of them instead.
+    -q | --quiet           : don't print anything to stdout.
+    -p | --progress        : show a progress bar, quiet mode is automaticaly
+                            enabled with this option.
+    --pie-limit num        : pie data lower than num% will show a sum instead.
+    -w | -watch-mode       : only report errors just like logwatch could do.
 
 Examples:
 
        pgbadger -p -g /var/log/postgresql.log
-       pgbadger -p -g /var/log/postgres.log.2.gz /var/log/postgres.log.1.gz /var/log/postgres.log
+       pgbadger -p -g /var/log/postgres.log.2.gz /var/log/postgres.log.1.gz \
+                      /var/log/postgres.log
        pgbadger -p -g `ls /var/log/postgresql/postgresql-2012-05-*`
+
+Reporting errors every week by cron job:
+
+    30 23 * * 1 /usr/bin/pgbadger -q -w /var/log/postgresql.log -o /var/reports/pg_errors.html
+
+this suppose that your log file and HTML report are also rotated every weeks.
+
 };
 
        exit 0;
@@ -757,6 +777,41 @@ Report not supported by text format
 
 }
 
+sub dump_error_as_text
+{
+
+       # Global informations
+       my $curdate = localtime(time);
+       my $fmt_nlines = &comma_numbers($nlines);
+       my $total_time = timestr($td);
+       $total_time =~ s/^([\.0-9]+) wallclock.*/$1/;
+       $total_time = &convert_time($total_time*1000);
+       my $logfile_str = join(',', @log_files);
+       print $fh qq{
+
+- Global informations --------------------------------------------------
+
+Generated on $curdate
+Log file: $logfile_str
+Parsed $fmt_nlines log entries in $total_time
+Log start from $first_log_date to $last_log_date
+};
+
+       print $fh "\n- Most frequent errors (N) ---------------------------------------------\n\n";
+       my $idx = 1;
+       foreach my $k (sort {$error_info{$b}{count} <=> $error_info{$a}{count}} keys %error_info) {
+               next if (!$error_info{$k}{count});
+               last if ($idx > $top);
+               print $fh "$idx) " . &comma_numbers($error_info{$k}{count}) . " - $k\n";
+               print $fh "--\n";
+               $idx++;
+       }
+       print $fh "\n\n";
+       print $fh "Report generated by <a href=\"https://github.com/dalibo/pgbadger\">PgBadger</a> $VERSION.\n";
+
+}
+
+
 sub html_header
 {
        my $date = localtime(time);
@@ -975,56 +1030,57 @@ function toggle(idButton, idDiv, label) {
 /* ]]> */
 </script>
 };
-if ($JQGRAPH) {
-       my @jslib = <DATA>;
-       print $fh <<EOF;
+       if ($JQGRAPH) {
+               my @jslib = <DATA>;
+               print $fh <<EOF;
 @jslib
 EOF
-}
+       }
        print $fh qq{
 </head>
 <body>
 <div id="content">
 
 <h1 id="top">PgBadger</h1>
-
+};
+       if (!$error_only) {
+               print $fh qq{
 <div class="menu">
 <a href="#OverallStatsReport">Overall statistics</a> |
 <a href="#HourlyStatsReport">Hourly statistics</a> |
 <a href="#QueriesByTypeReport">Queries by type</a> |
 };
-print $fh qq{
+               print $fh qq{
 <a href="#SlowestQueriesReport">Slowest queries</a> |
 <a href="#NormalizedQueriesMostTimeReport">Queries that took up the most time (N)</a> |
 <a href="#NormalizedQueriesMostFrequentReport">Most frequent queries (N)</a> |
 <a href="#NormalizedQueriesSlowestAverageReport">Slowest queries (N)</a><br />
 <a href="#NormalizedErrorsMostFrequentReport">Most frequent errors (N)</a> |
 };
-if (scalar keys %lock_info > 0) {
-       print $fh qq{<a href="#LocksByTypeReport">Locks by type</a> |};
-}
-if (exists $session_info{database}) {
-       print $fh qq{<a href="#SessionsDatabaseReport">Sessions per database</a> |};
-}
-if (exists $session_info{user}) {
-       print $fh qq{<a href="#SessionsUserReport">Sessions per user</a> |};
-}
-if (exists $session_info{host}) {
-       print $fh qq{<a href="#SessionsHostReport">Sessions per host</a> |};
-}
-if (exists $connection_info{database}) {
-       print $fh qq{<a href="#ConnectionsDatabaseReport">Connections per database</a> |};
-}
-if (exists $connection_info{user}) {
-       print $fh qq{<a href="#ConnectionsUserReport">Connections per user</a> |};
-}
-if (exists $connection_info{host}) {
-       print $fh qq{<a href="#ConnectionsHostReport">Connections per host</a> |};
-}
-print $fh qq{
-</div>
-<p>Normalized reports are marked with a "(N)".</p>
-};
+               if (scalar keys %lock_info > 0) {
+                       print $fh qq{<a href="#LocksByTypeReport">Locks by type</a> |};
+               }
+               if (exists $session_info{database}) {
+                       print $fh qq{<a href="#SessionsDatabaseReport">Sessions per database</a> |};
+               }
+               if (exists $session_info{user}) {
+                       print $fh qq{<a href="#SessionsUserReport">Sessions per user</a> |};
+               }
+               if (exists $session_info{host}) {
+                       print $fh qq{<a href="#SessionsHostReport">Sessions per host</a> |};
+               }
+               if (exists $connection_info{database}) {
+                       print $fh qq{<a href="#ConnectionsDatabaseReport">Connections per database</a> |};
+               }
+               if (exists $connection_info{user}) {
+                       print $fh qq{<a href="#ConnectionsUserReport">Connections per user</a> |};
+               }
+               if (exists $connection_info{host}) {
+                       print $fh qq{<a href="#ConnectionsHostReport">Connections per host</a> |};
+               }
+               print $fh "</div>\n";
+       }
+       print $fh "<p>Normalized reports are marked with a \"(N)\".</p>\n";
 
 }
 
@@ -1037,40 +1093,46 @@ sub html_footer
                Report generated by <a href="https://github.com/dalibo/pgbadger">PgBadger</a> $VERSION.
        </div>
 </div>
+};
+       if (!$error_only) {
+               print $fh qq{
 <div id="littleToc">
        <div id="littleTocContent">
 
                <ul>
                        <li><a href="#top">^ Back to top</a></li><li><a href="#OverallStatsReport">Overall statistics</a></li><li><a href="#HourlyStatsReport">Hourly statistics</a></li><li><a href="#QueriesByTypeReport">Queries by type</a></li>
 };
-if (scalar keys %lock_info > 0) {
-       print $fh qq{<li><a href="#LocksByTypeReport">Locks by type</a></li>};
-}
-if (exists $session_info{database}) {
-       print $fh qq{<li><a href="#SessionsDatabaseReport">Sessions per database</a></li>};
-}
-if (exists $session_info{user}) {
-       print $fh qq{<li><a href="#SessionsUserReport">Sessions per user</a></li>};
-}
-if (exists $session_info{host}) {
-       print $fh qq{<li><a href="#SessionsHostReport">Sessions per host</a></li><li>};
-}
-if (exists $connection_info{database}) {
-       print $fh qq{<li><a href="#ConnectionsDatabaseReport">Connections per database</a></li>};
-}
-if (exists $connection_info{user}) {
-       print $fh qq{<li><a href="#ConnectionsUserReport">Connections per user</a></li>};
-}
-if (exists $connection_info{host}) {
-       print $fh qq{<li><a href="#ConnectionsHostReport">Connections per host</a></li><li>};
-}
+               if (scalar keys %lock_info > 0) {
+                       print $fh qq{<li><a href="#LocksByTypeReport">Locks by type</a></li>};
+               }
+               if (exists $session_info{database}) {
+                       print $fh qq{<li><a href="#SessionsDatabaseReport">Sessions per database</a></li>};
+               }
+               if (exists $session_info{user}) {
+                       print $fh qq{<li><a href="#SessionsUserReport">Sessions per user</a></li>};
+               }
+               if (exists $session_info{host}) {
+                       print $fh qq{<li><a href="#SessionsHostReport">Sessions per host</a></li><li>};
+               }
+               if (exists $connection_info{database}) {
+                       print $fh qq{<li><a href="#ConnectionsDatabaseReport">Connections per database</a></li>};
+               }
+               if (exists $connection_info{user}) {
+                       print $fh qq{<li><a href="#ConnectionsUserReport">Connections per user</a></li>};
+               }
+               if (exists $connection_info{host}) {
+                       print $fh qq{<li><a href="#ConnectionsHostReport">Connections per host</a></li><li>};
+               }
 
 
-print $fh qq{<a href="#SlowestQueriesReport">Slowest queries</a></li><li><a href="#NormalizedQueriesMostTimeReport">Queries that took up the most time (N)</a></li><li><a href="#NormalizedQueriesMostFrequentReport">Most frequent queries (N)</a></li><li><a href="#NormalizedQueriesSlowestAverageReport">Slowest queries (N)</a></li><li><a href="#NormalizedErrorsMostFrequentReport">Most frequent errors (N)</a></li>
+               print $fh qq{<a href="#SlowestQueriesReport">Slowest queries</a></li><li><a href="#NormalizedQueriesMostTimeReport">Queries that took up the most time (N)</a></li><li><a href="#NormalizedQueriesMostFrequentReport">Most frequent queries (N)</a></li><li><a href="#NormalizedQueriesSlowestAverageReport">Slowest queries (N)</a></li><li><a href="#NormalizedErrorsMostFrequentReport">Most frequent errors (N)</a></li>
                </ul>
        </div>
        <div id="littleTocTitle">Table of contents</div>
 </div>
+};
+       }
+       print $fh qq{
 </body>
 </html>
 };
@@ -2018,6 +2080,85 @@ sub dump_as_html
 
 }
 
+sub dump_error_as_html
+{
+
+       # Dump the html header
+       &html_header();
+
+       # Global informations
+       my $curdate = localtime(time);
+       my $fmt_nlines = &comma_numbers($nlines);
+       my $total_time = timestr($td);
+       $total_time =~ s/^([\.0-9]+) wallclock.*/$1/;
+       $total_time = &convert_time($total_time*1000);
+       my $logfile_str = join(',', @log_files);
+       print $fh qq{
+<div class="information">
+<ul>
+<li>Generated on $curdate</li>
+<li>Log file: $logfile_str</li>
+<li>Parsed $fmt_nlines log entries in $total_time</li>
+<li>Log start from $first_log_date to $last_log_date</li>
+</ul>
+</div>
+};
+
+       print $fh qq{
+<h2 id="NormalizedErrorsMostFrequentReport">Most frequent errors (N) <a href="#top" title="Back to top">^</a></h2>
+<table class="queryList">
+<tr>
+       <th>Rank</th>
+       <th>Times reported</th>
+       <th>Error</th>
+
+</tr>
+};
+       my $idx = 1;
+       foreach my $k (sort {$error_info{$b}{count} <=> $error_info{$a}{count}} keys %error_info) {
+               next if (!$error_info{$k}{count});
+               last if ($idx > $top);
+               my $col = $idx % 2;
+               print $fh "<tr class=\"row$col\"><td class=\"center top\">$idx</td><td class=\"relevantInformation top center\"><div class=\"tooltipLink\"><span class=\"information\">", &comma_numbers($error_info{$k}{count}), "</span>";
+               print $fh "<div class=\"tooltip\"><table><tr><th>Day</th><th>Time</th><th>Count</th></tr>";
+               foreach my $d (sort keys %{$error_info{$k}{chronos}}) {
+                       my $c = 1;
+                       $d =~ /^\d{4}(\d{2})(\d{2})$/;
+                       my $zday = "$abbr_month{$1} $2";
+                       foreach my $h (sort keys %{$error_info{$k}{chronos}{$d}}) {
+                               my $colb = $c % 2;
+                               $zday = "&nbsp;" if ($c > 1);
+                               print $fh "<tr class=\"row$colb\"><td>$zday</td><td>$h</td><td>", &comma_numbers($error_info{$k}{chronos}{$d}{$h}{count}), "</td></tr>";
+                               $c++;
+                       }
+               }
+               print $fh "</table></div></div></td>\n";
+               if ($error_info{$k}{count} > 1) {
+                       print $fh "<td><div class=\"error\">$k</div>";
+                       print $fh "<input type=\"button\" class=\"examplesButton\" id=\"button_NormalizedErrorsMostFrequentReport_$idx\" name=\"button_NormalizedErrorsMostFrequentReport_$idx\" value=\"Show examples\" onclick=\"javascript:toggle('button_NormalizedErrorsMostFrequentReport_$idx', 'examples_NormalizedErrorsMostFrequentReport_$idx', 'examples');\" /><div id=\"examples_NormalizedErrorsMostFrequentReport_$idx\" class=\"examples\" style=\"display:none;\">";
+                       for (my $i = 0; $i <= $#{$error_info{$k}{date}}; $i++) {
+                               my $c = $i % 2;
+                               print $fh "<div class=\"example$c\" title=\"$error_info{$k}{date}[$i]\">$error_info{$k}{error}[$i]</div>\n";
+                               print $fh "<div class=\"errorInformation$c\">Detail: $error_info{$k}{detail}[$i]</div>\n" if ($error_info{$k}{detail}[$i]);
+                       }
+                       print $fh "</div>";
+               } elsif ($error_info{$k}{detail}[0]) {
+                       print $fh "<td><div class=\"error\" title=\"$error_info{$k}{date}[0]\">$k</div>";
+                       print $fh "<div class=\"errorInformation\">Detail: $error_info{$k}{detail}[0]</div>\n";
+               } else {
+                       print $fh "<td><div class=\"error\" title=\"$error_info{$k}{date}[0]\">$k</div>";
+               }
+               print $fh "</td></tr>\n";
+               $idx++;
+       }
+       print $fh "</table>\n";
+
+       # Dump the html footer
+       &html_footer();
+
+}
+
+
 # Highlight SQL code
 sub highlight_code
 {
@@ -2065,6 +2206,7 @@ sub parse_query
                return;
        }
        next if ($t_loglevel eq 'CONTEXT');
+       next if ( $error_only && ($t_loglevel !~ /(WARNING|ERROR|FATAL|PANIC|DETAIL|HINT|STATEMENT)/) );
 
        # Extract user and database information from the logprefix part
        my $t_dbname = '';