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;

Reply via email to