package org.archive.wayback.webapp;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PerfStats
{
private static final Logger LOGGER = Logger.getLogger(
PerfStats.class.getName());
/**
* output format constants.
*/
public enum OutputFormat {
BRACKET,
JSON
};
public static class PerfStatEntry
{
String name;
long start;
long total;
int count;
boolean isErr;
public PerfStatEntry(String name)
{
this.name = name;
clear();
}
public void clear()
{
start = 0;
total = 0;
count = 0;
isErr = false;
}
public void startNow()
{
if (start > 0) {
isErr = true;
}
start = System.currentTimeMillis();
}
public long endNow()
{
long elapsed = 0;
if (start > 0) {
long end = System.currentTimeMillis();
elapsed = (end - start);
count++;
} else {
isErr = true;
}
start = 0;
total += elapsed;
return elapsed;
}
public String toString()
{
// Skip perf stats that haven't been set at all
if (count == 0 && total == 0) {
return "";
}
if (start > 0) {
isErr = true;
}
StringBuilder builder = new StringBuilder(name);
builder.append(": ");
builder.append(total);
// builder.append(" ");
// builder.append(count);
if (isErr) {
builder.append(" ERR");
}
return builder.toString();
}
public long getTotal()
{
return total;
}
}
static ThreadLocal<Map<String, PerfStatEntry>> perfStats = new ThreadLocal<Map<String, PerfStatEntry>>()
{
@Override
protected Map<String, PerfStatEntry> initialValue() {
return new TreeMap<String, PerfStatEntry>();
}
};
static ThreadLocal<PerfStatEntry> lastEntry = new ThreadLocal<PerfStatEntry>()
{
@Override
protected PerfStatEntry initialValue() {
return null;
}
};
public static PerfStatEntry get(String statName)
{
PerfStatEntry entry = lastEntry.get();
if ((entry != null) && entry.name.equals(statName)) {
return entry;
}
entry = perfStats.get().get(statName);
if (entry == null) {
entry = new PerfStatEntry(statName);
perfStats.get().put(statName, entry);
}
lastEntry.set(entry);
return entry;
}
public static long getTotal(Enum<?> stat) {
return getTotal(stat.toString());
}
public static long getTotal(String statName) {
PerfStatEntry entry = get(statName);
return entry != null ? entry.getTotal() : 0;
}
public static void clearAll()
{
lastEntry.set(null);
for (PerfStatEntry entry : perfStats.get().values()) {
entry.clear();
}
}
public static void timeStart(Enum<?> stat)
{
timeStart(stat.toString());
}
public static void timeStart(String statName)
{
get(statName).startNow();
}
public static long timeEnd(Enum<?> stat)
{
return timeEnd(stat.toString(), true);
}
public static long timeEnd(Enum<?> stat, boolean log)
{
return timeEnd(stat.toString(), log);
}
public static long timeEnd(String statName)
{
return timeEnd(statName, true);
}
public static long timeEnd(String statName, boolean log)
{
long elapsed = get(statName).endNow();
if (log && LOGGER.isLoggable(Level.INFO)) {
StringBuilder builder = new StringBuilder();
builder.append("WB-PERF\t");
builder.append(statName);
builder.append("\t");
builder.append(elapsed);
LOGGER.info(builder.toString());
}
return elapsed;
}
public static String getAllStats() {
return getAllStats(OutputFormat.BRACKET);
}
/**
* Format all stats in the format specified.
* @param format serialization format
* @return serialized stats
*/
public static String getAllStats(OutputFormat format) {
StringBuilder sb = new StringBuilder();
boolean first = true;
Collection<PerfStatEntry> stats = perfStats.get().values();
switch (format) {
case JSON:
sb.append('{');
for (PerfStatEntry entry : stats) {
if (entry.count > 0) {
if (first) {
first = false;
} else {
sb.append(',');
}
sb.append('"').append(entry.name).append("\":");
if (entry.isErr)
sb.append("null");
else
sb.append(entry.total);
}
}
sb.append('}');
break;
default:
sb.append("[");
for (PerfStatEntry entry : stats) {
if (entry.count > 0) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(entry.toString());
}
}
sb.append("]");
break;
}
return sb.toString();
}
}