package org.simpleframework.http.validate;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class Logger extends Thread implements Measurement {
private static final long KILOBYTE = 1024L;
private final StatisticsLogger logger;
private final Averager latency;
private final ThreadMXBean tmbean;
private final AtomicInteger concurrency;
private final AtomicLong errors;
private final AtomicLong received;
private final AtomicLong sent;
private final AtomicLong waiting;
private final AtomicLong connections;
private final AtomicLong bytes;
private final AtomicLong sample;
private final long sampleDuration;
private final long start;
private volatile boolean dead;
private long previousBytesSent;
private long previousResponseCount;
private long maxResponseCount;
private long minResponseCount;
public Logger(StatisticsLogger logger, AtomicInteger concurrency) {
this(logger, concurrency, 0); // don't sample periodically
}
public Logger(StatisticsLogger logger, AtomicInteger concurrency, long sampleDuration) {
this.tmbean = ManagementFactory.getThreadMXBean();
this.latency = new Averager();
this.errors = new AtomicLong();
this.received = new AtomicLong();
this.sent = new AtomicLong();
this.waiting = new AtomicLong();
this.connections = new AtomicLong();
this.bytes = new AtomicLong();
this.sample = new AtomicLong();
this.concurrency = concurrency;
this.start = System.currentTimeMillis();
this.sampleDuration = sampleDuration;
this.logger = logger;
}
public long bytesToKilo(long bytes) {
return bytes / KILOBYTE;
}
public void responseDuration(int count, long duration) {
latency.sample(duration / count);
}
public void errorOccured() {
errors.getAndIncrement();
}
public void receivedResponse(int count) {
received.addAndGet(count);
}
public void sentRequest(int count) {
sent.addAndGet(count);
}
public void threadRunning() {
waiting.getAndDecrement();
}
public void threadWaiting() {
waiting.getAndIncrement();
}
public void connectionEstablished() {
connections.getAndIncrement();
}
public void connectionTerminated() {
connections.getAndDecrement();
}
public void bytesTransferred(long byteCount) {
bytes.getAndAdd(byteCount);
}
public void kill() {
try {
dead = true;
join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
while(!dead && sampleDuration > 0) {
try {
Thread.sleep(sampleDuration); // print out performance periodically
if(!dead) { // dont print out when dead as its not accurate
sample();
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
public void sample() throws Exception {
long responseCount = received.get();
long requestsPerSample = responseCount - previousResponseCount;
// track the bytes sent
long bytesSent = bytes.get();
long bytesSentPerSecond = bytesSent - previousBytesSent;
if (requestsPerSample > maxResponseCount) {
maxResponseCount = requestsPerSample;
}
if (previousResponseCount == 0) {
minResponseCount = requestsPerSample;
} else if (requestsPerSample < minResponseCount) { // clock min when we have had valid results
minResponseCount = requestsPerSample;
}
logger.log(new LogEvent(
sample.getAndIncrement(),
System.currentTimeMillis() - start, // what time was the sample done at
requestsPerSample,
received.get(),
connections.get(),
latency.getAverage(),
latency.getMax(),
latency.getMin(),
concurrency.get(),
waiting.get(),
tmbean.getThreadCount(),
bytesToKilo(Runtime.getRuntime().freeMemory()),
bytesToKilo(Runtime.getRuntime().totalMemory()),
bytesSentPerSecond,
bytes.get()));
// remember previous count
previousResponseCount = responseCount;
previousBytesSent = bytesSent;
latency.clear();
}
}