com.ajjpj.asysmon.datasink.offloadhttpjson.AHttpJsonOffloadingDataSink Maven / Gradle / Ivy
package com.ajjpj.asysmon.datasink.offloadhttpjson;
import com.ajjpj.abase.collection.mutable.ASoftlyLimitedQueue;
import com.ajjpj.asysmon.ASysMonApi;
import com.ajjpj.asysmon.config.ASysMonConfig;
import com.ajjpj.asysmon.config.log.ASysMonLogger;
import com.ajjpj.asysmon.data.AHierarchicalDataRoot;
import com.ajjpj.asysmon.data.AScalarDataPoint;
import com.ajjpj.asysmon.datasink.ADataSink;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author arno
*/
public class AHttpJsonOffloadingDataSink implements ADataSink {
public static final int NO_DATA_SLEEP_MILLIS = 10;
private static final ASysMonLogger log = ASysMonLogger.get(AHttpJsonOffloadingDataSink.class);
private final ASysMonConfig config;
//TODO how many concurrent HTTP connections does this provide? --> configure!
private final CloseableHttpClient httpClient = HttpClients.createDefault(); //TODO make this configurable
private final URI uri;
private final String sender;
private final String senderInstance;
private final ASoftlyLimitedQueue traceQueue;
private final ASoftlyLimitedQueue scalarQueue;
private final ExecutorService offloadingThreadPool;
private final ScheduledExecutorService scalarMeasurementPool;
private volatile boolean isShutDown = false;
public AHttpJsonOffloadingDataSink(final ASysMonApi sysMon, String uri, String sender, String senderInstance, int traceQueueSize, int scalarQueueSize, int numOffloadingThreads, int scalarMeasurementFrequencyMillis) {
this.config = sysMon.getConfig();
this.uri = URI.create(uri);
this.sender = sender;
this.senderInstance = senderInstance;
this.traceQueue = new ASoftlyLimitedQueue(traceQueueSize, new DiscardedLogger("trace queue overflow - discarding oldest trace"));
this.scalarQueue = new ASoftlyLimitedQueue(scalarQueueSize, new DiscardedLogger("environment queue overflow - discarding oldest data"));
offloadingThreadPool = Executors.newFixedThreadPool(numOffloadingThreads);
for(int i=0; i send a unique identifier with every *atom* (trace, environment measurement, ...)
//TODO re-enter the data into the queues when the server returns a non-OK http response code
traceQueue.add(data);
}
private void doOffload() throws Exception {
final List traces = new ArrayList();
AHierarchicalDataRoot candidate;
while ((candidate = traceQueue.poll()) != null) { //TODO limit number per HTTP request?!
traces.add(candidate);
}
final List scalars = new ArrayList();
AScalarDataPoint scalar;
while ((scalar = scalarQueue.poll()) != null) { //TODO limit number per HTTP request?
scalars.add(scalar);
}
if(traces.isEmpty() && scalars.isEmpty()) {
Thread.sleep(NO_DATA_SLEEP_MILLIS);
}
else {
try {
final HttpPost httpPost = new HttpPost(uri);
final AJsonOffloadingEntity entity = new AJsonOffloadingEntity(traces, scalars, sender, senderInstance);
httpPost.setEntity(entity);
final CloseableHttpResponse response = httpClient.execute(httpPost);
try {
//TODO response with commands for monitoring this app?!
} finally {
response.close();
}
}
catch(Exception exc) {
log.error(exc);
// add the data to the queue again for later retry
scalarQueue.addAll(scalars);
System.out.println(" == " + scalarQueue);
// wait a grace period for the situation to improve
Thread.sleep(5000); //TODO make this configurable
}
}
}
@Override public void shutdown() throws IOException {
isShutDown = true;
httpClient.close();
scalarMeasurementPool.shutdown();
offloadingThreadPool.shutdown();
}
private static class DiscardedLogger implements Runnable {
private final String msg;
private DiscardedLogger(String msg) {
this.msg = msg;
}
@Override public void run() {
log.warn(msg);
}
}
private class OffloadingRunnable implements Runnable {
@Override public void run() {
while(! isShutDown) {
try {
doOffload();
} catch (Exception e) {
e.printStackTrace(); //TODO exception handling
}
}
}
}
}