JAVA : Statistics Class

Another name for it would be Counter class.

How many times you did this ?

int databaseUpdateCounter=0;
.
{
.
     databaseUpdateCounter++;
.
}
.
.
System.out.println( "databaseUpdateCounter"+ databaseUpdateCounter);

you only need to follow up on the count of a certain operation.

And then you needed to count something else, and kept on adding counterVariables ?!

int databaseUpdateCounter=0;

int databaseInsertCounter=0;

int databaseDeleteCounter=0;
.
{
.
databaseUpdateCounter++;
.

databaseInsertCounter++;

. . .

.

.
}
.
.
System.out.println( "databaseUpdateCounter"+ databaseUpdateCounter);

. . .

Well, That’s what  you learned OO programming for.
I’m using a Statistics Class that has an Internal HashMap and some nice methods for administrating and displaying the counters you add to it.

/*
*  This is the Stats Class
*/
package x.y.z.utils;

import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;

/**
*
* @author Ahmed Maklad
*/
public class MyStats {
private static final HashMap<String,BigInteger> statMap=new HashMap<String,BigInteger>();
private static final HashMap<String,Long> statLastUpdateMap=new HashMap<String,Long>();
private static final HashMap<String,Double> statTotalUpdateMap=new HashMap<String,Double>();
static{
//
}

    // the typical Counter++ method
public static void inc(String statKey){
BigInteger newVal;
if (statMap.containsKey(statKey)){
newVal=statMap.get(statKey).add( BigInteger.valueOf(1)) ;
}else{
newVal=BigInteger.valueOf(1);
}
set(statKey,newVal.intValue());
}

    // in-case you want to jump-start or reset the counter
public static void set(String statKey,int val){
statMap.put(statKey, BigInteger.valueOf(val) );
// Rate MyStats
double totalDuration ;
if (statLastUpdateMap.containsKey(statKey)){
totalDuration =  statLastUpdateMap.get(statKey);
totalDuration = System.currentTimeMillis() - totalDuration;
totalDuration= totalDuration+statTotalUpdateMap.get(statKey);
}else{
totalDuration = Long.valueOf(0L);
}
statTotalUpdateMap.put(statKey, totalDuration);
statLastUpdateMap.put(statKey, System.currentTimeMillis() );
}

    // get the current status of a Counter
public static int get(String statKey){
int returnVal=0;
if (statMap.containsKey(statKey)){
returnVal = statMap.get(statKey ).intValue();
}else{
set(statKey,0);
returnVal=0;
}
return returnVal;
}

    // get a report about the counters and their update rate
public static String getStats(){
StringBuilder resultText=new StringBuilder();
resultText.append ("******************* START STATISTICS **************************\n");
resultText.append ( String.format( "%-40s : %6s : %6s : %6s : %6s \n", "key","Count","ticks/sec","Total Time","Last Update") );
for (String key:statMap.keySet()){
long count;
double rate;
if (statMap.get(key).intValue()>0 ) {
count=statMap.get(key).longValue();
}else{
count=1;
}
rate= statTotalUpdateMap.get(key).longValue()  / Long.valueOf(count).doubleValue() /1000;
resultText.append (
String.format( "%-40s : %6d : %9.2f : %10.2f : %6s \n",
key,
count,
rate ,
statTotalUpdateMap.get(key)/1000,
new Date( statLastUpdateMap.get(key) ) )
);
}
resultText.append ("******************* END STATISTICS **************************");
return resultText.toString();
}
}

How to use this class in your code:

  • Simply invoke MyStats.inc(“COUNTER_NAME”); and it will be added to your MyStats class.
  • Since all methods are static, you don’t need to instantiate it.
  • The class makes a simple calculation between each update of a counter and calculates the update rate.
  • At the end of your code invoke MyStats.getStats() method to get a full report about counters and their update rates.
public boolean updateAddressDb(AddressRecord spoi){
. . .
MyStats.inc("DB_UPDATE_ADDRRECORD");
}
public boolean deleteAddressDb(AddressRecord spoi){
. . .
MyStats.inc("DB_DELETE_ADDRRECORD");
}

public boolean InsertAddressDb(AddressRecord spoi){
. . .
  try{
      MyStats.inc("DB_INSERT_ADDRRECORD");
  } catch(Exception ex){
      . . .
      MyStats.inc(ex.getMessage());
  }
}
public static void main(String [] args){
 ...
AddressRecord adr=new AddressRecord ();
. . .
 . . .
// do your Business
InsertAddressDb(adr);
. . .
updateAddressDb(adr)
. . .
deleteAddressDb(adr)
...
// get the stats
System.out.println (MyStats.getStats);
}

The output should be something like this:

******************* START STATISTICS **************************
 key                                     :  Count : ticks/sec : Total Time : Last Update
 DB_UPDATE_ADDRRECORD                    :     30 :      3.44 :     103.06 : Fri Aug 03 12:28:26 CEST 2012
 DB_INSERT_ADDRRECORD                    :     30 :      3.44 :     103.06 : Fri Aug 03 12:28:24 CEST 2012
 DB_DELETE_ADDRRECORD                    :     29 :      3.44 :     103.06 : Fri Aug 03 12:28:23 CEST 2012
 Exception Xyz                           :      1 :      1.78 :       3.56 : Fri Aug 03 12:27:04 CEST 2012
 ******************* END STATISTICS **************************

I don’t see any reason why this couldn’t be also useful in other languages like PHP and Perl … etc.
Off course there is plenty space of improvement in the class, please feel free to comment with your suggestions and improvements.

If you like this tip, please use the stars below to rate this article or comment.