Skip to content

Commit

Permalink
Update query-metric service to generate HTML response via Spring MVC (#6
Browse files Browse the repository at this point in the history
)
  • Loading branch information
kevinrr888 authored and billoley committed May 9, 2024
1 parent 10289d6 commit 1b56d17
Show file tree
Hide file tree
Showing 30 changed files with 1,063 additions and 791 deletions.
5 changes: 5 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.21</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
package datawave.microservice.querymetric;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.annotation.JsonIgnore;

import datawave.microservice.querymetric.BaseQueryMetric.PageMetric;
import datawave.webservice.HtmlProvider;
import datawave.webservice.result.BaseResponse;

public abstract class BaseQueryMetricListResponse<T extends BaseQueryMetric> extends BaseResponse implements HtmlProvider {
public abstract class BaseQueryMetricListResponse<T extends BaseQueryMetric> extends BaseResponse {

private static final long serialVersionUID = 1L;
private static final String TITLE = "Query Metrics";
private static final String EMPTY = "";
@XmlElementWrapper(name = "queryMetrics")
@XmlElement(name = "queryMetric")
protected List<T> result = null;
Expand All @@ -35,22 +22,16 @@ public abstract class BaseQueryMetricListResponse<T extends BaseQueryMetric> ext
protected boolean isGeoQuery = false;
@XmlTransient
private boolean administratorMode = false;
private String JQUERY_INCLUDES;
protected String BASE_URL = "/DataWave/Query/Metrics";

public BaseQueryMetricListResponse() {
setHtmlIncludePaths(new HashMap<>());
}
@XmlTransient
protected String header;
@XmlTransient
protected String footer;

public void setHtmlIncludePaths(Map<String,String> pathMap) {
// @formatter:off
JQUERY_INCLUDES =
"<script type='text/javascript' src='" + pathMap.getOrDefault("jquery", "") + "/jquery.min.js'></script>\n";
// @formatter:on
}
protected String basePath = "/querymetric";
protected String viewName = "querymetric";

public void setBaseUrl(String baseUrl) {
this.BASE_URL = baseUrl;
public void setBasePath(String basePath) {
this.basePath = basePath;
}

private static String numToString(long number) {
Expand Down Expand Up @@ -90,131 +71,17 @@ public void setGeoQuery(boolean geoQuery) {
isGeoQuery = geoQuery;
}

@JsonIgnore
@XmlTransient
@Override
public String getTitle() {
return TITLE;
public void setViewName(String viewName) {
this.viewName = viewName;
}

@JsonIgnore
@XmlTransient
@Override
public String getPageHeader() {
return getTitle();
}
abstract public ModelAndView createModelAndView();

@JsonIgnore
@XmlTransient
@Override
public String getHeadContent() {
if (isGeoQuery) {
// @formatter:off
return JQUERY_INCLUDES +
"<script type='text/javascript'>" +
"$(document).ready(function() {" +
" var currentUrl = window.location.href.replace(/\\/+$/, '');" +
" var queryHeader = document.getElementById(\"query-header\").innerHTML;" +
" queryHeader = queryHeader + '<br>(<a href=\"' + currentUrl + '/map\">map</a>)';" +
" document.getElementById(\"query-header\").innerHTML = queryHeader;" +
"});" +
"</script>";
// @formatter: on
} else {
return EMPTY;
}
public void setHeader(String header) {
this.header = header;
}

@JsonIgnore
@XmlTransient
@Override
public String getMainContent() {
StringBuilder builder = new StringBuilder();

builder.append("<table>\n");
builder.append("<tr>\n");
builder.append("<th>Visibility</th><th>Query Date</th><th>User</th><th>UserDN</th><th>Proxy Server(s)</th><th>Query ID</th><th>Query Type</th>");
builder.append("<th>Query Logic</th><th id=\"query-header\">Query</th><th>Begin Date</th><th>End Date</th><th>Query Auths</th><th>Server</th>");
builder.append("<th>Query Setup Time (ms)</th><th>Query Setup Call Time (ms)</th><th>Number Pages</th><th>Number Results</th>");
builder.append("<th>Total Page Time (ms)</th><th>Total Page Call Time (ms)</th><th>Total Page Serialization Time (ms)</th>");
builder.append("<th>Total Page Bytes Sent (uncompressed)</th><th>Lifecycle</th><th>Elapsed Time</th><th>Error Code</th><th>Error Message</th>");
builder.append("\n</tr>\n");

TreeMap<Date,T> metricMap = new TreeMap<Date,T>(Collections.reverseOrder());

for (T metric : this.getResult()) {
metricMap.put(metric.getCreateDate(), metric);
}

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss");

int x = 0;
for (T metric : metricMap.values()) {
// highlight alternating rows
if (x % 2 == 0) {
builder.append("<tr class=\"highlight\" style=\"vertical-align:top;\">\n");
} else {
builder.append("<tr style=\"vertical-align:top;\">\n");
}
x++;

builder.append("<td>").append(metric.getColumnVisibility()).append("</td>");
builder.append("<td style=\"min-width:125px !important;\">").append(sdf.format(metric.getCreateDate())).append("</td>");
builder.append("<td>").append(metric.getUser()).append("</td>");
String userDN = metric.getUserDN();
builder.append("<td style=\"min-width:500px !important;\">").append(userDN == null ? "" : userDN).append("</td>");
String proxyServers = metric.getProxyServers() == null ? "" : StringUtils.join(metric.getProxyServers(), "<BR/>");
builder.append("<td>").append(proxyServers).append("</td>");
if (this.isAdministratorMode()) {
builder.append("<td><a href=\"/DataWave/Query/Metrics/user/").append(metric.getUser()).append("/").append(metric.getQueryId()).append("/")
.append("\">").append(metric.getQueryId()).append("</a></td>");
} else {
builder.append("<td><a href=\"/DataWave/Query/Metrics/id/").append(metric.getQueryId()).append("/").append("\">").append(metric.getQueryId())
.append("</a></td>");
}
builder.append("<td>").append(metric.getQueryType()).append("</td>");
builder.append("<td>").append(metric.getQueryLogic()).append("</td>");
builder.append("<td style=\"word-wrap: break-word;\">").append(StringEscapeUtils.escapeHtml4(metric.getQuery())).append("</td>");

String beginDate = metric.getBeginDate() == null ? "" : sdf.format(metric.getBeginDate());
builder.append("<td style=\"min-width:125px !important;\">").append(beginDate).append("</td>");
String endDate = metric.getEndDate() == null ? "" : sdf.format(metric.getEndDate());
builder.append("<td style=\"min-width:125px !important;\">").append(endDate).append("</td>");
String queryAuths = metric.getQueryAuthorizations() == null ? "" : metric.getQueryAuthorizations().replaceAll(",", " ");
builder.append("<td style=\"word-wrap: break-word; min-width:300px !important;\">").append(queryAuths).append("</td>");

builder.append("<td>").append(metric.getHost()).append("</td>");
builder.append("<td>").append(numToString(metric.getSetupTime())).append("</td>");
builder.append("<td>").append(numToString(metric.getCreateCallTime())).append("</td>\n");
builder.append("<td>").append(metric.getNumPages()).append("</td>");
builder.append("<td>").append(metric.getNumResults()).append("</td>");
long count = 0l;
long callTime = 0l;
long serializationTime = 0l;
long bytesSent = 0l;
for (PageMetric p : metric.getPageTimes()) {
count += p.getReturnTime();
callTime += (p.getCallTime()) == -1 ? 0 : p.getCallTime();
serializationTime += (p.getSerializationTime()) == -1 ? 0 : p.getSerializationTime();
bytesSent += (p.getBytesWritten()) == -1 ? 0 : p.getBytesWritten();
}
builder.append("<td>").append(count).append("</td>\n");
builder.append("<td>").append(numToString(callTime)).append("</td>\n");
builder.append("<td>").append(numToString(serializationTime)).append("</td>\n");
builder.append("<td>").append(numToString(bytesSent)).append("</td>\n");
builder.append("<td>").append(metric.getLifecycle()).append("</td>");
builder.append("<td>").append(metric.getElapsedTime()).append("</td>");
String errorCode = metric.getErrorCode();
builder.append("<td style=\"word-wrap: break-word;\">").append((errorCode == null) ? "" : StringEscapeUtils.escapeHtml4(errorCode)).append("</td>");
String errorMessage = metric.getErrorMessage();
builder.append("<td style=\"word-wrap: break-word;\">").append((errorMessage == null) ? "" : StringEscapeUtils.escapeHtml4(errorMessage))
.append("</td>");

builder.append("\n</tr>\n");
}

builder.append("</table>\n");

return builder.toString();

public void setFooter(String footer) {
this.footer = footer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package datawave.microservice.querymetric;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PageMetricModel extends BaseQueryMetric.PageMetric {

private NumberFormat nf = NumberFormat.getIntegerInstance();
private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss");

public PageMetricModel(BaseQueryMetric.PageMetric pageMetric) {
super(pageMetric);
}

public String getPageNumberStr() {
return numToString(getPageNumber(), 1);
}

public String getPageRequestedStr() {
return getPageRequested() > 0 ? sdf.format(new Date(getPageRequested())) : "";
}

public String getPageReturnedStr() {
return getPageReturned() > 0 ? sdf.format(new Date(getPageReturned())) : "";
}

public String getReturnTimeStr() {
return nf.format(getReturnTime());
}

public String getPageSizeStr() {
return nf.format(getPagesize());
}

public String getCallTimeStr() {
return numToString(getCallTime(), 0);
}

public String getLoginTimeStr() {
return numToString(getLoginTime(), 0);
}

public String getSerializationTimeStr() {
return numToString(getSerializationTime(), 0);
}

public String getBytesWrittenStr() {
return numToString(getBytesWritten(), 0);
}

private String numToString(long number, long minValue) {
return number < minValue ? "" : nf.format(number);
}
}
Loading

0 comments on commit 1b56d17

Please sign in to comment.