my $regex_prefix_dbuser = '';
my $quiet = 0;
my $progress = 0;
+my $error_only = 0;
my $NUMPROGRESS = 10000;
my @DIMENSIONS = (800,300);
"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) {
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;
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.
-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;
}
+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);
/* ]]> */
</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";
}
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>
};
}
+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 = " " 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
{
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 = '';