On Thu, 11 Apr 2002, Sam Noble wrote:
> I'm interested in counting the number of *PIECES OF PAPER* used by
> our duplexing HP 4050 printers (and perhaps some 4000 and 4100 models as
> well). We charge people for printing but would like to encourage the use
> of our duplexing printers -- save the earth and all. Obviously, it's
> always possible for somebody to alternate in blank pages, but I think
> that this can be dealt with by charging slightly more than %50 of the
> price of a single-sided job.
>
> Has anybody done this? Can you outline the steps you took?
>
> It occurred to me that I might mess around with bounce queues, but
> in the end I want to have a single output queue which directly talks (via
> ifhp) to each printer, but I need my accounting file to reflect the fact
> that a job was duplexed or not (which I might be able to do simply by
> running a script on the postscript job to check for the duplexing
> postscript commands).
In our printcap, we use the stock lprng accounting scripts:
:as=|/auto/global/lprng/libexec/filters/accounting.pl start
:ae=|/auto/global/lprng/libexec/filters/accounting.pl end
and also this:
:ifhp=model=hp4050,of_options=pagecount waitend
:accounting=/auto/global/lprng/libexec/filters/acc.pl
which runs acc.pl after each job.
The acc.pl script is attachment #1. For weird reasons, we write
accounting info to two different files... Produces lines like this:
ifhp|rebecca|7763|appenzell|pr62|o|duplex|217353|3|2002-04-11-16:22:55.498
ifhp|parag|7771|ojibwa|pr69|o|simplex|141945|3|2002-04-11-16:25:48.718
Then every month, we split off the old month's lines and run
a report with this script, attchment #2, also perl:
% pracct -h
Usage: pracct [-bhnptu] [-i user] [-L file]
-u Show accounting by user
-p Show accounting by printer
-i Show accounting for a specific user
-t Show page total only
-b Omit headers and totals, and separate fields with a tab
-n Sort by number of pages instead of by user or printer
-L Specify the log file
-h Print this help message and exit
e.g.
pracct -u -i $USER
This will show both "pages" and "sheets" usage. Sample output:
User Sheets Percent Pages Percent
-------- ------ ------- ------ -------
aban 152 0.3 152 0.2
abhijit 400 0.9 680 0.9
achatham 27 0.1 29 0.0
...
Total: 44179 72499
We also have a CGI script that will produce a "Top 10" users web page...
This info will certainly require modifications for your site setup.
Bytheway, we're running lprng 3.7.4 and ifhp 3.4.4 . YMMV.
Dan
--
Daniel E. Singer, System Administrator
Dept. of Computer Science, Duke University, Durham NC 27708 USA
"Non cognosco. In hoc tantum laboro."
#!/usr/local/bin/perl
# @(#) /auto/global/lprng/libexec/filters/SCCS/s.acc.pl 1.1 2001/02/02 13:21:23
#
# acc.pl, 11/2000, D.Singer
# derived from:
#
# Patrick Powell Sun Sep 3 11:23:22 PDT 1995
# LPRng
#= File: =
#= accounting.sh =
#= =
#= Synopsis: =
#This program is called at the completion of printing a job by the OF
#filter. The accounting file will hold information about the
#completion of a job. The accounting file will have the following
#format:
#
#start -qpid -kcontrolfile -nlogin -hhost -Pprinter \
# -ppagecounter -Fformt -Ttime
#end -bpages -qpid -kcontrolfile -nlogin -hhost -Pprinter \
# -ppagecounter -Ffmt -Ttime
#
#The accounting program will be called with the following parameters
#
#program -bpages -qpid -kcontrolfile \
# -nlogin -hhost -Pprinter -ppagecounter -Fformt '-Ttime' accoutingfile
#$file1 = "/var/spool/lprng/PRINTER_ACCOUNTING_LOG";
$file1 = "/var/spool/lpd/ACCT_LOG";
#$file2 = "/auto/global/lprng/log/acct_log";
$file2 = "/auto/global/lprng/log/acct_log";
$debugfile = "/auto/global/lprng/log/acct_log.debug";
$debug = 0;
$pages = "";
$pid = "";
$controlfile = "";
$login = "";
$host = "";
$printer = "";
$pagecounter = "";
$format = "";
$time = "";
$accountingfile = "";
$mode = "";
$zoption = "";
foreach ( @ARGV ) {
if (($mode eq "") and (/^start$/ or /^end$/)) {
$mode = $_;
}
elsif (/^-b/) {
$pages = substr($_,2) if ($pages eq "");
}
elsif (/^-h/) {
if ($host eq "") {
$host = substr($_,2);
$host =~ s/\.cs\.duke\.edu$//;
}
}
elsif (/^-k/) {
$controlfile = substr($_,2) if ($controlfile eq "");
}
elsif (/^-n/) {
$login = substr($_,2) if ($login eq "");
}
elsif (/^-p/) {
$pagecounter = substr($_,2) if ($pagecounter eq "");
}
elsif (/^-q/) {
$pid = substr($_,2) if ($pid eq "");
}
elsif (/^-t/) {
$time = substr($_,2) if ($time eq "");
}
elsif (/^-F/) {
$format = substr($_,2) if ($format eq "");
}
elsif (/^-P/) {
$printer = substr($_,2) if ($printer eq "");
}
elsif (/^-Z/) {
$zoption = substr($_,2) if ($zoption eq "");
}
elsif (/^-/) {
}
else {
$accountingfile = $_;
#last;
}
}
$line =
"ifhp|$login|$pid|$host|$printer|$format|$zoption|$pagecounter|$pages|$time\n";
if ($mode eq "start") {
exit 0;
}
if ($debug) {
open FH, ">>$debugfile" or die "cannot open \"$debugfile\".";
print FH "\n";
foreach ( @ARGV ) {
print FH "$_\n";
}
print FH "mode = $mode\n";
print FH "accountingfile = $accountingfile\n";
close FH;
#exit 0;
}
#elsif ($mode eq "start") {
# exit 0;
#}
if ($file1 ne "") {
open FH, ">>$file1" or die "cannot open \"$file1\".";
print FH $line;
close FH;
}
if ($file2 ne "") {
open FH, ">>$file2" or die "cannot open \"$file2\".";
print FH $line;
close FH;
}
exit 0;
#!/usr/local/bin/perl
# @(#) pracct 1.18@(#) (Printer Accounting Script) 04/19/01 11:56:54
#use English;
use Getopt::Std;
#use FileHandle;
#use Time::CTime;
#autoflush STDERR 1;
#autoflush STDOUT 1;
$dflt_printer_log = "/auto/global/lprng/log/acct_log";
# might need to skip some printers for various reasons;
# this is a space separated list;
#
# pr59 is the SPARCprinter E, which has trouble with accounting;
# pr118 is currently in D.Singer's office for testing;
#
#$printers_to_ignore = "pr59 pr118";
$printers_to_ignore = "pr59";
# Let's setup some labels for the printers;
# each entry is:
# "dns_name:short_name:long_name"
#
@printer_names = (
"pr10:312p:312 (private)",
"pr59:135:135 (public)",
"pr62:331:331 (public)",
"pr64:128:128 (public)",
"pr65:211:211 (public)",
"pr66:312:312 (public)",
"pr67:315p:315 (private)",
"pr68:329p:329 (private)",
"pr69:109:109 (public)",
"pr70:240:240 (public)",
"pr87:230:230 (public)",
"pr95:314p:314 (private)",
"pr99:204p:204 (private)",
"pr118:127p:127 (private)",
"pr151:108:108 (public)",
"pr211: 04: 04 (public)",
"pr213:211p:211 (private)",
"pr232:022:022 (public)"
);
# set up some arrays with this data
for $I (@printer_names) {
($i,$s,$l) = split ":", $I;
$short_printer_names{$i} = $s;
$long_printer_names{$s} = $l;
}
# the usage message
$usage_message = qq|
USAGE: pracct [-bhnptu] [-i user] [-L file]
[ -u Show accounting by user ]
[ -p Show accounting by printer ]
[ -i Show accounting for a specific user ]
[ -t Show page total only ]
[ -b Omit headers and totals, and separate fields with a tab ]
[ -n Sort by number of pages instead of by user or printer ]
[ -L Specify the log file ]
[ -h Print this help message and exit ]
e.g.
pracct -u -i \$USER
|;
# parse the command line options
getopts('bhi:L:nptu');
# Pass the usage message if we are called with -h
if ($opt_h){
print "$usage_message\n";
exit 0;
}
# -i implies -u
if ($opt_i) {
$opt_u = 1;
}
# If we do not have exactly one primary option, print a uages message
if ( (($opt_p + $opt_u + $opt_t) != 1) ){
print "$usage_message\n";
exit 1;
}
# open the printer log - this should be in an automounted directory
if ($opt_L eq "") {
$printer_log = $dflt_printer_log;
}
else {
$printer_log = $opt_L;
}
open FH, "< $printer_log" or die "cannot open $printer_log";
# Grab all of the relevant data.
while(<FH>){
($junk,$user,$pid,$machine,$printer,$type,$options,$pagecount,$pages,$date) = split
"\\|";
#ifhp:doyle:978:boa:pr66:o:simplex:19104:10:2001-01-31-15:25:19.028
#ifhp:priya:937:garter:pr232:o:duplex:24418:16:2001-01-31-15:26:18.591
# Note: the following seems to no longer apply, all records at
# this time contain type "o";
# make sure the entries for the HP4s do not have two entries
# The hps have two entries like the following:
# junk:thomasp:29438:lepus.cs.duke.edu:pr67:f:duplex:171153:1
# junk:thomasp:29430:lepus.cs.duke.edu:pr67:o:duplex:171153:1
# only one of them should count.
#next unless $type eq "f";
# also, skip certain printers altogether
next if ($printers_to_ignore =~ /\b$printer\b/);
## # Make sure that we are fair. If the used duplex then they
## # only get half of the pages printed.
## if ($options eq "duplex") {
## $pages_mod = $pages % 2;
## if ($pages_mod =~ /1/){
## $extra_page = 1;
## }
## $real_pages = int($pages/2) + $extra_page;
## }
## else {
## $real_pages = $pages;
## }
## # For duplex, only count 1.5 for each front/back pair
## if ($options =~ /\bduplex\b/) {
## $real_pages = ( int($pages / 2) * 1.5 ) + ( $pages % 2 );
## }
## else {
## $real_pages = $pages;
## }
# we're going to make two separate page counts:
# physical sheets (_sheets_), and printed sides (_pages_)
if ($options =~ /\bduplex\b/) {
$real_sheets = int($pages / 2) + ( $pages % 2 );
}
else {
$real_sheets = $pages;
}
$real_pages = $pages;
# add the pages into the totals for each printer and/or user
# and keep grand totals
if ($user ne "") {
$user_total_pages{$user} += $real_pages;
$user_total_sheets{$user} += $real_sheets;
}
if ($printer ne "") {
$printer_total_sheets{$short_printer_names{$printer}} += $real_sheets;
$printer_total_pages{$short_printer_names{$printer}} += $real_pages;
$total_printed_pages += $real_pages;
$total_printed_sheets += $real_sheets;
}
}
# Get the creation time for the file.
#($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime,
$blksize, $blocks) = stat FH;
#@File_created = split /\s/,ctime($ctime);
#@Time_now = split /\s+/,ctime(time);
close FH;
# print qq|
#
# Printer usage from $File_created[0] $File_created[1] $File_created[3] to
$Time_now[0] $Time_now[1] $Time_now[2]\n\n|;
# user page accounting report
if ($opt_u) {
if (!$opt_b) {
#$fmt1 = "%-8s %5s %7s\n";
#$fmt2 = "%-8s %5d %3s\n";
#$fmt3 = "%-8s %5d\n";
$fmt1 = "%-8s %6s %7s %6s %7s\n";
$fmt2 = "%-8s %6d %3s %6d %3s\n";
$fmt3 = "%-8s %6d %6d\n";
#printf ($fmt1,"User","Pages","Percent");
#printf ($fmt1,"--------","-----","-------");
printf ($fmt1,"User","Sheets","Percent","Pages","Percent");
printf ($fmt1,"--------","------","-------","------","-------");
}
else {
#$fmt2 = "%s\t%d\t%s\n";
$fmt2 = "%s\t%d\t%s\t%d\t%s\n";
}
$I = 0;
foreach $users (sort keys %user_total_sheets) {
$total_user_pages_value = $user_total_pages{$users};
$total_user_sheets_value = $user_total_sheets{$users};
$pages_percentage = sprintf "%.1f",
100*($total_user_pages_value/$total_printed_pages);
$sheets_percentage = sprintf "%.1f",
100*($total_user_sheets_value/$total_printed_sheets);
# individual user?
if ($opt_i && $users ne $opt_i) {
next;
}
$line = sprintf
($fmt2,$users,$total_user_sheets_value,$sheets_percentage,$total_user_pages_value,$pages_percentage);
if ($opt_n) {
$lines[$I++] = $line;
next;
}
print $line;
}
if ($opt_n) {
@newlines = sort usort @lines;
for $I (@newlines) {
print $I;
}
}
if (!$opt_i && !$opt_b) {
print "\n";
printf ($fmt3,"Total:",$total_printed_sheets,$total_printed_pages);
}
}
# If we are presented with a request for printer info
if ($opt_p) {
if (!$opt_b) {
#$fmt1 = "%-20s %6s\n";
#$fmt2 = "%-20s %6d\n";
#$fmt3 = "%-20s %6d\n";
$fmt1 = "%-20s %6s %6s\n";
$fmt2 = "%-20s %6d %6d\n";
$fmt3 = "%-20s %6d %6d\n";
#printf ($fmt1,"Printer","Sheets");
#printf ($fmt1,"----------","------");
printf ($fmt1,"Printer","Sheets","Pages");
printf ($fmt1,"----------","------","------");
}
else {
#$fmt2 = "%s\t%d\n";
$fmt2 = "%s\t%d\t%d\n";
}
$I = 0;
foreach $printer_name (sort keys %printer_total_sheets) {
$total_printer_sheets_value = $printer_total_sheets{$printer_name};
$total_printer_pages_value = $printer_total_pages{$printer_name};
$line = sprintf
($fmt2,$long_printer_names{$printer_name},$total_printer_sheets_value,$total_printer_pages_value);
if ($opt_n) {
$lines[$I++] = $line;
next;
}
print $line;
}
if ($opt_n) {
@newlines = sort psort @lines;
for $I (@newlines) {
print $I;
}
}
if (!$opt_b) {
print "\n";
#printf ($fmt3,"Total:",$total_printed_pages);
#printf ($fmt3,"Total:",$total_printed_sheets);
printf ($fmt3,"Total:",$total_printed_sheets,$total_printed_pages);
}
}
# If we are presented with a request for page total only
if (defined $opt_t) {
#print "Total:\t$total_printed_pages\n";
#print "Total:\t$total_printed_sheets\n";
print "Total:\t$total_printed_sheets\t$total_printed_pages\n";
}
# user pages sort
sub usort {
$_a = $a;
$_b = $b;
$_au = $a;
$_bu = $b;
$_au =~ s/\s.*//;
$_bu =~ s/\s.*//;
$_a =~ s/\w+\s+//;
$_b =~ s/\w+\s+//;
$_a =~ s/\s+.*//;
$_b =~ s/\s+.*//;
$_b <=> $_a or $_bu cmp $_au;
}
# printer pages sort
sub psort {
if ($opt_b) {
$_a = $a;
$_b = $b;
$_au = $a;
$_bu = $b;
$_au =~ s/\t.*//;
$_bu =~ s/\t.*//;
$_a =~ s/.*\t//;
$_b =~ s/.*\t//;
}
else {
$_a = substr($a,16);
$_b = substr($b,16);
$_au = substr($a,1,15);
$_bu = substr($b,1,15);
$_au =~ s/ +$//;
$_bu =~ s/ +$//;
$_a =~ s/\s+//;
$_a =~ s/\s+.*//;
$_b =~ s/\s+//;
$_b =~ s/\s+.*//;
}
$_b <=> $_a or $_bu cmp $_au;
}
exit 0;