From 29e978404864c2dfa788d23d0efc10c41320fbe1 Mon Sep 17 00:00:00 2001 From: Thomas Hochstein Date: Sun, 11 May 2025 14:31:53 +0200 Subject: [PATCH] Refactor postingstats. - Make all text configurable (i18n). - Generalize to make it usable for HostStats. - Fallback to last month if no month is given. - Add option handling, import VERSION, add POD. Signed-off-by: Thomas Hochstein --- bin/postingstats.pl | 384 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 319 insertions(+), 65 deletions(-) diff --git a/bin/postingstats.pl b/bin/postingstats.pl index 227f53e..b378fbb 100644 --- a/bin/postingstats.pl +++ b/bin/postingstats.pl @@ -2,88 +2,93 @@ # # postingstats.pl # -# This script will create a posting statistic for de.admin.lists -# from NewsStats output. +# This script will create statistic postings from NewsStats output. +# It defaults to statistics for de.* posted to de.admin.lists, but +# defaults can be changed at ----- configuration -----. # # It is part of the NewsStats package. # -# Copyright (c) 2010-2012 Thomas Hochstein +# Copyright (c) 2010-2012, 2025 Thomas Hochstein # # It can be redistributed and/or modified under the same terms under # which Perl itself is published. # -# $~ groupstats.pl --nocomments --sums --format dump | postingstats.pl xxxx-xx +# Usage: +# $~ groupstats.pl --nocomments --sums --format dump | postingstats.pl -t groups +# $~ cliservstats.pl -t server --nocomments --sums --format dump | postingstats.pl -t hosts # +BEGIN { + use File::Basename; + # we're in .../bin, so our module is in ../lib + push(@INC, dirname($0).'/../lib'); +} use strict; +use warnings; + +use NewsStats qw(:DEFAULT LastMonth); + +use Getopt::Long qw(GetOptions); +Getopt::Long::config ('bundling'); + use constant TABLEWIDTH => 28; # width of table without newsgroup name -our $VERSION = '0.01'; +##### ----- pre-config ----------------------------------------------- +### read commandline options +my ($Month, $Type); +GetOptions ('m|month=s' => \$Month, + 't|type=s' => \$Type, + 'h|help' => \&ShowPOD, + 'V|version' => \&ShowVersion) or exit 1; +$Month = &LastMonth if !$Month; +if ($Month !~ /^\d{4}-\d{2}$/) { + $Month = &LastMonth; + &Bleat(1,"--month option has an invalid format - set to $Month."); +}; +# parse $Type +if (!$Type) { + # default + $Type = 'GroupStats'; +} elsif ($Type =~ /(news)?groups?/i) { + $Type = 'GroupStats'; +} elsif ($Type =~ /(host|server)s?/i) { + $Type = 'HostStats'; +}; +my $Timestamp = time; -##### ----- subroutines ----- - -sub percentage { -# calculate percentage rate from base value and percentage - my ($base,$percentage) = @_; - return ($percentage * 100 / $base); -} - -sub divider { -# build a divider line of $symbol as wide as the table is - my ($symbol,$maxlength) = @_; - return ':' . $symbol x ($maxlength+TABLEWIDTH) . ":\n"; -} - -##### ----- main loop ----- - -# get $month from ARGV -my $month = shift; - -# read from STDIN -my (%postings, $hierarchy, $maxlength); - -while(<>) { - my ($group, $postings) = split; - $hierarchy = $postings if $group eq 'de.ALL'; - next if $group =~ /ALL$/; - $postings{$group} = $postings; - $maxlength = length($group) if length($group) > $maxlength; -} - -# print to STDOUT -my $heading = ' Postingstatistik fuer de.* im Monat '.$month; -my $padding = ' ' x (($maxlength+TABLEWIDTH-2-length($heading))/2); -my $timestamp = time; -my $counter = 0; - -print < -Newsgroups: de.admin.news.misc -Subject: Postingstatistik fuer de.* im Monat $month -Message-ID: +##### ----- configuration -------------------------------------------- +my $TLH = 'de'; +my %Heading = ('GroupStats' => 'Postingstatistik fuer de.* im Monat '.$Month, + 'HostStats' => 'Serverstatistik fuer de.* im Monat '.$Month + ); +my %TH = ('counter' => 'Nr.', + 'value' => 'Anzahl', + 'percentage' => 'Prozent' + ); +my %LeadIn = ('GroupStats' => < < +Newsgroups: local.test +Subject: Postingstatistik fuer de.* im Monat $Month +Message-ID: +Approved: thh\@thh.name Mime-Version: 1.0 -Content-Type: text/plain; charset=ISO-8859-1 +Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit User-Agent: postingstats.pl/$VERSION (NewsStats) -HEADER +GROUPSIN +From: Thomas Hochstein +Newsgroups: local.test +Subject: Serverstatistik fuer de.* im Monat $Month +Message-ID: +Approved: thh\@thh.name +Mime-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit +User-Agent: postingstats.pl/$VERSION (NewsStats) -print ÷r('=',$maxlength); -printf(": %s%s%s :\n",$padding,$heading,$padding); -print ÷r('=',$maxlength); -printf(": Nr. : Anzahl : Prozent : %-*s :\n",$maxlength,'Newsgroup'); -print ÷r('-',$maxlength); - -foreach my $group (sort { $postings{$b} <=> $postings {$a}} keys %postings) { - $counter++; - printf(": %3u. : %6u : %6.2f%% : %-*s :\n",$counter,$postings{$group},&percentage($hierarchy,$postings{$group}),$maxlength,$group); -} - -print ÷r('-',$maxlength); -printf(": : %6u : %s : %-*s :\n",$hierarchy,'100.00%',$maxlength,'de.*'); -print ÷r('=',$maxlength); - -print < < < zur Verfuegung. -LEADOUT +GROUPSOUT + +Alle Zahlen wurden ermittelt auf einem Newsserver mit redundanter Anbin- +dung fuer de.* unter Anwendung ueblicher Filtermassnahmen. Steuernach- +richten werden nicht erfasst; Postings, die supersedet oder gecancelt +wurden, bleiben erfasst, sofern sie das System ueberhaupt (und vor der +Loeschnachricht) erreicht haben. +HOSTSOUT + +##### ----- subroutines ---------------------------------------------- + +sub Percentage { +# calculate percentage rate from base value and percentage + my ($Base,$Percentage) = @_; + return ($Percentage * 100 / $Base); +} + +sub Divider { +# build a divider line of $Symbol as wide as the table is + my ($Symbol,$MaxLength) = @_; + return ':' . $Symbol x ($MaxLength+TABLEWIDTH) . ":\n"; +} + +##### ----- main loop ------------------------------------------------ + +my (%Value, $SumName, $SumTotal, $MaxLength); +$MaxLength = 0; +if ($Type eq 'GroupStats') { + $SumName = "$TLH.ALL"; + $TH{'name'} = 'Newsgroup' +} elsif ($Type eq 'HostStats') { + $SumName = 'ALL'; + $TH{'name'} = 'Server' +} + +# read from STDIN +while(<>) { + my ($Name, $Value) = split; + $SumTotal = $Value if $Name eq $SumName; + next if $Name =~ /ALL$/; + $Value{$Name} = $Value; + $MaxLength = length($Name) if length($Name) > $MaxLength; +} + +# print to STDOUT +my $PaddingLeft = ' ' x int((($MaxLength+TABLEWIDTH-2-length($Heading{$Type}))/2)); +my $PaddingRight = $PaddingLeft; +$PaddingLeft .= ' ' if (length($Heading{$Type}) + (length($PaddingLeft) * 2) < $MaxLength+TABLEWIDTH); +my $Counter = 0; + +print $LeadIn{$Type}; + +print &Divider('=',$MaxLength); +printf(": %s%s%s :\n",$PaddingLeft,$Heading{$Type},$PaddingRight); +print &Divider('=',$MaxLength); +printf(": %-3s : %-6s : %-7s : %-*s :\n", + substr($TH{'counter'},0,3), + substr($TH{'value'},0,6), + substr($TH{'percentage'},0,7), + $MaxLength,$TH{'name'}); +print &Divider('-',$MaxLength); + +foreach my $Name (sort { $Value{$b} <=> $Value {$a}} keys %Value) { + $Counter++; + printf(": %3u. : %6u : %6.2f%% : %-*s :\n",$Counter,$Value{$Name},&Percentage($SumTotal,$Value{$Name}),$MaxLength,$Name); +} + +print &Divider('-',$MaxLength); +printf(": : %6u : %s : %-*s :\n",$SumTotal,'100.00%',$MaxLength,''); +print &Divider('=',$MaxLength); + +print $LeadOut{$Type}; + +__END__ + +################################ Documentation ################################# + +=head1 NAME + +postingstats - format and post reports + +=head1 SYNOPSIS + +B B<-t> I [B<-Vh> [B<-m> I] + +=head1 REQUIREMENTS + +See L. + +=head1 DESCRIPTION + +This script will re-format reports on newsgroup usage created by +B or B and create a message that can +be posted to Usenet. + +=head2 Features and options + +B will create a table with entries numbered from most +to least and percentages calculated from the sum total of all values. + +It depends on a sorted list on STDIN in I format with I. + +B needs a B<--type> and a B<--month> to create a caption +and select matching lead-ins and lead-outs. B<--type> is also needed +to catch the correct sum total from input. + +It will default to posting statistics (number of postings per group) +and last month. + +Output from B can be piped to any C implementation, +e.g. C from L. + +=head2 Configuration + +Configuration is done by changing the code in the +C<----- configuration -----> section. + +=over 3 + +=item C<$TLH> + +Top level hierarchy the report was created for. Used for display and +sum total. + +=item C<%Heading> + +Hash with keys for I and I. Used to display a +heading. + +=item C<%TH> + +Hash with keys for I, I and I. Used to +create the table header for I, I and I. + +I must not be longer than 3 characters, I no longer +than 6 characters and I no longer than 7 characters. +Output will be truncated otherwise. + +=item C<%LeadIn> + +Hash with keys for I and I. Used to create the +headers for our posting. Can contain other text that will be shown +before C<%Heading>. + +=item C<%LeadOut> + +Hash with keys for I and I. Will be shown at the +end of our posting. + +=back + +=head1 OPTIONS + +=over 3 + +=item B<-V>, B<--version> + +Print out version and copyright information and exit. + +=item B<-h>, B<--help> + +Print this man page and exit. + +=item B<-t>, B<--type> I + +Set report type to posting statistics or hosts statistics accordingly. + +=item B<-m>, B<--month> I + +Set month for display. + +=back + +=head1 INSTALLATION + +See L. + +=head1 USAGE + +Create a posting from a posting statistics report for last month: + + groupstats.pl --nocomments --sums --format dump | postingstats.pl -t groups + +Create a posting from a posting statistics report for 2012-01: + + groupstats.pl --nocomments --sums --format dump | postingstats.pl -t groups -m 2012-01 + +Create a posting from a host statistics report for last month: + + cliservstats.pl -t server --nocomments --sums --format dump | postingstats.pl -t hosts + +=head1 FILES + +=over 4 + +=item F + +The script itself. + +=item F + +Library functions for the NewsStats package. + +=item F + +Runtime configuration file. + +=back + +=head1 BUGS + +Please report any bugs or feature requests to the author or use the +bug tracker at L! + +=head1 SEE ALSO + +=over 2 + +=item - + +L + +=item - + +l>doc/INSTALL> + +=item - + +groupstats -h + +=item - + +cliservstats -h + +=back + +This script is part of the B package. + +=head1 AUTHOR + +Thomas Hochstein + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2010-2012, 2025 Thomas Hochstein + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=cut