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.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||||
|
import ca.uhn.fhirtest.interceptor.AnalyticsInterceptor;
|
||||||
import ca.uhn.fhirtest.joke.HolyFooCowInterceptor;
|
import ca.uhn.fhirtest.joke.HolyFooCowInterceptor;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -24,6 +25,16 @@ public class CommonConfig {
|
||||||
return retVal;
|
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.
|
* 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) {
|
} catch (Exception e) {
|
||||||
ourLog.error("Failure during startup", e);
|
ourLog.error("Failure during startup", e);
|
||||||
}
|
}
|
||||||
server.stop();
|
|
||||||
|
|
||||||
// base = "http://fhir.healthintersections.com.au/open";
|
// base = "http://fhir.healthintersections.com.au/open";
|
||||||
// base = "http://spark.furore.com/fhir";
|
// base = "http://spark.furore.com/fhir";
|
||||||
|
|
Loading…
Reference in New Issue