Skip to content

Commit

Permalink
Add more logging to server logs like memory usage. Put parse time in …
Browse files Browse the repository at this point in the history
…log file too. Strip svgtree from log.

Signed-off-by: Terence Parr <parrt@antlr.org>
  • Loading branch information
parrt committed Jun 22, 2024
1 parent 2073836 commit 9c1a8a6
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 158 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Launch!

```bash
cd ~/antlr4-lab
sudo nohup java -cp ~/.m2/repository/org/antlr/antlr4-lab/0.3-SNAPSHOT/antlr4-lab-0.2-SNAPSHOT-complete.jar org.antlr.v4.server.ANTLRHttpServer
sudo nohup java -cp ~/.m2/repository/org/antlr/antlr4-lab/0.
3-SNAPSHOT/antlr4-lab-0.3-SNAPSHOT-complete.jar org.antlr.v4.server.ANTLRHttpServer
```

If you are running the server locally on your box, visit [http://localhost/index.html](http://localhost/index.html) to run the client.
Expand Down
295 changes: 144 additions & 151 deletions src/org/antlr/v4/server/ANTLRHttpServer.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.antlr.v4.server;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.antlr.v4.server.persistent.PersistenceLayer;
Expand All @@ -20,163 +20,156 @@
import org.slf4j.LoggerFactory;



import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.NumberFormat;
import java.util.Optional;

import static org.antlr.v4.server.GrammarProcessor.interp;

public class ANTLRHttpServer {
public static final String IMAGES_DIR = "/tmp/antlr-images";

public static class ParseServlet extends DefaultServlet {
static final ch.qos.logback.classic.Logger LOGGER =
(ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ANTLRHttpServer.class);

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException
{

JsonObject jsonResponse = new JsonObject();
try {
response.setContentType("text/plain;charset=utf-8");
response.setContentType("text/html;");
response.addHeader("Access-Control-Allow-Origin", "*");

JsonObject jsonObj = JsonParser.parseReader(request.getReader()).getAsJsonObject();
// System.out.println(jsonObj);

String grammar = jsonObj.get("grammar").getAsString();
String lexGrammar = jsonObj.get("lexgrammar").getAsString(); // can be null
String input = jsonObj.get("input").getAsString();
String startRule = jsonObj.get("start").getAsString();

StringBuilder logMsg = new StringBuilder();
logMsg.append("GRAMMAR:\n");
logMsg.append(grammar);
logMsg.append("\nLEX GRAMMAR:\n");
logMsg.append(lexGrammar);
logMsg.append("\nINPUT:\n\"\"\"");
logMsg.append(input);
logMsg.append("\"\"\"\n");
logMsg.append("STARTRULE: ");
logMsg.append(startRule);
logMsg.append('\n');
LOGGER.info(logMsg.toString());

if (grammar.strip().length() == 0 && lexGrammar.strip().length() == 0) {
jsonResponse.addProperty("arg_error", "missing either combined grammar or lexer and " +
"parser both");
}
else if (grammar.strip().length() == 0 && lexGrammar.strip().length() > 0) {
jsonResponse.addProperty("arg_error", "missing parser grammar");
}
else if (startRule.strip().length() == 0) {
jsonResponse.addProperty("arg_error", "missing start rule");
}
else if (input.length() == 0) {
jsonResponse.addProperty("arg_error", "missing input");
}
else {
try {
jsonResponse = interp(grammar, lexGrammar, input, startRule);
}
catch (ParseCancellationException pce) {
jsonResponse.addProperty("exception_trace", "parser timeout ("+GrammarProcessor.MAX_PARSE_TIME_MS+"ms)");
}
catch (Throwable e) {
e.printStackTrace(System.err);
}
}
}
catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
jsonResponse.addProperty("exception_trace", sw.toString());
jsonResponse.addProperty("exception", e.getMessage());
}
LOGGER.info("RESULT:\n"+jsonResponse);
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter w = response.getWriter();
w.write(new Gson().toJson(jsonResponse));
w.flush();
}
}

public static class ShareServlet extends DefaultServlet {
static final ch.qos.logback.classic.Logger LOGGER =
(ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ANTLRHttpServer.class);

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException
{
final JsonObject jsonResponse = new JsonObject();
try {
response.setContentType("text/plain;charset=utf-8");
response.setContentType("text/html;");
response.addHeader("Access-Control-Allow-Origin", "*");

JsonObject jsonObj = JsonParser.parseReader(request.getReader()).getAsJsonObject();
PersistenceLayer<String> persistenceLayer = new CloudStoragePersistenceLayer();
UniqueKeyGenerator keyGen = new DummyUniqueKeyGenerator();
Optional<String> uniqueKey = keyGen.generateKey();
persistenceLayer.persist(new Gson().toJson(jsonResponse).getBytes(StandardCharsets.UTF_8),
uniqueKey.orElseThrow());

jsonResponse.addProperty("resource_id", uniqueKey.orElseThrow());
}
catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
jsonResponse.addProperty("exception_trace", sw.toString());
jsonResponse.addProperty("exception", e.getMessage());

}
LOGGER.info("RESULT:\n"+jsonResponse);
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter w = response.getWriter();
w.write(new Gson().toJson(jsonResponse));
w.flush();
}
}

public static void main(String[] args) throws Exception {
new File(IMAGES_DIR).mkdirs();

Files.createDirectories(Path.of("/var/log/antlrlab"));
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(10);
threadPool.setName("server");

Server server = new Server(threadPool);

ServerConnector http = new ServerConnector(server);
http.setPort(80);

server.addConnector(http);

// Server server = new Server(8080);

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new ParseServlet()), "/parse/*");
context.addServlet(new ServletHolder(new ShareServlet()), "/share/*");

