Issue #113 - CustomRequestLog

update logHandle directly rather than creating list of tokens

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2018-11-06 12:16:22 +01:00
parent 012d412ccb
commit 4be4b4e7b4
1 changed files with 33 additions and 85 deletions

View File

@ -22,8 +22,6 @@ import java.io.IOException;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -286,18 +284,16 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
private String _logTimeZone = "GMT"; private String _logTimeZone = "GMT";
private final MethodHandle _logHandle; private final MethodHandle _logHandle;
private final String _format;
public CustomRequestLog(String formatString) public CustomRequestLog(String formatString)
{ {
try try
{ {
_format = formatString;
_logHandle = getLogHandle(formatString); _logHandle = getLogHandle(formatString);
} }
catch (Throwable t) catch (Throwable t)
{ {
throw new IllegalStateException(); throw new IllegalStateException(t);
} }
} }
@ -549,119 +545,71 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
b.append(request.getRemoteAddr()); b.append(request.getRemoteAddr());
} }
public static void main(String[] args) throws Throwable
{
Request request = new Request(null, null);
String formatString = "clientIP: %a | ";
MethodHandle logHandle = getLogHandle(formatString);
StringBuilder b = new StringBuilder();
logHandle.invoke(b, request);
System.err.println(b.toString());
}
private static MethodHandle getLogHandle(String formatString) throws NoSuchMethodException, IllegalAccessException
{
//TODO add response to signature //TODO add response to signature
MethodType logType = methodType(Void.TYPE, StringBuilder.class, Request.class); private static final MethodType LOG_TYPE = methodType(Void.TYPE, StringBuilder.class, Request.class);
private MethodHandle getLogHandle(String formatString) throws Throwable
{
MethodHandle append = MethodHandles.lookup().findStatic(CustomRequestLog.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class)); MethodHandle append = MethodHandles.lookup().findStatic(CustomRequestLog.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class));
MethodHandle logHandle = dropArguments(append.bindTo("\n"), 1, Request.class); MethodHandle logHandle = dropArguments(append.bindTo("\n"), 1, Request.class);
for (Token s : tokenize(formatString))
{
if (s.isLiteralString())
{
logHandle = foldArguments(logHandle, dropArguments(append.bindTo(s.literal), 1, Request.class));
}
else
{
switch (s.code)
{
case "a":
{
String method = "logClientIP";
MethodHandle specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
logHandle = foldArguments(logHandle, specificHandle);
break;
}
}
}
}
return logHandle;
}
private static List<Token> tokenize(String value)
{
List<Token> tokens = new ArrayList<>();
final Pattern PERCENT_CODE = Pattern.compile("(?<remaining>.*)%(?:\\{(?<arg>[^{}]+)})?(?<code>[a-zA-Z%])"); final Pattern PERCENT_CODE = Pattern.compile("(?<remaining>.*)%(?:\\{(?<arg>[^{}]+)})?(?<code>[a-zA-Z%])");
final Pattern LITERAL = Pattern.compile("(?<remaining>.*%(?:\\{[^{}]+})?[a-zA-Z%])(?<literal>.*)"); final Pattern LITERAL = Pattern.compile("(?<remaining>.*%(?:\\{[^{}]+})?[a-zA-Z%])(?<literal>.*)");
while(value.length()>0) String remaining = formatString;
while(remaining.length()>0)
{ {
Matcher m = PERCENT_CODE.matcher(value); Matcher m = PERCENT_CODE.matcher(remaining);
Matcher m2 = LITERAL.matcher(value);
if (m.matches()) if (m.matches())
{ {
String code = m.group("code"); String code = m.group("code");
String arg = m.group("arg"); String arg = m.group("arg");
tokens.add(new Token(code, arg)); logHandle = updateLogHandle(logHandle, code, arg);
value = m.group("remaining"); remaining = m.group("remaining");
continue; continue;
} }
Matcher m2 = LITERAL.matcher(remaining);
String literal; String literal;
if (m2.matches()) if (m2.matches())
{ {
literal = m2.group("literal"); literal = m2.group("literal");
value = m2.group("remaining"); remaining = m2.group("remaining");
} }
else else
{ {
literal = value; literal = remaining;
value = ""; remaining = "";
}
logHandle = updateLogHandle(logHandle, append, literal);
} }
tokens.add(new Token(literal));
} return logHandle;
return tokens;
} }
private MethodHandle updateLogHandle(MethodHandle logHandle, MethodHandle append, String literal)
private static class Token
{ {
public boolean isLiteralString() return foldArguments(logHandle, dropArguments(append.bindTo(literal), 1, Request.class));
{
return(literal != null);
} }
public boolean isPercentCode()
private MethodHandle updateLogHandle(MethodHandle logHandle, String code, String arg) throws Throwable
{ {
return(code != null); switch (code)
{
case "a":
{
String method = "logClientIP";
MethodHandle specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, LOG_TYPE);
return foldArguments(logHandle, specificHandle);
} }
public String code = null; default:
public String arg = null; LOG.warn("Unsupported code %{}", code);
public String literal = null; return logHandle;
public Token(String code, String arg)
{
this.code = code;
this.arg = arg;
}
public Token(String literal)
{
this.literal = literal;
} }
} }
} }