#!/usr/bin/perl # # postingstats.pl # # 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, 2025 Thomas Hochstein # # It can be redistributed and/or modified under the same terms under # which Perl itself is published. # # Usage: # $~ groupstats.pl --nocomments --sums --format dump | postingstats.pl -t groups # $~ hoststats.pl --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 ##### ----- 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; ##### ----- 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=us-ascii Content-Transfer-Encoding: 7bit User-Agent: postingstats.pl/$VERSION (NewsStats) 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) HOSTSIN my %LeadOut = ('GroupStats' => < < zur Verfuegung. 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 (present in C). =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: hoststats.pl --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 =item - groupstats -h =item - hoststats -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