ServletHolder holderHome = new ServletHolder("static-home", DefaultServlet.class);
holderHome.setInitParameter("resourceBase", "static");
holderHome.setInitParameter("dirAllowed","true");
holderHome.setInitParameter("pathInfoOnly","true");
context.addServlet(holderHome,"/*");

server.setHandler(context);

server.start();
}
public static final String IMAGES_DIR = "/tmp/antlr-images";

public static class ParseServlet extends DefaultServlet {
static final ch.qos.logback.classic.Logger LOGGER = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ANTLRHttpServer.class);

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
logMemoryInfo("BEFORE PARSE");
JsonObject jsonResponse = new JsonObject();
try {
response.setContentType("text/plain;charset=utf-8");
response.setContentType("text/html;");
response.addHeader("Access-Control-Allow-Origin", "*");

JsonObject jsonObj = JsonParser.parseReader(request.getReader()).getAsJsonObject();

String grammar = jsonObj.get("grammar").getAsString();
String lexGrammar = jsonObj.get("lexgrammar").getAsString(); // can be null
String input = jsonObj.get("input").getAsString();
String startRule = jsonObj.get("start").getAsString();

StringBuilder logMsg = new StringBuilder();
logMsg.append("GRAMMAR:\n");
logMsg.append(grammar);
logMsg.append("\nLEX GRAMMAR:\n");
logMsg.append(lexGrammar);
logMsg.append("\nINPUT:\n\"\"\"");
logMsg.append(input);
logMsg.append("\"\"\"\n");
logMsg.append("STARTRULE: ");
logMsg.append(startRule);
logMsg.append('\n');
LOGGER.info(logMsg.toString());

if (grammar.isBlank() && lexGrammar.isBlank()) {
jsonResponse.addProperty("arg_error", "missing either combined grammar or lexer and " + "parser both");
} else if (grammar.isBlank()) {
jsonResponse.addProperty("arg_error", "missing parser grammar");
} else if (startRule.isBlank()) {
jsonResponse.addProperty("arg_error", "missing start rule");
} else if (input.isEmpty()) {
jsonResponse.addProperty("arg_error", "missing input");
} else {
try {
jsonResponse = interp(grammar, lexGrammar, input, startRule);
} catch (ParseCancellationException pce) {
jsonResponse.addProperty("exception_trace", "parser timeout (" + GrammarProcessor.MAX_PARSE_TIME_MS + "ms)");
} catch (Throwable e) {
e.printStackTrace(System.err);
}
}
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
jsonResponse.addProperty("exception_trace", sw.toString());
jsonResponse.addProperty("exception", e.getMessage());
}
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter w = response.getWriter();
w.write(new Gson().toJson(jsonResponse));
w.flush();
JsonElement result = jsonResponse.get("result");
((JsonObject)result).remove("svgtree"); // can be huge
logMemoryInfo("AFTER PARSE");
LOGGER.info("RESULT:\n" + jsonResponse);
}
}

private static void logMemoryInfo(String prefix) {
Runtime.getRuntime().gc();
var fm = Runtime.getRuntime().freeMemory();
var tm = Runtime.getRuntime().totalMemory();
NumberFormat.getInstance().format(fm);
ParseServlet.LOGGER.info(prefix+" memory: free=" + NumberFormat.getInstance().format(fm) + " bytes" +
", total=" + NumberFormat.getInstance().format(tm) + " bytes");
}

public static class ShareServlet extends DefaultServlet {
static final ch.qos.logback.classic.Logger LOGGER = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ANTLRHttpServer.class);

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
final JsonObject jsonResponse = new JsonObject();
try {
response.setContentType("text/plain;charset=utf-8");
response.setContentType("text/html;");
response.addHeader("Access-Control-Allow-Origin", "*");

JsonObject jsonObj = JsonParser.parseReader(request.getReader()).getAsJsonObject();
PersistenceLayer<String> persistenceLayer = new CloudStoragePersistenceLayer();
UniqueKeyGenerator keyGen = new DummyUniqueKeyGenerator();
Optional<String> uniqueKey = keyGen.generateKey();
persistenceLayer.persist(new Gson().toJson(jsonResponse).getBytes(StandardCharsets.UTF_8), uniqueKey.orElseThrow());

jsonResponse.addProperty("resource_id", uniqueKey.orElseThrow());
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
jsonResponse.addProperty("exception_trace", sw.toString());
jsonResponse.addProperty("exception", e.getMessage());

}
LOGGER.info("RESULT:\n" + jsonResponse);
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter w = response.getWriter();
w.write(new Gson().toJson(jsonResponse));
w.flush();
}
}

public static void main(String[] args) throws Exception {
new File(IMAGES_DIR).mkdirs();

Files.createDirectories(Path.of("/var/log/antlrlab"));
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(10);
threadPool.setName("server");

Server server = new Server(threadPool);

ServerConnector http = new ServerConnector(server);
http.setPort(80);

server.addConnector(http);

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new ParseServlet()), "/parse/*");
context.addServlet(new ServletHolder(new ShareServlet()), "/share/*");

ServletHolder holderHome = new ServletHolder("static-home", DefaultServlet.class);
holderHome.setInitParameter("resourceBase", "static");
holderHome.setInitParameter("dirAllowed", "true");
holderHome.setInitParameter("pathInfoOnly", "true");
context.addServlet(holderHome, "/*");

server.setHandler(context);

server.start();
}
}
Loading

0 comments on commit 9c1a8a6

Please sign in to comment.