Merge branch 'thh-bug51' into next
[usenet/newsstats.git] / bin / groupstats.pl
CommitLineData
3f817eb4 1#! /usr/bin/perl
2832c235
TH
2#
3# groupstats.pl
4#
5# This script will get statistical data on newgroup usage
d3b6810d 6# from a database.
dfc2b81c 7#
2832c235
TH
8# It is part of the NewsStats package.
9#
07c0b258 10# Copyright (c) 2010-2013 Thomas Hochstein <thh@inter.net>
2832c235 11#
dfc2b81c 12# It can be redistributed and/or modified under the same terms under
2832c235
TH
13# which Perl itself is published.
14
15BEGIN {
16 our $VERSION = "0.01";
17 use File::Basename;
2ad99c20
TH
18 # we're in .../bin, so our module is in ../lib
19 push(@INC, dirname($0).'/../lib');
2832c235
TH
20}
21use strict;
3f817eb4 22use warnings;
2832c235 23
edd250f2 24use NewsStats qw(:DEFAULT :TimePeriods :Output :SQLHelper ReadGroupList);
2832c235
TH
25
26use DBI;
edd250f2
TH
27use Getopt::Long qw(GetOptions);
28Getopt::Long::config ('bundling');
2832c235
TH
29
30################################# Main program #################################
31
32### read commandline options
edd250f2
TH
33my ($OptBoundType,$OptCaptions,$OptCheckgroupsFile,$OptComments,
34 $OptFileTemplate,$OptFormat,$OptGroupBy,$OptGroupsDB,$LowBound,$OptMonth,
23ab67a0 35 $OptNewsgroups,$OptOrderBy,$OptReportType,$OptSums,$UppBound,$OptConfFile);
edd250f2
TH
36GetOptions ('b|boundary=s' => \$OptBoundType,
37 'c|captions!' => \$OptCaptions,
38 'checkgroups=s' => \$OptCheckgroupsFile,
39 'comments!' => \$OptComments,
40 'filetemplate=s' => \$OptFileTemplate,
41 'f|format=s' => \$OptFormat,
42 'g|group-by=s' => \$OptGroupBy,
43 'groupsdb=s' => \$OptGroupsDB,
44 'l|lower=i' => \$LowBound,
45 'm|month=s' => \$OptMonth,
46 'n|newsgroups=s' => \$OptNewsgroups,
47 'o|order-by=s' => \$OptOrderBy,
48 'r|report=s' => \$OptReportType,
49 's|sums!' => \$OptSums,
50 'u|upper=i' => \$UppBound,
23ab67a0 51 'conffile=s' => \$OptConfFile,
edd250f2
TH
52 'h|help' => \&ShowPOD,
53 'V|version' => \&ShowVersion) or exit 1;
54# parse parameters
55# $OptComments defaults to TRUE
56$OptComments = 1 if (!defined($OptComments));
57# force --nocomments when --filetemplate is used
58$OptComments = 0 if ($OptFileTemplate);
59# parse $OptBoundType
60if ($OptBoundType) {
61 if ($OptBoundType =~ /level/i) {
62 $OptBoundType = 'level';
63 } elsif ($OptBoundType =~ /av(era)?ge?/i) {
64 $OptBoundType = 'average';
65 } elsif ($OptBoundType =~ /sums?/i) {
66 $OptBoundType = 'sum';
67 } else {
68 $OptBoundType = 'default';
69 }
70}
71# parse $OptReportType
72if ($OptReportType) {
73 if ($OptReportType =~ /av(era)?ge?/i) {
74 $OptReportType = 'average';
75 } elsif ($OptReportType =~ /sums?/i) {
76 $OptReportType = 'sum';
77 } else {
78 $OptReportType = 'default';
79 }
80}
17ef4408
TH
81# honor $OptCheckgroupsFile,
82# warn for $OptSums if set concurrently
83my $ValidGroups;
84if ($OptCheckgroupsFile) {
85 # read list of newsgroups from --checkgroups
86 # into a hash reference
87 $ValidGroups = &ReadGroupList($OptCheckgroupsFile);
88 &Bleat(1,"--sums option can't possibly work with --checkgroups option set")
89 if $OptSums;
90}
2832c235
TH
91
92### read configuration
23ab67a0 93my %Conf = %{ReadConfig($OptConfFile)};
2832c235
TH
94
95### override configuration via commandline options
96my %ConfOverride;
edd250f2 97$ConfOverride{'DBTableGrps'} = $OptGroupsDB if $OptGroupsDB;
2832c235
TH
98&OverrideConfig(\%Conf,\%ConfOverride);
99
f2ddfd8a
TH
100### init database
101my $DBHandle = InitDB(\%Conf,1);
102
edd250f2
TH
103### get time period and newsgroups, prepare SQL 'WHERE' clause
104# get time period
105# and set caption for output and expression for SQL 'WHERE' clause
106my ($CaptionPeriod,$SQLWherePeriod) = &GetTimePeriod($OptMonth);
107# bail out if --month is invalid
108&Bleat(2,"--month option has an invalid format - ".
109 "please use 'YYYY-MM', 'YYYY-MM:YYYY-MM' or 'ALL'!") if !$CaptionPeriod;
110# get list of newsgroups and set expression for SQL 'WHERE' clause
111# with placeholders as well as a list of newsgroup to bind to them
c30822b4
TH
112my ($SQLWhereNewsgroups,@SQLBindNewsgroups);
113if ($OptNewsgroups) {
114 ($SQLWhereNewsgroups,@SQLBindNewsgroups) = &SQLGroupList($OptNewsgroups);
115 # bail out if --newsgroups is invalid
116 &Bleat(2,"--newsgroups option has an invalid format!")
117 if !$SQLWhereNewsgroups;
118}
edd250f2
TH
119
120### build SQL WHERE clause (and HAVING clause, if needed)
121my ($SQLWhereClause,$SQLHavingClause);
122# $OptBoundType 'level'
123if ($OptBoundType and $OptBoundType ne 'default') {
124 $SQLWhereClause = SQLBuildClause('where',$SQLWherePeriod,
125 $SQLWhereNewsgroups,&SQLHierarchies($OptSums));
126 $SQLHavingClause = SQLBuildClause('having',&SQLSetBounds($OptBoundType,
127 $LowBound,$UppBound));
128# $OptBoundType 'threshold' / 'default' or none
f2ddfd8a 129} else {
edd250f2
TH
130 $SQLWhereClause = SQLBuildClause('where',$SQLWherePeriod,
131 $SQLWhereNewsgroups,&SQLHierarchies($OptSums),
132 &SQLSetBounds('default',$LowBound,$UppBound));
133}
2832c235 134
edd250f2 135### get sort order and build SQL 'ORDER BY' clause
ea91003a
TH
136# force to 'month' for $OptReportType 'average' or 'sum'
137$OptGroupBy = 'month' if ($OptReportType and $OptReportType ne 'default');
edd250f2
TH
138# default to 'newsgroup' for $OptBoundType 'level' or 'average'
139$OptGroupBy = 'newsgroup' if (!$OptGroupBy and
140 $OptBoundType and $OptBoundType ne 'default');
ea91003a
TH
141# default to 'newsgroup' if $OptGroupBy is not set and
142# just one newsgroup is requested, but more than one month
143$OptGroupBy = 'newsgroup' if (!$OptGroupBy and
144 $OptMonth =~ /:/ and $OptNewsgroups !~ /[:*%]/);
edd250f2 145# parse $OptGroupBy to $GroupBy, create ORDER BY clause $SQLOrderClause
ea91003a 146# if $OptGroupBy is still not set, SQLSortOrder() will default to 'month'
edd250f2
TH
147my ($GroupBy,$SQLOrderClause) = SQLSortOrder($OptGroupBy, $OptOrderBy);
148# $GroupBy will contain 'month' or 'newsgroup' (parsed result of $OptGroupBy)
149# set it to 'month' or 'key' for OutputData()
150$GroupBy = ($GroupBy eq 'month') ? 'month' : 'key';
151
152### get report type and build SQL 'SELECT' query
153my $SQLSelect;
154my $SQLGroupClause = '';
155my $Precision = 0; # number of digits right of decimal point for output
156if ($OptReportType and $OptReportType ne 'default') {
157 $SQLGroupClause = 'GROUP BY newsgroup';
158 # change $SQLOrderClause: replace everything before 'postings'
159 $SQLOrderClause =~ s/BY.+postings/BY postings/;
160 if ($OptReportType eq 'average') {
161 $SQLSelect = "'All months',newsgroup,AVG(postings)";
162 $Precision = 2;
163 # change $SQLOrderClause: replace 'postings' with 'AVG(postings)'
164 $SQLOrderClause =~ s/postings/AVG(postings)/;
165 } elsif ($OptReportType eq 'sum') {
166 $SQLSelect = "'All months',newsgroup,SUM(postings)";
167 # change $SQLOrderClause: replace 'postings' with 'SUM(postings)'
168 $SQLOrderClause =~ s/postings/SUM(postings)/;
169 }
170 } else {
171 $SQLSelect = 'month,newsgroup,postings';
2832c235
TH
172};
173
edd250f2
TH
174### get length of longest newsgroup name delivered by query
175### for formatting purposes
176my $Field = ($GroupBy eq 'month') ? 'newsgroup' : 'month';
b342fcf0
TH
177my ($MaxLength,$MaxValLength) = &GetMaxLength($DBHandle,$Conf{'DBTableGrps'},
178 $Field,'postings',$SQLWhereClause,
179 $SQLHavingClause,
180 @SQLBindNewsgroups);
edd250f2
TH
181
182### build and execute SQL query
183my ($DBQuery);
184# special query preparation for $OptBoundType 'level', 'average' or 'sums'
185if ($OptBoundType and $OptBoundType ne 'default') {
186 # prepare and execute first query:
187 # get list of newsgroups meeting level conditions
188 $DBQuery = $DBHandle->prepare(sprintf('SELECT newsgroup FROM %s.%s %s '.
189 'GROUP BY newsgroup %s',
190 $Conf{'DBDatabase'},$Conf{'DBTableGrps'},
191 $SQLWhereClause,$SQLHavingClause));
192 $DBQuery->execute(@SQLBindNewsgroups)
193 or &Bleat(2,sprintf("Can't get groups data for %s from %s.%s: %s\n",
194 $CaptionPeriod,$Conf{'DBDatabase'},$Conf{'DBTableGrps'},
195 $DBI::errstr));
b802bc3d
TH
196 # add newsgroups to a comma-seperated list ready for IN(...) query
197 my $GroupList;
198 while (my ($Newsgroup) = $DBQuery->fetchrow_array) {
edd250f2 199 $GroupList .= ',' if $GroupList;
b802bc3d
TH
200 $GroupList .= "'$Newsgroup'";
201 };
edd250f2
TH
202 # enhance $WhereClause
203 if ($GroupList) {
204 $SQLWhereClause = SQLBuildClause('where',$SQLWhereClause,
205 sprintf('newsgroup IN (%s)',$GroupList));
206 } else {
207 # condition cannot be satisfied;
208 # force query to fail by adding '0=1'
209 $SQLWhereClause = SQLBuildClause('where',$SQLWhereClause,'0=1');
210 }
211}
212
213# prepare query
214$DBQuery = $DBHandle->prepare(sprintf('SELECT %s FROM %s.%s %s %s %s',
215 $SQLSelect,
216 $Conf{'DBDatabase'},$Conf{'DBTableGrps'},
c30822b4
TH
217 $SQLWhereClause,$SQLGroupClause,
218 $SQLOrderClause));
2832c235
TH
219
220# execute query
edd250f2
TH
221$DBQuery->execute(@SQLBindNewsgroups)
222 or &Bleat(2,sprintf("Can't get groups data for %s from %s.%s: %s\n",
223 $CaptionPeriod,$Conf{'DBDatabase'},$Conf{'DBTableGrps'},
224 $DBI::errstr));
225
226### output results
227# set default to 'pretty'
228$OptFormat = 'pretty' if !$OptFormat;
229# print captions if --caption is set
230if ($OptCaptions && $OptComments) {
231 # print time period with report type
232 my $CaptionReportType= '(number of postings for each month)';
233 if ($OptReportType and $OptReportType ne 'default') {
234 $CaptionReportType= '(average number of postings for each month)'
235 if $OptReportType eq 'average';
236 $CaptionReportType= '(number of all postings for that time period)'
237 if $OptReportType eq 'sum';
238 }
239 printf("# ----- Report for %s %s\n",$CaptionPeriod,$CaptionReportType);
240 # print newsgroup list if --newsgroups is set
241 printf("# ----- Newsgroups: %s\n",join(',',split(/:/,$OptNewsgroups)))
242 if $OptNewsgroups;
243 # print boundaries, if set
244 my $CaptionBoundary= '(counting only month fulfilling this condition)';
245 if ($OptBoundType and $OptBoundType ne 'default') {
246 $CaptionBoundary= '(every single month)' if $OptBoundType eq 'level';
247 $CaptionBoundary= '(on average)' if $OptBoundType eq 'average';
248 $CaptionBoundary= '(all month summed up)' if $OptBoundType eq 'sum';
249 }
250 printf("# ----- Threshold: %s %s x %s %s %s\n",
251 $LowBound ? $LowBound : '',$LowBound ? '=>' : '',
252 $UppBound ? '<=' : '',$UppBound ? $UppBound : '',$CaptionBoundary)
253 if ($LowBound or $UppBound);
254 # print primary and secondary sort order
255 printf("# ----- Grouped by %s (%s), sorted %s%s\n",
256 ($GroupBy eq 'month') ? 'Months' : 'Newsgroups',
257 ($OptGroupBy and $OptGroupBy =~ /-?desc$/i) ? 'descending' : 'ascending',
258 ($OptOrderBy and $OptOrderBy =~ /posting/i) ? 'by number of postings ' : '',
259 ($OptOrderBy and $OptOrderBy =~ /-?desc$/i) ? 'descending' : 'ascending');
260}
23ab67a0 261
edd250f2
TH
262# output data
263&OutputData($OptFormat,$OptComments,$GroupBy,$Precision,
264 $OptCheckgroupsFile ? $ValidGroups : '',
b342fcf0 265 $OptFileTemplate,$DBQuery,$MaxLength,$MaxValLength);
2832c235
TH
266
267### close handles
268$DBHandle->disconnect;
269
270__END__
271
272################################ Documentation #################################
273
274=head1 NAME
275
276groupstats - create reports on newsgroup usage
277
278=head1 SYNOPSIS
279
23ab67a0 280B<groupstats> [B<-Vhcs> B<--comments>] [B<-m> I<YYYY-MM>[:I<YYYY-MM>] | I<all>] [B<-n> I<newsgroup(s)>] [B<--checkgroups> I<checkgroups file>] [B<-r> I<report type>] [B<-l> I<lower boundary>] [B<-u> I<upper boundary>] [B<-b> I<boundary type>] [B<-g> I<group by>] [B<-o> I<order by>] [B<-f> I<output format>] [B<--filetemplate> I<filename template>] [B<--groupsdb> I<database table>] [--conffile I<filename>]
2832c235
TH
281
282=head1 REQUIREMENTS
283
edd250f2 284See L<doc/README>.
2832c235
TH
285
286=head1 DESCRIPTION
287
288This script create reports on newsgroup usage (number of postings per
289group per month) taken from result tables created by
edd250f2 290B<gatherstats.pl>.
2832c235 291
edd250f2 292=head2 Features and options
2832c235 293
edd250f2 294=head3 Time period and newsgroups
2832c235 295
edd250f2
TH
296The time period to act on defaults to last month; you can assign another
297time period or a single month (or drop all time constraints) via the
298B<--month> option (see below).
2832c235 299
edd250f2
TH
300B<groupstats> will process all newsgroups by default; you can limit
301processing to only some newsgroups by supplying a list of those groups via
302B<--newsgroups> option (see below). You can include hierarchy levels in
303the output by adding the B<--sums> switch (see below). Optionally
304newsgroups not present in a checkgroups file can be excluded from output,
305sse B<--checkgroups> below.
306
307=head3 Report type
308
309You can choose between different B<--report> types: postings per month,
310average postings per month or all postings summed up; for details, see
311below.
312
313=head3 Upper and lower boundaries
314
315Furthermore you can set an upper and/or lower boundary to exclude some
316results from output via the B<--lower> and B<--upper> options,
317respectively. By default, all newsgroups with more and/or less postings
318per month will be excluded from the result set (i.e. not shown and not
319considered for average and sum reports). You can change the meaning of
320those boundaries with the B<--boundary> option. For details, please see
321below.
322
323=head3 Sorting and formatting the output
324
325By default, all results are grouped by month; you can group results by
326newsgroup instead via the B<--groupy-by> option. Within those groups, the
327list of newsgroups (or months) is sorted alphabetically (or
328chronologically, respectively) ascending. You can change that order (and
329sort by number of postings) with the B<--order-by> option. For details and
330exceptions, please see below.
331
332The results will be formatted as a kind of table; you can change the
333output format to a simple list or just a list of newsgroups and number of
334postings with the B<--format> option. Captions will be added by means of
335the B<--caption> option; all comments (and captions) can be supressed by
336using B<--nocomments>.
337
338Last but not least you can redirect all output to a number of files, e.g.
339one for each month, by submitting the B<--filetemplate> option, see below.
340Captions and comments are automatically disabled in this case.
2832c235
TH
341
342=head2 Configuration
343
f2ddfd8a 344B<groupstats> will read its configuration from F<newsstats.conf>
2832c235
TH
345which should be present in the same directory via Config::Auto.
346
347See doc/INSTALL for an overview of possible configuration options.
348
edd250f2 349You can override some configuration options via the B<--groupsdb> option.
2832c235
TH
350
351=head1 OPTIONS
352
353=over 3
354
edd250f2 355=item B<-V>, B<--version>
2832c235 356
edd250f2 357Print out version and copyright information and exit.
2832c235 358
edd250f2 359=item B<-h>, B<--help>
2832c235
TH
360
361Print this man page and exit.
362
dfc2b81c 363=item B<-m>, B<--month> I<YYYY-MM[:YYYY-MM]|all>
2832c235 364
edd250f2
TH
365Set processing period to a single month in YYYY-MM format or to a time
366period between two month in YYYY-MM:YYYY-MM format (two month, separated
367by a colon). By using the keyword I<all> instead, you can set no
368processing period to process the whole database.
2832c235 369
edd250f2 370=item B<-n>, B<--newsgroups> I<newsgroup(s)>
2832c235
TH
371
372Limit processing to a certain set of newsgroups. I<newsgroup(s)> can
373be a single newsgroup name (de.alt.test), a newsgroup hierarchy
374(de.alt.*) or a list of either of these, separated by colons, for
375example
376
377 de.test:de.alt.test:de.newusers.*
378
edd250f2 379=item B<-s>, B<--sums|--nosums> (sum per hierarchy level)
2832c235 380
edd250f2
TH
381Include "virtual" groups for every hierarchy level in output, for
382example:
2832c235 383
edd250f2
TH
384 de.alt.ALL 10
385 de.alt.test 5
386 de.alt.admin 7
2832c235 387
edd250f2 388See the B<gatherstats> man page for details.
2832c235 389
17ef4408
TH
390This option does not work together with the B<--checkgroups> option as
391all "virtual" groups will not be present in the checkgroups file.
392
edd250f2 393=item B<--checkgroups> I<filename>
2832c235 394
edd250f2
TH
395Restrict output to those newgroups present in a file in checkgroups format
396(one newgroup name per line; everything after the first whitespace on each
397line is ignored). All other newsgroups will be removed from output.
2832c235 398
95d9fe2c
TH
399Contrary to B<gatherstats>, I<filename> is not a template, but refers to
400a single file in checkgroups format.
401
17ef4408
TH
402The B<--sums> option will not work together with this option as "virtual"
403groups will not be present in the checkgroups file.
404
edd250f2 405=item B<-r>, B<--report> I<default|average|sums>
2832c235 406
edd250f2 407Choose the report type: I<default>, I<average> or I<sums>
2832c235 408
edd250f2
TH
409By default, B<groupstats> will report the number of postings for each
410newsgroup in each month. But it can also report the average number of
411postings per group for all months or the total sum of postings per group
412for all months.
2832c235 413
edd250f2
TH
414For report types I<average> and I<sums>, the B<group-by> option has no
415meaning and will be silently ignored (see below).
2832c235 416
edd250f2 417=item B<-l>, B<--lower> I<lower boundary>
2832c235 418
edd250f2 419Set the lower boundary. See B<--boundary> below.
2832c235 420
edd250f2 421=item B<-l>, B<--upper> I<upper boundary>
2832c235 422
edd250f2 423Set the upper boundary. See B<--boundary> below.
2832c235 424
edd250f2
TH
425=item B<-b>, B<--boundary> I<boundary type>
426
427Set the boundary type to one of I<default>, I<level>, I<average> or
428I<sums>.
429
430By default, all newsgroups with more postings per month than the upper
431boundary and/or less postings per month than the lower boundary will be
432excluded from further processing. For the default report that means each
433month only newsgroups with a number of postings between the boundaries
434will be displayed. For the other report types, newsgroups with a number of
435postings exceeding the boundaries in all (!) months will not be
436considered.
437
438For example, lets take a list of newsgroups like this:
439
440 ----- 2012-01:
441 de.comp.datenbanken.misc 6
442 de.comp.datenbanken.ms-access 84
443 de.comp.datenbanken.mysql 88
444 ----- 2012-02:
445 de.comp.datenbanken.misc 8
446 de.comp.datenbanken.ms-access 126
447 de.comp.datenbanken.mysql 21
448 ----- 2012-03:
449 de.comp.datenbanken.misc 24
450 de.comp.datenbanken.ms-access 83
451 de.comp.datenbanken.mysql 36
452
453With C<groupstats --month 2012-01:2012-03 --lower 25 --report sums>,
454you'll get the following result:
2832c235 455
edd250f2
TH
456 ----- All months:
457 de.comp.datenbanken.ms-access 293
458 de.comp.datenbanken.mysql 124
2832c235 459
edd250f2
TH
460de.comp.datenbanken.misc has not been considered even though it has 38
461postings in total, because it has less than 25 postings in every single
95d9fe2c
TH
462month. If you want to list all newsgroups with more than 25 postings
463I<in total>, you'll have to set the boundary type to I<sum>, see below.
628a183c 464
edd250f2
TH
465A boundary type of I<level> will show only those newsgroups - at all -
466that satisfy the boundaries in each and every single month. With the above
467list of newsgroups and
468C<groupstats --month 2012-01:2012-03 --lower 25 --boundary level --report sums>,
469you'll get this result:
2832c235 470
edd250f2
TH
471 ----- All months:
472 de.comp.datenbanken.ms-access 293
2832c235 473
edd250f2 474de.comp.datenbanken.mysql has not been considered because it had less than
95d9fe2c 47525 postings in 2012-02 (only).
2832c235 476
edd250f2 477You can use that to get a list of newsgroups that have more (or less) then
95d9fe2c 478x postings in every month during the whole reporting period.
2832c235 479
edd250f2
TH
480A boundary type of I<average> will show only those newsgroups - at all -that
481satisfy the boundaries on average. With the above list of newsgroups and
482C<groupstats --month 2012-01:2012-03 --lower 25 --boundary avg --report sums>,
483you'll get this result:
78389b28 484
edd250f2
TH
485 ----- All months:
486 de.comp.datenbanken.ms-access 293
487 de.comp.datenbanken.mysql 145
2832c235 488
edd250f2 489The average number of postings in the three groups is:
2832c235 490
edd250f2
TH
491 de.comp.datenbanken.misc 12.67
492 de.comp.datenbanken.ms-access 97.67
493 de.comp.datenbanken.mysql 48.33
2832c235 494
edd250f2
TH
495Last but not least, a boundary type of I<sums> will show only those
496newsgroups - at all - that satisfy the boundaries with the total sum of
497all postings during the reporting period. With the above list of
498newsgroups and
499C<groupstats --month 2012-01:2012-03 --lower 25 --boundary sum --report sums>,
500you'll finally get this result:
2832c235 501
edd250f2
TH
502 ----- All months:
503 de.comp.datenbanken.misc 38
504 de.comp.datenbanken.ms-access 293
505 de.comp.datenbanken.mysql 145
2832c235 506
2832c235 507
edd250f2 508=item B<-g>, B<--group-by> I<month[-desc]|newsgroups[-desc]>
2832c235 509
edd250f2
TH
510By default, all results are grouped by month, sorted chronologically in
511ascending order, like this:
78389b28 512
edd250f2
TH
513 ----- 2012-01:
514 de.comp.datenbanken.ms-access 84
515 de.comp.datenbanken.mysql 88
516 ----- 2012-02:
517 de.comp.datenbanken.ms-access 126
518 de.comp.datenbanken.mysql 21
78389b28 519
edd250f2
TH
520The results can be grouped by newsgroups instead via
521B<--group-by> I<newsgroup>:
522
523 ----- de.comp.datenbanken.ms-access:
524 2012-01 84
525 2012-02 126
526 ----- de.comp.datenbanken.mysql:
527 2012-01 88
528 2012-02 21
529
530By appending I<-desc> to the group-by option parameter, you can reverse
531the sort order - e.g. B<--group-by> I<month-desc> will give:
532
533 ----- 2012-02:
534 de.comp.datenbanken.ms-access 126
535 de.comp.datenbanken.mysql 21
536 ----- 2012-01:
537 de.comp.datenbanken.ms-access 84
538 de.comp.datenbanken.mysql 88
539
540Average and sums reports (see above) will always be grouped by months;
541this option will therefore be ignored.
542
543=item B<-o>, B<--order-by> I<default[-desc]|postings[-desc]>
544
545Within each group (a single month or single newsgroup, see above), the
546report will be sorted by newsgroup names in ascending alphabetical order
547by default. You can change the sort order to descending or sort by number
548of postings instead.
549
550=item B<-f>, B<--format> I<pretty|list|dump>
551
552Select the output format, I<pretty> being the default:
553
554 ----- 2012-01:
555 de.comp.datenbanken.ms-access 84
556 de.comp.datenbanken.mysql 88
557 ----- 2012-02:
558 de.comp.datenbanken.ms-access 126
559 de.comp.datenbanken.mysql 21
560
561I<list> format looks like this:
562
563 2012-01 de.comp.datenbanken.ms-access 84
564 2012-01 de.comp.datenbanken.mysql 88
565 2012-02 de.comp.datenbanken.ms-access 126
566 2012-02 de.comp.datenbanken.mysql 21
567
568And I<dump> format looks like this:
569
570 # 2012-01:
571 de.comp.datenbanken.ms-access 84
572 de.comp.datenbanken.mysql 88
573 # 2012-02:
574 de.comp.datenbanken.ms-access 126
575 de.comp.datenbanken.mysql 21
576
577You can remove the comments by using B<--nocomments>, see below.
578
579=item B<-c>, B<--captions|--nocaptions>
580
581Add captions to output, like this:
582
583 ----- Report for 2012-01 to 2012-02 (number of postings for each month)
584 ----- Newsgroups: de.comp.datenbanken.*
585 ----- Threshold: 10 => x <= 20 (on average)
586 ----- Grouped by Newsgroups (ascending), sorted by number of postings descending
587
588False by default.
589
590=item B<--comments|--nocomments>
591
592Add comments (group headers) to I<dump> and I<pretty> output. True by default.
593
594Use I<--nocomments> to suppress anything except newsgroup names/months and
595numbers of postings. This is enforced when using B<--filetemplate>, see below.
596
597=item B<--filetemplate> I<filename template>
598
599Save output to file(s) instead of dumping it to STDOUT. B<groupstats> will
600create one file for each month (or each newsgroup, accordant to the
601setting of B<--group-by>, see above), with filenames composed by adding
602year and month (or newsgroup names) to the I<filename template>, for
603example with B<--filetemplate> I<stats>:
604
605 stats-2012-01
606 stats-2012-02
78389b28
TH
607 ... and so on
608
edd250f2 609B<--nocomments> is enforced, see above.
78389b28 610
edd250f2 611=item B<--groupsdb> I<database table>
2832c235
TH
612
613Override I<DBTableGrps> from F<newsstats.conf>.
614
23ab67a0
TH
615=item B<--conffile> I<filename>
616
617Load configuration from I<filename> instead of F<newsstats.conf>.
618
2832c235
TH
619=back
620
621=head1 INSTALLATION
622
edd250f2 623See L<doc/INSTALL>.
2832c235
TH
624
625=head1 EXAMPLES
626
edd250f2 627Show number of postings per group for lasth month in I<pretty> format:
2832c235
TH
628
629 groupstats
630
631Show that report for January of 2010 and de.alt.* plus de.test,
632including display of hierarchy levels:
633
edd250f2 634 groupstats --month 2010-01 --newsgroups de.alt.*:de.test --sums
2832c235 635
edd250f2
TH
636Only show newsgroups with 30 postings or less last month, ordered
637by number of postings, descending, in I<pretty> format:
2832c235 638
edd250f2 639 groupstats --upper 30 --order-by postings-desc
2832c235 640
edd250f2
TH
641Show the total of all postings for the year of 2010 for all groups that
642had 30 postings or less in every single month in that year, ordered by
643number of postings in descending order:
644
645 groupstats -m 2010-01:2010-12 -u 30 -b level -r sums -o postings-desc
2832c235 646
edd250f2 647The same for the average number of postings in the year of 2010:
2832c235 648
edd250f2 649 groupstats -m 2010-01:2010-12 -u 30 -b level -r avg -o postings-desc
2832c235 650
edd250f2
TH
651List number of postings per group for eacht month of 2010 and redirect
652output to one file for each month, namend stats-2010-01 and so on, in
653machine-readable form (without formatting):
2832c235 654
edd250f2 655 groupstats -m 2010-01:2010-12 -f dump --filetemplate stats
2832c235 656
2832c235
TH
657
658=head1 FILES
659
660=over 4
661
2ad99c20 662=item F<bin/groupstats.pl>
2832c235
TH
663
664The script itself.
665
2ad99c20 666=item F<lib/NewsStats.pm>
2832c235
TH
667
668Library functions for the NewsStats package.
669
2ad99c20 670=item F<etc/newsstats.conf>
2832c235 671
edd250f2 672Runtime configuration file.
2832c235
TH
673
674=back
675
676=head1 BUGS
677
678Please report any bugs or feature requests to the author or use the
679bug tracker at L<http://bugs.th-h.de/>!
680
681=head1 SEE ALSO
682
683=over 2
684
685=item -
686
edd250f2 687L<doc/README>
2832c235
TH
688
689=item -
690
edd250f2 691l>doc/INSTALL>
2832c235
TH
692
693=item -
694
695gatherstats -h
696
697=back
698
699This script is part of the B<NewsStats> package.
700
701=head1 AUTHOR
702
703Thomas Hochstein <thh@inter.net>
704
705=head1 COPYRIGHT AND LICENSE
706
edd250f2 707Copyright (c) 2010-2012 Thomas Hochstein <thh@inter.net>
2832c235
TH
708
709This program is free software; you may redistribute it and/or modify it
710under the same terms as Perl itself.
711
712=cut
This page took 0.055557 seconds and 4 git commands to generate.