com.linkedin.parseq.JhatHandler Maven / Gradle / Ivy
package com.linkedin.parseq;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import com.linkedin.parseq.httpclient.HttpClient;
import com.linkedin.parseq.trace.ShallowTraceBuilder;
import com.linkedin.parseq.trace.Trace;
import com.linkedin.parseq.trace.TraceBuilder;
import com.linkedin.parseq.trace.TraceRelationship;
import com.linkedin.parseq.trace.codec.json.JsonTraceCodec;
import com.ning.http.client.Response;
final class JhatHandler extends AbstractHandler {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Pattern REGEX = Pattern.compile("^.*?.*?\\s*(.*)\\s* ", Pattern.DOTALL);
private static final JsonTraceCodec CODEC = new JsonTraceCodec();
private final Engine _engine;
private final String _script;
JhatHandler(Engine engine) throws IOException {
_engine = engine;
_script = read(getClass().getClassLoader().getResourceAsStream("RecoverParSeqTracesFromHeapDump.js"));
}
private static String read(InputStream input) throws IOException {
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
return buffer.lines().collect(Collectors.joining("\n"));
}
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (target.startsWith("/jhat")) {
baseRequest.setHandled(true);
// Process request in async mode
final AsyncContext ctx = request.startAsync();
final Task> responseTask = fetchJSON(request)
.recover("handleFailure", this::handleFailure)
.andThen("writeResponseAndComplete", r -> writeResponseAndComplete(response, r, ctx));
// Execute
_engine.run(responseTask);
}
}
private void writeResponseAndComplete(HttpServletResponse response, HttpResponse r, AsyncContext ctx) throws IOException {
response.getWriter().write(r.getBody());
response.setStatus(r.getStatus());
ctx.complete();
}
private HttpResponse handleFailure(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
String stackTrace = sw.toString();
return new HttpResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error processing request:\n" + stackTrace);
}
private Task fetchJSON(HttpServletRequest request) {
String location = request.getParameter("location");
if (location == null) {
return Task.value(new HttpResponse(HttpServletResponse.SC_BAD_REQUEST, "Missing location query parameter"));
} else {
return Task.flatten(Task.callable(() -> oqlGetTask(location)))
.map("processOQLResponse", this::processOQLResponse);
}
}
private Task oqlGetTask(String location) {
try {
return HttpClient.get(location + "/oql/")
.setRequestTimeout(900000)
.addQueryParam("query", _script).task("runOQL");
} catch (Exception e) {
throw new RuntimeException("Can't create GET request to jhat server using location: " + location, e);
}
}
private HttpResponse processOQLResponse(Response response) throws IOException {
String responseBody = response.getResponseBody();
if (response.getStatusCode() != HttpServletResponse.SC_OK) {
return new HttpResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to query Jhat:\n" + responseBody);
} else {
Matcher regexMatcher = REGEX.matcher(responseBody);
if (regexMatcher.find()) {
String cutResponse = regexMatcher.group(1);
String fixedCutResponse = cutResponse.substring(0, cutResponse.length() - 4) + " ]";
final JsonNode resultsArr =
OBJECT_MAPPER.readTree(OBJECT_MAPPER.getJsonFactory().createJsonParser(fixedCutResponse));
final StringJoiner joiner = new StringJoiner(", ", "[ ", " ]");
for (JsonNode node : resultsArr) {
Trace trace = CODEC.decode(node.toString());
TraceBuilder builder = new TraceBuilder(trace.getRelationships().size() + 1, trace.getPlanClass(), trace.getPlanId());
Map traceMap = new HashMap<>();
trace.getTraceMap().forEach((key, value) -> {
ShallowTraceBuilder stb = new ShallowTraceBuilder(value);
traceMap.put(key, stb);
builder.addShallowTrace(stb);
});
for (TraceRelationship rel : trace.getRelationships()) {
builder.addRelationship(rel.getRelationhsip(), traceMap.get(rel.getFrom()), traceMap.get(rel.getTo()));
}
joiner.add(CODEC.encode(builder.build()));
}
return new HttpResponse(HttpServletResponse.SC_OK, joiner.toString());
} else {
return new HttpResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed parsing Jhat response:\n" + responseBody);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy