Add analytics to fhirtest.uhn.ca
This commit is contained in:
parent
c7d191dc38
commit
207ba872fa
|
@ -5,6 +5,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhirtest.interceptor.AnalyticsInterceptor;
|
||||
import ca.uhn.fhirtest.joke.HolyFooCowInterceptor;
|
||||
|
||||
@Configuration
|
||||
|
@ -24,6 +25,16 @@ public class CommonConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interceptor pings Google Analytics with usage data for the server
|
||||
*/
|
||||
@Bean
|
||||
public IServerInterceptor analyticsInterceptor() {
|
||||
AnalyticsInterceptor retVal = new AnalyticsInterceptor();
|
||||
retVal.setAnalyticsTid("UA-1395874-6");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
package ca.uhn.fhirtest.interceptor;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class AnalyticsInterceptor extends InterceptorAdapter {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AnalyticsInterceptor.class);
|
||||
|
||||
private String myAnalyticsTid;
|
||||
private int myCollectThreshold = 100000;
|
||||
private final LinkedList<AnalyticsEvent> myEventBuffer = new LinkedList<AnalyticsEvent>();
|
||||
private String myHostname;
|
||||
private HttpClient myHttpClient;
|
||||
private long myLastFlushed;
|
||||
private long mySubmitPeriod = 60000;
|
||||
private int mySubmitThreshold = 1000;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public AnalyticsInterceptor() {
|
||||
myHttpClient = new ApacheRestfulClientFactory().getNativeHttpClient();
|
||||
try {
|
||||
myHostname = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
myHostname = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
if (myHttpClient instanceof CloseableHttpClient) {
|
||||
IOUtils.closeQuietly((CloseableHttpClient) myHttpClient);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doFlush() {
|
||||
List<AnalyticsEvent> eventsToFlush;
|
||||
synchronized (myEventBuffer) {
|
||||
int size = myEventBuffer.size();
|
||||
if (size > 20) {
|
||||
size = 20;
|
||||
}
|
||||
eventsToFlush = new ArrayList<AnalyticsEvent>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
AnalyticsEvent nextEvent = myEventBuffer.pollFirst();
|
||||
if (nextEvent != null) {
|
||||
eventsToFlush.add(nextEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (AnalyticsEvent next : eventsToFlush) {
|
||||
b.append("v=1");
|
||||
b.append("&tid=").append(myAnalyticsTid);
|
||||
|
||||
b.append("&t=event");
|
||||
b.append("&an=").append(UrlUtil.escape(myHostname)).append('+').append(UrlUtil.escape(next.getApplicationName()));
|
||||
b.append("&ec=").append(next.getResourceName());
|
||||
b.append("&ea=").append(next.getRestOperation());
|
||||
|
||||
b.append("&cid=").append(next.getClientId());
|
||||
b.append("&uip=").append(UrlUtil.escape(next.getSourceIp()));
|
||||
b.append("&ua=").append(UrlUtil.escape(next.getUserAgent()));
|
||||
b.append("\n");
|
||||
}
|
||||
|
||||
String contents = b.toString();
|
||||
HttpPost post = new HttpPost("https://www.google-analytics.com/batch");
|
||||
post.setEntity(new StringEntity(contents, ContentType.APPLICATION_FORM_URLENCODED));
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
response = (CloseableHttpResponse) myHttpClient.execute(post);
|
||||
ourLog.trace("Analytics response: {}", response);
|
||||
ourLog.info("Flushed {} analytics events and got HTTP {} {}", eventsToFlush.size(), response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failed to submit analytics:", e);
|
||||
} finally {
|
||||
if (response != null) {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 5000)
|
||||
public synchronized void flush() {
|
||||
int pendingEvents;
|
||||
synchronized (myEventBuffer) {
|
||||
pendingEvents = myEventBuffer.size();
|
||||
}
|
||||
|
||||
if (pendingEvents == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - myLastFlushed > mySubmitPeriod) {
|
||||
doFlush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingEvents >= mySubmitThreshold) {
|
||||
doFlush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theRequest) {
|
||||
ServletRequestDetails details = (ServletRequestDetails) theRequest.getRequestDetails();
|
||||
|
||||
// Make sure we only send one event per request
|
||||
if (details.getUserData().containsKey(getClass().getName())) {
|
||||
return;
|
||||
}
|
||||
details.getUserData().put(getClass().getName(), "");
|
||||
|
||||
String sourceIp = details.getHeader("x-forwarded-for");
|
||||
if (isBlank(sourceIp)) {
|
||||
sourceIp = details.getServletRequest().getRemoteAddr();
|
||||
}
|
||||
if (sourceIp.contains(", ")) {
|
||||
sourceIp = sourceIp.substring(0, sourceIp.indexOf(", "));
|
||||
}
|
||||
|
||||
AnalyticsEvent event = new AnalyticsEvent();
|
||||
event.setSourceIp(sourceIp);
|
||||
event.setRestOperation(theOperation);
|
||||
event.setUserAgent(details.getHeader("User-Agent"));
|
||||
event.setApplicationName(details.getServletRequest().getServletPath());
|
||||
event.setRestOperation(theOperation);
|
||||
event.setResourceName(defaultIfBlank(details.getResourceName(), "SERVER"));
|
||||
event.setClientId(UUID.randomUUID().toString());
|
||||
|
||||
synchronized (myEventBuffer) {
|
||||
if (myEventBuffer.size() > myCollectThreshold) {
|
||||
ourLog.warn("Not collecting analytics on request! Event buffer has {} items in it", myEventBuffer.size());
|
||||
}
|
||||
myEventBuffer.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnalyticsTid(String theAnalyticsTid) {
|
||||
myAnalyticsTid = theAnalyticsTid;
|
||||
}
|
||||
|
||||
public static class AnalyticsEvent {
|
||||
private String myApplicationName;
|
||||
private String myClientId;
|
||||
private String myResourceName;
|
||||
private RestOperationTypeEnum myRestOperation;
|
||||
private String mySourceIp;
|
||||
|
||||
private String myUserAgent;
|
||||
|
||||
public String getApplicationName() {
|
||||
return myApplicationName;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return myClientId;
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
return myResourceName;
|
||||
}
|
||||
|
||||
public RestOperationTypeEnum getRestOperation() {
|
||||
return myRestOperation;
|
||||
}
|
||||
|
||||
public String getSourceIp() {
|
||||
return mySourceIp;
|
||||
}
|
||||
|
||||
public String getUserAgent() {
|
||||
return myUserAgent;
|
||||
}
|
||||
|
||||
public void setApplicationName(String theApplicationName) {
|
||||
myApplicationName = theApplicationName;
|
||||
}
|
||||
|
||||
public void setClientId(String theClientId) {
|
||||
myClientId = theClientId;
|
||||
}
|
||||
|
||||
public void setResourceName(String theResourceName) {
|
||||
myResourceName = theResourceName;
|
||||
}
|
||||
|
||||
public void setRestOperation(RestOperationTypeEnum theRestOperation) {
|
||||
myRestOperation = theRestOperation;
|
||||
}
|
||||
|
||||
public void setSourceIp(String theSourceIp) {
|
||||
mySourceIp = theSourceIp;
|
||||
}
|
||||
|
||||
public void setUserAgent(String theUserAgent) {
|
||||
myUserAgent = theUserAgent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -49,7 +49,6 @@ public class UhnFhirTestApp {
|
|||
} catch (Exception e) {
|
||||
ourLog.error("Failure during startup", e);
|
||||
}
|
||||
server.stop();
|
||||
|
||||
// base = "http://fhir.healthintersections.com.au/open";
|
||||
// base = "http://spark.furore.com/fhir";
|
||||
|
|
Loading…
Reference in New Issue