Merge pull request #3144 from lachlan-roberts/jetty-9.4.x
Issue #113 - CustomRequestLog
This commit is contained in:
commit
bda9307028
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.requestlog.jmh;
|
package org.eclipse.jetty.requestlog.jmh;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodHandles.dropArguments;
|
|
||||||
import static java.lang.invoke.MethodHandles.foldArguments;
|
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -43,6 +39,10 @@ import org.openjdk.jmh.runner.RunnerException;
|
||||||
import org.openjdk.jmh.runner.options.Options;
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
import static java.lang.invoke.MethodHandles.dropArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.foldArguments;
|
||||||
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
|
@ -79,14 +79,7 @@ public class RequestLogBenchmark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThreadLocal<StringBuilder> buffers = new ThreadLocal<StringBuilder>()
|
private ThreadLocal<StringBuilder> buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected StringBuilder initialValue()
|
|
||||||
{
|
|
||||||
return new StringBuilder(256);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
MethodHandle logHandle;
|
MethodHandle logHandle;
|
||||||
Object[] iteratedLog;
|
Object[] iteratedLog;
|
||||||
|
|
||||||
|
@ -96,8 +89,7 @@ public class RequestLogBenchmark
|
||||||
{
|
{
|
||||||
MethodType logType = methodType(Void.TYPE, StringBuilder.class, String.class);
|
MethodType logType = methodType(Void.TYPE, StringBuilder.class, String.class);
|
||||||
|
|
||||||
MethodHandle append = MethodHandles.lookup()
|
MethodHandle append = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class));
|
||||||
.findStatic(RequestLogBenchmark.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class));
|
|
||||||
MethodHandle logURI = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logURI", logType);
|
MethodHandle logURI = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logURI", logType);
|
||||||
MethodHandle logAddr = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logAddr", logType);
|
MethodHandle logAddr = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logAddr", logType);
|
||||||
MethodHandle logLength = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logLength", logType);
|
MethodHandle logLength = MethodHandles.lookup().findStatic(RequestLogBenchmark.class, "logLength", logType);
|
||||||
|
@ -171,7 +163,7 @@ public class RequestLogBenchmark
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StringBuilder b = buffers.get();
|
StringBuilder b = buffers.get();
|
||||||
logHandle.invoke(buffers.get(), request);
|
logHandle.invoke(b, request);
|
||||||
String l = b.toString();
|
String l = b.toString();
|
||||||
b.setLength(0);
|
b.setLength(0);
|
||||||
return l;
|
return l;
|
||||||
|
@ -202,7 +194,7 @@ public class RequestLogBenchmark
|
||||||
public String testHandle()
|
public String testHandle()
|
||||||
{
|
{
|
||||||
return logMethodHandle(Long.toString(ThreadLocalRandom.current().nextLong()));
|
return logMethodHandle(Long.toString(ThreadLocalRandom.current().nextLong()));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws RunnerException
|
public static void main(String[] args) throws RunnerException
|
||||||
|
|
|
@ -18,17 +18,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.security;
|
package org.eclipse.jetty.security;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.isIn;
|
|
||||||
import static org.hamcrest.Matchers.not;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
@ -45,7 +34,6 @@ import java.util.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.servlet.HttpConstraintElement;
|
import javax.servlet.HttpConstraintElement;
|
||||||
import javax.servlet.HttpMethodConstraintElement;
|
import javax.servlet.HttpMethodConstraintElement;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
@ -83,6 +71,17 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.isIn;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class ConstraintTest
|
public class ConstraintTest
|
||||||
{
|
{
|
||||||
private static final String TEST_REALM = "TestRealm";
|
private static final String TEST_REALM = "TestRealm";
|
||||||
|
@ -1526,6 +1525,12 @@ public class ConstraintTest
|
||||||
|
|
||||||
UserIdentity.Scope scope = new UserIdentity.Scope()
|
UserIdentity.Scope scope = new UserIdentity.Scope()
|
||||||
{
|
{
|
||||||
|
@Override
|
||||||
|
public ContextHandler getContextHandler()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getContextPath()
|
public String getContextPath()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
<!-- Configure the Jetty Request Log -->
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Configure Request Log for Server -->
|
||||||
|
<!-- (Use RequestLogHandler for a context specific RequestLog -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Set name="RequestLog">
|
||||||
|
<New id="RequestLog" class="org.eclipse.jetty.server.CustomRequestLog">
|
||||||
|
<!-- Writer -->
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.server.AsyncRequestLogWriter">
|
||||||
|
<Arg><Property name="jetty.base" default="." />/<Property>
|
||||||
|
<Name>jetty.customrequestlog.filePath</Name>
|
||||||
|
<Default><Property name="jetty.requestlog.dir" default="logs"/>/yyyy_mm_dd.request.log</Default>
|
||||||
|
</Property></Arg>
|
||||||
|
<Arg/>
|
||||||
|
|
||||||
|
<Set name="filenameDateFormat"><Property name="jetty.requestlog.filenameDateFormat" default="yyyy_MM_dd"/></Set>
|
||||||
|
<Set name="retainDays"><Property name="jetty.requestlog.retainDays" default="90"/></Set>
|
||||||
|
<Set name="append"><Property name="jetty.requestlog.append" default="false"/></Set>
|
||||||
|
<Set name="timeZone"><Property name="jetty.requestlog.timezone" default="GMT"/></Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
|
||||||
|
<!-- Format String -->
|
||||||
|
<Arg>
|
||||||
|
<Property name="jetty.requestlog.formatString">
|
||||||
|
<Default>
|
||||||
|
<Get class="org.eclipse.jetty.server.CustomRequestLog" name="EXTENDED_NCSA_FORMAT"/>
|
||||||
|
</Default>
|
||||||
|
</Property>
|
||||||
|
</Arg>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,41 @@
|
||||||
|
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||||
|
|
||||||
|
[description]
|
||||||
|
Enables a format string style request log.
|
||||||
|
|
||||||
|
[provides]
|
||||||
|
requestlog
|
||||||
|
|
||||||
|
[tags]
|
||||||
|
requestlog
|
||||||
|
|
||||||
|
[depend]
|
||||||
|
server
|
||||||
|
|
||||||
|
[xml]
|
||||||
|
etc/jetty-customrequestlog.xml
|
||||||
|
|
||||||
|
[files]
|
||||||
|
logs/
|
||||||
|
|
||||||
|
[ini-template]
|
||||||
|
## Logging directory (relative to $jetty.base)
|
||||||
|
# jetty.requestlog.dir=logs
|
||||||
|
|
||||||
|
## File path
|
||||||
|
# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
|
||||||
|
|
||||||
|
## Date format for rollovered files (uses SimpleDateFormat syntax)
|
||||||
|
# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
|
||||||
|
|
||||||
|
## How many days to retain old log files
|
||||||
|
# jetty.requestlog.retainDays=90
|
||||||
|
|
||||||
|
## Whether to append to existing file
|
||||||
|
# jetty.requestlog.append=false
|
||||||
|
|
||||||
|
## Timezone of the log entries
|
||||||
|
# jetty.requestlog.timezone=GMT
|
||||||
|
|
||||||
|
## Format string
|
||||||
|
# jetty.requestlog.formatString=%a - %u %t "%r" %s %B "%{Referer}i" "%{User-Agent}i" "%C"
|
|
@ -28,7 +28,7 @@ import org.eclipse.jetty.http.pathmap.PathMappings;
|
||||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||||
import org.eclipse.jetty.util.DateCache;
|
import org.eclipse.jetty.util.DateCache;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
@ -37,20 +37,17 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* Configuration options allow a choice between the standard Common Log Format (as used in the 3 log format) and the
|
* Configuration options allow a choice between the standard Common Log Format (as used in the 3 log format) and the
|
||||||
* Combined Log Format (single log format). This log format can be output by most web servers, and almost all web log
|
* Combined Log Format (single log format). This log format can be output by most web servers, and almost all web log
|
||||||
* analysis software can understand these formats.
|
* analysis software can understand these formats.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with a {@link RequestLog.Writer}
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implements RequestLog
|
@Deprecated
|
||||||
|
public class AbstractNCSARequestLog extends ContainerLifeCycle implements RequestLog
|
||||||
{
|
{
|
||||||
protected static final Logger LOG = Log.getLogger(AbstractNCSARequestLog.class);
|
protected static final Logger LOG = Log.getLogger(AbstractNCSARequestLog.class);
|
||||||
|
|
||||||
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
|
private static ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected StringBuilder initialValue()
|
|
||||||
{
|
|
||||||
return new StringBuilder(256);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
protected final RequestLog.Writer _requestLogWriter;
|
||||||
|
|
||||||
private String[] _ignorePaths;
|
private String[] _ignorePaths;
|
||||||
private boolean _extended;
|
private boolean _extended;
|
||||||
|
@ -64,28 +61,36 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
private Locale _logLocale = Locale.getDefault();
|
private Locale _logLocale = Locale.getDefault();
|
||||||
private String _logTimeZone = "GMT";
|
private String _logTimeZone = "GMT";
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
public AbstractNCSARequestLog(RequestLog.Writer requestLogWriter)
|
||||||
|
{
|
||||||
|
this._requestLogWriter = requestLogWriter;
|
||||||
|
addBean(_requestLogWriter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is logging enabled
|
* Is logging enabled
|
||||||
|
*
|
||||||
* @return true if logging is enabled
|
* @return true if logging is enabled
|
||||||
*/
|
*/
|
||||||
protected abstract boolean isEnabled();
|
protected boolean isEnabled()
|
||||||
|
{
|
||||||
/* ------------------------------------------------------------ */
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write requestEntry out. (to disk or slf4j log)
|
* Write requestEntry out. (to disk or slf4j log)
|
||||||
|
*
|
||||||
* @param requestEntry the request entry
|
* @param requestEntry the request entry
|
||||||
* @throws IOException if unable to write the entry
|
* @throws IOException if unable to write the entry
|
||||||
*/
|
*/
|
||||||
public abstract void write(String requestEntry) throws IOException;
|
public void write(String requestEntry) throws IOException
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
|
|
||||||
private void append(StringBuilder buf,String s)
|
|
||||||
{
|
{
|
||||||
if (s==null || s.length()==0)
|
_requestLogWriter.write(requestEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void append(StringBuilder buf, String s)
|
||||||
|
{
|
||||||
|
if (s == null || s.length() == 0)
|
||||||
buf.append('-');
|
buf.append('-');
|
||||||
else
|
else
|
||||||
buf.append(s);
|
buf.append(s);
|
||||||
|
@ -112,7 +117,7 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
|
|
||||||
if (_logServer)
|
if (_logServer)
|
||||||
{
|
{
|
||||||
append(buf,request.getServerName());
|
append(buf, request.getServerName());
|
||||||
buf.append(' ');
|
buf.append(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +132,9 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
|
|
||||||
buf.append(addr);
|
buf.append(addr);
|
||||||
buf.append(" - ");
|
buf.append(" - ");
|
||||||
|
|
||||||
String auth = getAuthentication(request);
|
String auth = getAuthentication(request);
|
||||||
append(buf,auth==null?"-":auth);
|
append(buf, auth == null ? "-" : auth);
|
||||||
|
|
||||||
buf.append(" [");
|
buf.append(" [");
|
||||||
if (_logDateCache != null)
|
if (_logDateCache != null)
|
||||||
|
@ -138,15 +143,15 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
buf.append(request.getTimeStamp());
|
buf.append(request.getTimeStamp());
|
||||||
|
|
||||||
buf.append("] \"");
|
buf.append("] \"");
|
||||||
append(buf,request.getMethod());
|
append(buf, request.getMethod());
|
||||||
buf.append(' ');
|
buf.append(' ');
|
||||||
append(buf,request.getOriginalURI());
|
append(buf, request.getOriginalURI());
|
||||||
buf.append(' ');
|
buf.append(' ');
|
||||||
append(buf,request.getProtocol());
|
append(buf, request.getProtocol());
|
||||||
buf.append("\" ");
|
buf.append("\" ");
|
||||||
|
|
||||||
int status = response.getCommittedMetaData().getStatus();
|
int status = response.getCommittedMetaData().getStatus();
|
||||||
if (status >=0)
|
if (status >= 0)
|
||||||
{
|
{
|
||||||
buf.append((char)('0' + ((status / 100) % 10)));
|
buf.append((char)('0' + ((status / 100) % 10)));
|
||||||
buf.append((char)('0' + ((status / 10) % 10)));
|
buf.append((char)('0' + ((status / 10) % 10)));
|
||||||
|
@ -221,21 +226,22 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the user authentication
|
* Extract the user authentication
|
||||||
|
*
|
||||||
* @param request The request to extract from
|
* @param request The request to extract from
|
||||||
* @return The string to log for authenticated user.
|
* @return The string to log for authenticated user.
|
||||||
*/
|
*/
|
||||||
protected String getAuthentication(Request request)
|
protected String getAuthentication(Request request)
|
||||||
{
|
{
|
||||||
Authentication authentication = request.getAuthentication();
|
Authentication authentication = request.getAuthentication();
|
||||||
|
|
||||||
if (authentication instanceof Authentication.User)
|
if (authentication instanceof Authentication.User)
|
||||||
return ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
|
return ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
|
||||||
|
|
||||||
// TODO extract the user name if it is Authentication.Deferred and return as '?username'
|
// TODO extract the user name if it is Authentication.Deferred and return as '?username'
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +430,7 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
||||||
{
|
{
|
||||||
if (_logDateFormat != null)
|
if (_logDateFormat != null)
|
||||||
{
|
{
|
||||||
_logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
|
_logDateCache = new DateCache(_logDateFormat, _logLocale, _logTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_ignorePaths != null && _ignorePaths.length > 0)
|
if (_ignorePaths != null && _ignorePaths.length > 0)
|
||||||
|
|
|
@ -18,112 +18,22 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* An asynchronously writing NCSA Request Log
|
* An asynchronously writing NCSA Request Log
|
||||||
|
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with an {@link AsyncRequestLogWriter}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AsyncNCSARequestLog extends NCSARequestLog
|
public class AsyncNCSARequestLog extends NCSARequestLog
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(AsyncNCSARequestLog.class);
|
|
||||||
private final BlockingQueue<String> _queue;
|
|
||||||
private transient WriterThread _thread;
|
|
||||||
private boolean _warnedFull;
|
|
||||||
|
|
||||||
public AsyncNCSARequestLog()
|
public AsyncNCSARequestLog()
|
||||||
{
|
{
|
||||||
this(null,null);
|
this(null,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncNCSARequestLog(BlockingQueue<String> queue)
|
public AsyncNCSARequestLog(String filename, BlockingQueue<String> queue)
|
||||||
{
|
{
|
||||||
this(null,queue);
|
super(new AsyncRequestLogWriter(filename, queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncNCSARequestLog(String filename)
|
|
||||||
{
|
|
||||||
this(filename,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncNCSARequestLog(String filename,BlockingQueue<String> queue)
|
|
||||||
{
|
|
||||||
super(filename);
|
|
||||||
if (queue==null)
|
|
||||||
queue=new BlockingArrayQueue<>(1024);
|
|
||||||
_queue=queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class WriterThread extends Thread
|
|
||||||
{
|
|
||||||
WriterThread()
|
|
||||||
{
|
|
||||||
setName("AsyncNCSARequestLog@"+Integer.toString(AsyncNCSARequestLog.this.hashCode(),16));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
while (isRunning())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String log = _queue.poll(10,TimeUnit.SECONDS);
|
|
||||||
if (log!=null)
|
|
||||||
AsyncNCSARequestLog.super.write(log);
|
|
||||||
|
|
||||||
while(!_queue.isEmpty())
|
|
||||||
{
|
|
||||||
log=_queue.poll();
|
|
||||||
if (log!=null)
|
|
||||||
AsyncNCSARequestLog.super.write(log);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.warn(e);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected synchronized void doStart() throws Exception
|
|
||||||
{
|
|
||||||
super.doStart();
|
|
||||||
_thread = new WriterThread();
|
|
||||||
_thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStop() throws Exception
|
|
||||||
{
|
|
||||||
_thread.interrupt();
|
|
||||||
_thread.join();
|
|
||||||
super.doStop();
|
|
||||||
_thread=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(String log) throws IOException
|
|
||||||
{
|
|
||||||
if (!_queue.offer(log))
|
|
||||||
{
|
|
||||||
if (_warnedFull)
|
|
||||||
LOG.warn("Log Queue overflow");
|
|
||||||
_warnedFull=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An asynchronously writing RequestLogWriter
|
||||||
|
*/
|
||||||
|
public class AsyncRequestLogWriter extends RequestLogWriter
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(AsyncRequestLogWriter.class);
|
||||||
|
private final BlockingQueue<String> _queue;
|
||||||
|
private transient AsyncRequestLogWriter.WriterThread _thread;
|
||||||
|
private boolean _warnedFull;
|
||||||
|
|
||||||
|
public AsyncRequestLogWriter()
|
||||||
|
{
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncRequestLogWriter(String filename, BlockingQueue<String> queue)
|
||||||
|
{
|
||||||
|
super(filename);
|
||||||
|
if (queue == null)
|
||||||
|
queue = new BlockingArrayQueue<>(1024);
|
||||||
|
_queue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WriterThread extends Thread
|
||||||
|
{
|
||||||
|
WriterThread()
|
||||||
|
{
|
||||||
|
setName("AsyncRequestLogWriter@" + Integer.toString(AsyncRequestLogWriter.this.hashCode(), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
while (isRunning())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String log = _queue.poll(10, TimeUnit.SECONDS);
|
||||||
|
if (log != null)
|
||||||
|
AsyncRequestLogWriter.super.write(log);
|
||||||
|
|
||||||
|
while (!_queue.isEmpty())
|
||||||
|
{
|
||||||
|
log = _queue.poll();
|
||||||
|
if (log != null)
|
||||||
|
AsyncRequestLogWriter.super.write(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
LOG.warn(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void doStart() throws Exception
|
||||||
|
{
|
||||||
|
super.doStart();
|
||||||
|
_thread = new AsyncRequestLogWriter.WriterThread();
|
||||||
|
_thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStop() throws Exception
|
||||||
|
{
|
||||||
|
_thread.interrupt();
|
||||||
|
_thread.join();
|
||||||
|
super.doStop();
|
||||||
|
_thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String log) throws IOException
|
||||||
|
{
|
||||||
|
if (!_queue.offer(log))
|
||||||
|
{
|
||||||
|
if (_warnedFull)
|
||||||
|
LOG.warn("Log Queue overflow");
|
||||||
|
_warnedFull = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -34,8 +34,6 @@ import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.UnavailableException;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.http.BadMessageException;
|
import org.eclipse.jetty.http.BadMessageException;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
|
@ -48,9 +46,9 @@ import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MetaData;
|
import org.eclipse.jetty.http.MetaData;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.ChannelEndPoint;
|
import org.eclipse.jetty.io.ChannelEndPoint;
|
||||||
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.io.QuietException;
|
import org.eclipse.jetty.io.QuietException;
|
||||||
import org.eclipse.jetty.io.RuntimeIOException;
|
|
||||||
import org.eclipse.jetty.server.HttpChannelState.Action;
|
import org.eclipse.jetty.server.HttpChannelState.Action;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||||
|
@ -74,6 +72,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HttpChannel.class);
|
private static final Logger LOG = Log.getLogger(HttpChannel.class);
|
||||||
private final AtomicBoolean _committed = new AtomicBoolean();
|
private final AtomicBoolean _committed = new AtomicBoolean();
|
||||||
|
private final AtomicBoolean _responseCompleted = new AtomicBoolean();
|
||||||
private final AtomicLong _requests = new AtomicLong();
|
private final AtomicLong _requests = new AtomicLong();
|
||||||
private final Connector _connector;
|
private final Connector _connector;
|
||||||
private final Executor _executor;
|
private final Executor _executor;
|
||||||
|
@ -246,6 +245,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
return _response;
|
return _response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Connection getConnection()
|
||||||
|
{
|
||||||
|
return _endPoint.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
public EndPoint getEndPoint()
|
public EndPoint getEndPoint()
|
||||||
{
|
{
|
||||||
return _endPoint;
|
return _endPoint;
|
||||||
|
@ -277,6 +281,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
public void recycle()
|
public void recycle()
|
||||||
{
|
{
|
||||||
_committed.set(false);
|
_committed.set(false);
|
||||||
|
_responseCompleted.set(false);
|
||||||
_request.recycle();
|
_request.recycle();
|
||||||
_response.recycle();
|
_response.recycle();
|
||||||
_committedMetaData=null;
|
_committedMetaData=null;
|
||||||
|
@ -662,11 +667,13 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
long timeStamp = _request.getTimeStamp();
|
long timeStamp = _request.getTimeStamp();
|
||||||
return String.format("%s@%x{r=%s,c=%b,a=%s,uri=%s,age=%d}",
|
return String.format("%s@%x{r=%s,c=%b,c=%b/%b,a=%s,uri=%s,age=%d}",
|
||||||
getClass().getSimpleName(),
|
getClass().getSimpleName(),
|
||||||
hashCode(),
|
hashCode(),
|
||||||
_requests,
|
_requests,
|
||||||
_committed.get(),
|
_committed.get(),
|
||||||
|
isRequestCompleted(),
|
||||||
|
isResponseCompleted(),
|
||||||
_state.getState(),
|
_state.getState(),
|
||||||
_request.getHttpURI(),
|
_request.getHttpURI(),
|
||||||
timeStamp == 0 ? 0 : System.currentTimeMillis() - timeStamp);
|
timeStamp == 0 ? 0 : System.currentTimeMillis() - timeStamp);
|
||||||
|
@ -828,7 +835,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
|
|
||||||
// wrap callback to process 100 responses
|
// wrap callback to process 100 responses
|
||||||
final int status=info.getStatus();
|
final int status=info.getStatus();
|
||||||
final Callback committed = (status<200&&status>=100)?new Commit100Callback(callback):new CommitCallback(callback, content, complete);
|
final Callback committed = (status<200&&status>=100)?new Send100Callback(callback):new SendCallback(callback, content, true, complete);
|
||||||
|
|
||||||
notifyResponseBegin(_request);
|
notifyResponseBegin(_request);
|
||||||
|
|
||||||
|
@ -838,7 +845,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
else if (info==null)
|
else if (info==null)
|
||||||
{
|
{
|
||||||
// This is a normal write
|
// This is a normal write
|
||||||
_transport.send(null,_request.isHead(), content, complete, new ContentCallback(callback, content, complete));
|
_transport.send(null,_request.isHead(), content, complete, new SendCallback(callback, content, false, complete));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -878,6 +885,27 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
return _committed.get();
|
return _committed.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the request lifecycle is completed
|
||||||
|
*/
|
||||||
|
public boolean isRequestCompleted()
|
||||||
|
{
|
||||||
|
return _state.isCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the response is completely written.
|
||||||
|
*/
|
||||||
|
public boolean isResponseCompleted()
|
||||||
|
{
|
||||||
|
return _responseCompleted.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPersistent()
|
||||||
|
{
|
||||||
|
return _endPoint.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Non-Blocking write, committing the response if needed.</p>
|
* <p>Non-Blocking write, committing the response if needed.</p>
|
||||||
* Called as last link in HttpOutput.Filter chain
|
* Called as last link in HttpOutput.Filter chain
|
||||||
|
@ -1222,17 +1250,19 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CommitCallback extends Callback.Nested
|
private class SendCallback extends Callback.Nested
|
||||||
{
|
{
|
||||||
private final ByteBuffer _content;
|
private final ByteBuffer _content;
|
||||||
private final int _length;
|
private final int _length;
|
||||||
|
private final boolean _commit;
|
||||||
private final boolean _complete;
|
private final boolean _complete;
|
||||||
|
|
||||||
private CommitCallback(Callback callback, ByteBuffer content, boolean complete)
|
private SendCallback(Callback callback, ByteBuffer content, boolean commit, boolean complete)
|
||||||
{
|
{
|
||||||
super(callback);
|
super(callback);
|
||||||
_content = content == null ? BufferUtil.EMPTY_BUFFER : content.slice();
|
_content = content == null ? BufferUtil.EMPTY_BUFFER : content.slice();
|
||||||
_length = _content.remaining();
|
_length = _content.remaining();
|
||||||
|
_commit = commit;
|
||||||
_complete = complete;
|
_complete = complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1241,11 +1271,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
{
|
{
|
||||||
_written += _length;
|
_written += _length;
|
||||||
super.succeeded();
|
super.succeeded();
|
||||||
notifyResponseCommit(_request);
|
if (_commit)
|
||||||
if (_content.hasRemaining())
|
notifyResponseCommit(_request);
|
||||||
|
if (_length>0)
|
||||||
notifyResponseContent(_request, _content);
|
notifyResponseContent(_request, _content);
|
||||||
if (_complete)
|
if (_complete)
|
||||||
|
{
|
||||||
|
_responseCompleted.set(true);
|
||||||
notifyResponseEnd(_request);
|
notifyResponseEnd(_request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1281,11 +1315,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Commit100Callback extends CommitCallback
|
private class Send100Callback extends SendCallback
|
||||||
{
|
{
|
||||||
private Commit100Callback(Callback callback)
|
private Send100Callback(Callback callback)
|
||||||
{
|
{
|
||||||
super(callback, null, false);
|
super(callback, null, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1297,30 +1331,4 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
||||||
super.failed(new IllegalStateException());
|
super.failed(new IllegalStateException());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ContentCallback extends Callback.Nested
|
|
||||||
{
|
|
||||||
private final ByteBuffer _content;
|
|
||||||
private final int _length;
|
|
||||||
private final boolean _complete;
|
|
||||||
|
|
||||||
private ContentCallback(Callback callback, ByteBuffer content, boolean complete)
|
|
||||||
{
|
|
||||||
super(callback);
|
|
||||||
_content = content == null ? BufferUtil.EMPTY_BUFFER : content.slice();
|
|
||||||
_length = _content.remaining();
|
|
||||||
_complete = complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void succeeded()
|
|
||||||
{
|
|
||||||
_written += _length;
|
|
||||||
super.succeeded();
|
|
||||||
if (_content.hasRemaining())
|
|
||||||
notifyResponseContent(_request, _content);
|
|
||||||
if (_complete)
|
|
||||||
notifyResponseEnd(_request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,9 @@
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.RolloverFileOutputStream;
|
import org.eclipse.jetty.util.RolloverFileOutputStream;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
|
|
||||||
|
@ -36,31 +32,23 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
* Format (single log format). This log format can be output by most web
|
* Format (single log format). This log format can be output by most web
|
||||||
* servers, and almost all web log analysis software can understand these
|
* servers, and almost all web log analysis software can understand these
|
||||||
* formats.
|
* formats.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with a {@link RequestLogWriter}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@ManagedObject("NCSA standard format request log")
|
@ManagedObject("NCSA standard format request log")
|
||||||
public class NCSARequestLog extends AbstractNCSARequestLog
|
public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
{
|
{
|
||||||
private String _filename;
|
private final RequestLogWriter _requestLogWriter;
|
||||||
private boolean _append;
|
|
||||||
private int _retainDays;
|
|
||||||
private boolean _closeOut;
|
|
||||||
private String _filenameDateFormat = null;
|
|
||||||
private transient OutputStream _out;
|
|
||||||
private transient OutputStream _fileOut;
|
|
||||||
private transient Writer _writer;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Create request log object with default settings.
|
* Create request log object with default settings.
|
||||||
*/
|
*/
|
||||||
public NCSARequestLog()
|
public NCSARequestLog()
|
||||||
{
|
{
|
||||||
setExtended(true);
|
this((String)null);
|
||||||
_append = true;
|
|
||||||
_retainDays = 31;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Create request log object with specified output file name.
|
* Create request log object with specified output file name.
|
||||||
*
|
*
|
||||||
|
@ -70,33 +58,41 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
*/
|
*/
|
||||||
public NCSARequestLog(String filename)
|
public NCSARequestLog(String filename)
|
||||||
{
|
{
|
||||||
setExtended(true);
|
this(new RequestLogWriter(filename));
|
||||||
_append = true;
|
}
|
||||||
_retainDays = 31;
|
|
||||||
setFilename(filename);
|
/**
|
||||||
|
* Create request log object given a RequestLogWriter file name.
|
||||||
|
*
|
||||||
|
* @param writer the writer which manages the output of the formatted string
|
||||||
|
* produced by the {@link RequestLog}
|
||||||
|
*/
|
||||||
|
public NCSARequestLog(RequestLogWriter writer)
|
||||||
|
{
|
||||||
|
super(writer);
|
||||||
|
_requestLogWriter = writer;
|
||||||
|
setExtended(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Set the output file name of the request log.
|
* Set the output file name of the request log.
|
||||||
* The file name may be in the format expected by
|
* The file name may be in the format expected by
|
||||||
* {@link RolloverFileOutputStream}.
|
* {@link RolloverFileOutputStream}.
|
||||||
*
|
*
|
||||||
* @param filename file name of the request log
|
* @param filename file name of the request log
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public void setFilename(String filename)
|
public void setFilename(String filename)
|
||||||
{
|
{
|
||||||
if (filename != null)
|
_requestLogWriter.setFilename(filename);
|
||||||
{
|
}
|
||||||
filename = filename.trim();
|
|
||||||
if (filename.length() == 0)
|
@Override
|
||||||
filename = null;
|
public void setLogTimeZone(String tz)
|
||||||
}
|
{
|
||||||
_filename = filename;
|
super.setLogTimeZone(tz);
|
||||||
|
_requestLogWriter.setTimeZone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the output file name of the request log.
|
* Retrieve the output file name of the request log.
|
||||||
*
|
*
|
||||||
|
@ -105,10 +101,9 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
@ManagedAttribute("file of log")
|
@ManagedAttribute("file of log")
|
||||||
public String getFilename()
|
public String getFilename()
|
||||||
{
|
{
|
||||||
return _filename;
|
return _requestLogWriter.getFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the file name of the request log with the expanded
|
* Retrieve the file name of the request log with the expanded
|
||||||
* date wildcard if the output is written to the disk using
|
* date wildcard if the output is written to the disk using
|
||||||
|
@ -118,19 +113,15 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
*/
|
*/
|
||||||
public String getDatedFilename()
|
public String getDatedFilename()
|
||||||
{
|
{
|
||||||
if (_fileOut instanceof RolloverFileOutputStream)
|
return _requestLogWriter.getDatedFilename();
|
||||||
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabled()
|
protected boolean isEnabled()
|
||||||
{
|
{
|
||||||
return (_fileOut != null);
|
return _requestLogWriter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Set the number of days before rotated log files are deleted.
|
* Set the number of days before rotated log files are deleted.
|
||||||
*
|
*
|
||||||
|
@ -138,10 +129,9 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
*/
|
*/
|
||||||
public void setRetainDays(int retainDays)
|
public void setRetainDays(int retainDays)
|
||||||
{
|
{
|
||||||
_retainDays = retainDays;
|
_requestLogWriter.setRetainDays(retainDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the number of days before rotated log files are deleted.
|
* Retrieve the number of days before rotated log files are deleted.
|
||||||
*
|
*
|
||||||
|
@ -150,10 +140,9 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
@ManagedAttribute("number of days that log files are kept")
|
@ManagedAttribute("number of days that log files are kept")
|
||||||
public int getRetainDays()
|
public int getRetainDays()
|
||||||
{
|
{
|
||||||
return _retainDays;
|
return _requestLogWriter.getRetainDays();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Set append to log flag.
|
* Set append to log flag.
|
||||||
*
|
*
|
||||||
|
@ -162,10 +151,9 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
*/
|
*/
|
||||||
public void setAppend(boolean append)
|
public void setAppend(boolean append)
|
||||||
{
|
{
|
||||||
_append = append;
|
_requestLogWriter.setAppend(append);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Retrieve append to log flag.
|
* Retrieve append to log flag.
|
||||||
*
|
*
|
||||||
|
@ -174,22 +162,20 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
@ManagedAttribute("existing log files are appends to the new one")
|
@ManagedAttribute("existing log files are appends to the new one")
|
||||||
public boolean isAppend()
|
public boolean isAppend()
|
||||||
{
|
{
|
||||||
return _append;
|
return _requestLogWriter.isAppend();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Set the log file name date format.
|
* Set the log file name date format.
|
||||||
* @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
|
|
||||||
*
|
*
|
||||||
* @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream}
|
* @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream}
|
||||||
|
* @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
|
||||||
*/
|
*/
|
||||||
public void setFilenameDateFormat(String logFileDateFormat)
|
public void setFilenameDateFormat(String logFileDateFormat)
|
||||||
{
|
{
|
||||||
_filenameDateFormat = logFileDateFormat;
|
_requestLogWriter.setFilenameDateFormat(logFileDateFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the file name date format string.
|
* Retrieve the file name date format string.
|
||||||
*
|
*
|
||||||
|
@ -197,24 +183,15 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
*/
|
*/
|
||||||
public String getFilenameDateFormat()
|
public String getFilenameDateFormat()
|
||||||
{
|
{
|
||||||
return _filenameDateFormat;
|
return _requestLogWriter.getFilenameDateFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
@Override
|
@Override
|
||||||
public void write(String requestEntry) throws IOException
|
public void write(String requestEntry) throws IOException
|
||||||
{
|
{
|
||||||
synchronized(this)
|
_requestLogWriter.write(requestEntry);
|
||||||
{
|
|
||||||
if (_writer==null)
|
|
||||||
return;
|
|
||||||
_writer.write(requestEntry);
|
|
||||||
_writer.write(StringUtil.__LINE_SEPARATOR);
|
|
||||||
_writer.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Set up request logging and open log file.
|
* Set up request logging and open log file.
|
||||||
*
|
*
|
||||||
|
@ -223,25 +200,9 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
@Override
|
@Override
|
||||||
protected synchronized void doStart() throws Exception
|
protected synchronized void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (_filename != null)
|
|
||||||
{
|
|
||||||
_fileOut = new RolloverFileOutputStream(_filename,_append,_retainDays,TimeZone.getTimeZone(getLogTimeZone()),_filenameDateFormat,null);
|
|
||||||
_closeOut = true;
|
|
||||||
LOG.info("Opened " + getDatedFilename());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_fileOut = System.err;
|
|
||||||
|
|
||||||
_out = _fileOut;
|
|
||||||
|
|
||||||
synchronized(this)
|
|
||||||
{
|
|
||||||
_writer = new OutputStreamWriter(_out);
|
|
||||||
}
|
|
||||||
super.doStart();
|
super.doStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* Close the log file and perform cleanup.
|
* Close the log file and perform cleanup.
|
||||||
*
|
*
|
||||||
|
@ -253,29 +214,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
super.doStop();
|
super.doStop();
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_writer != null)
|
|
||||||
_writer.flush();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
if (_out != null && _closeOut)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_out.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
_out = null;
|
|
||||||
_fileOut = null;
|
|
||||||
_closeOut = false;
|
|
||||||
_writer = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,26 +16,55 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A <code>RequestLog</code> can be attached to a {@link org.eclipse.jetty.server.handler.RequestLogHandler} to enable
|
* A <code>RequestLog</code> can be attached to a {@link org.eclipse.jetty.server.handler.RequestLogHandler} to enable
|
||||||
* logging of requests/responses.
|
* logging of requests/responses.
|
||||||
|
*
|
||||||
* @see RequestLogHandler#setRequestLog(RequestLog)
|
* @see RequestLogHandler#setRequestLog(RequestLog)
|
||||||
* @see Server#setRequestLog(RequestLog)
|
* @see Server#setRequestLog(RequestLog)
|
||||||
*/
|
*/
|
||||||
public interface RequestLog
|
public interface RequestLog
|
||||||
{
|
{
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
/**
|
||||||
* @param request The request to log.
|
* @param request The request to log.
|
||||||
* @param response The response to log. Note that for some requests
|
* @param response The response to log. Note that for some requests
|
||||||
* the response instance may not have been fully populated (Eg 400 bad request
|
* the response instance may not have been fully populated (Eg 400 bad request
|
||||||
* responses are sent without a servlet response object). Thus for basic
|
* responses are sent without a servlet response object). Thus for basic
|
||||||
* log information it is best to consult {@link Response#getCommittedMetaData()}
|
* log information it is best to consult {@link Response#getCommittedMetaData()}
|
||||||
* and {@link Response#getHttpChannel()} directly.
|
* and {@link Response#getHttpChannel()} directly.
|
||||||
*/
|
*/
|
||||||
public void log(Request request, Response response);
|
void log(Request request, Response response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the generated log string to a log sink
|
||||||
|
*/
|
||||||
|
interface Writer
|
||||||
|
{
|
||||||
|
void write(String requestEntry) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Collection implements RequestLog
|
||||||
|
{
|
||||||
|
private final RequestLog[] _logs;
|
||||||
|
|
||||||
|
public Collection(RequestLog... logs)
|
||||||
|
{
|
||||||
|
_logs = logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Request request, Response response)
|
||||||
|
{
|
||||||
|
for (RequestLog log : _logs)
|
||||||
|
{
|
||||||
|
log.log(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.RolloverFileOutputStream;
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writer which outputs pre-formatted request log strings to a file using {@link RolloverFileOutputStream}.
|
||||||
|
*/
|
||||||
|
@ManagedObject("Request Log writer which writes to file")
|
||||||
|
public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(RequestLogWriter.class);
|
||||||
|
|
||||||
|
private String _filename;
|
||||||
|
private boolean _append;
|
||||||
|
private int _retainDays;
|
||||||
|
private boolean _closeOut;
|
||||||
|
private String _timeZone = "GMT";
|
||||||
|
private String _filenameDateFormat = null;
|
||||||
|
private transient OutputStream _out;
|
||||||
|
private transient OutputStream _fileOut;
|
||||||
|
private transient Writer _writer;
|
||||||
|
|
||||||
|
public RequestLogWriter()
|
||||||
|
{
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestLogWriter(String filename)
|
||||||
|
{
|
||||||
|
setAppend(true);
|
||||||
|
setRetainDays(31);
|
||||||
|
|
||||||
|
if (filename != null)
|
||||||
|
setFilename(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output file name of the request log.
|
||||||
|
* The file name may be in the format expected by
|
||||||
|
* {@link RolloverFileOutputStream}.
|
||||||
|
*
|
||||||
|
* @param filename file name of the request log
|
||||||
|
*/
|
||||||
|
public void setFilename(String filename)
|
||||||
|
{
|
||||||
|
if (filename != null)
|
||||||
|
{
|
||||||
|
filename = filename.trim();
|
||||||
|
if (filename.length() == 0)
|
||||||
|
filename = null;
|
||||||
|
}
|
||||||
|
_filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the output file name of the request log.
|
||||||
|
*
|
||||||
|
* @return file name of the request log
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("filename")
|
||||||
|
public String getFileName()
|
||||||
|
{
|
||||||
|
return _filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the file name of the request log with the expanded
|
||||||
|
* date wildcard if the output is written to the disk using
|
||||||
|
* {@link RolloverFileOutputStream}.
|
||||||
|
*
|
||||||
|
* @return file name of the request log, or null if not applicable
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("dated filename")
|
||||||
|
public String getDatedFilename()
|
||||||
|
{
|
||||||
|
if (_fileOut instanceof RolloverFileOutputStream)
|
||||||
|
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
protected boolean isEnabled()
|
||||||
|
{
|
||||||
|
return (_fileOut != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of days before rotated log files are deleted.
|
||||||
|
*
|
||||||
|
* @param retainDays number of days to keep a log file
|
||||||
|
*/
|
||||||
|
public void setRetainDays(int retainDays)
|
||||||
|
{
|
||||||
|
_retainDays = retainDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the number of days before rotated log files are deleted.
|
||||||
|
*
|
||||||
|
* @return number of days to keep a log file
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("number of days to keep a log file")
|
||||||
|
public int getRetainDays()
|
||||||
|
{
|
||||||
|
return _retainDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set append to log flag.
|
||||||
|
*
|
||||||
|
* @param append true - request log file will be appended after restart,
|
||||||
|
* false - request log file will be overwritten after restart
|
||||||
|
*/
|
||||||
|
public void setAppend(boolean append)
|
||||||
|
{
|
||||||
|
_append = append;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve append to log flag.
|
||||||
|
*
|
||||||
|
* @return value of the flag
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("if request log file will be appended after restart")
|
||||||
|
public boolean isAppend()
|
||||||
|
{
|
||||||
|
return _append;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the log file name date format.
|
||||||
|
*
|
||||||
|
* @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream}
|
||||||
|
* @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
|
||||||
|
*/
|
||||||
|
public void setFilenameDateFormat(String logFileDateFormat)
|
||||||
|
{
|
||||||
|
_filenameDateFormat = logFileDateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the file name date format string.
|
||||||
|
*
|
||||||
|
* @return the log File Date Format
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("log file name date format")
|
||||||
|
public String getFilenameDateFormat()
|
||||||
|
{
|
||||||
|
return _filenameDateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String requestEntry) throws IOException
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (_writer == null)
|
||||||
|
return;
|
||||||
|
_writer.write(requestEntry);
|
||||||
|
_writer.write(System.lineSeparator());
|
||||||
|
_writer.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void doStart() throws Exception
|
||||||
|
{
|
||||||
|
if (_filename != null)
|
||||||
|
{
|
||||||
|
_fileOut = new RolloverFileOutputStream(_filename, _append, _retainDays, TimeZone.getTimeZone(getTimeZone()), _filenameDateFormat, null);
|
||||||
|
_closeOut = true;
|
||||||
|
LOG.info("Opened " + getDatedFilename());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_fileOut = System.err;
|
||||||
|
|
||||||
|
_out = _fileOut;
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
_writer = new OutputStreamWriter(_out);
|
||||||
|
}
|
||||||
|
super.doStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeZone(String timeZone)
|
||||||
|
{
|
||||||
|
_timeZone = timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("timezone of the log")
|
||||||
|
public String getTimeZone()
|
||||||
|
{
|
||||||
|
return _timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStop() throws Exception
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
super.doStop();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_writer != null)
|
||||||
|
_writer.flush();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
if (_out != null && _closeOut)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_out.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
_out = null;
|
||||||
|
_fileOut = null;
|
||||||
|
_closeOut = false;
|
||||||
|
_writer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,49 +21,47 @@ package org.eclipse.jetty.server;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.log.Slf4jLog;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of NCSARequestLog where output is sent as a SLF4J INFO Log message on the named logger "org.eclipse.jetty.server.RequestLog"
|
* Implementation of NCSARequestLog where output is sent as a SLF4J INFO Log message on the named logger "org.eclipse.jetty.server.RequestLog"
|
||||||
|
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with an {@link Slf4jRequestLogWriter}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@ManagedObject("NCSA standard format request log to slf4j bridge")
|
@ManagedObject("NCSA standard format request log to slf4j bridge")
|
||||||
public class Slf4jRequestLog extends AbstractNCSARequestLog
|
public class Slf4jRequestLog extends AbstractNCSARequestLog
|
||||||
{
|
{
|
||||||
private Slf4jLog logger;
|
private final Slf4jRequestLogWriter _requestLogWriter;
|
||||||
private String loggerName;
|
|
||||||
|
|
||||||
public Slf4jRequestLog()
|
public Slf4jRequestLog()
|
||||||
{
|
{
|
||||||
// Default logger name (can be set)
|
this(new Slf4jRequestLogWriter());
|
||||||
this.loggerName = "org.eclipse.jetty.server.RequestLog";
|
}
|
||||||
|
|
||||||
|
public Slf4jRequestLog(Slf4jRequestLogWriter writer)
|
||||||
|
{
|
||||||
|
super(writer);
|
||||||
|
_requestLogWriter = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoggerName(String loggerName)
|
public void setLoggerName(String loggerName)
|
||||||
{
|
{
|
||||||
this.loggerName = loggerName;
|
_requestLogWriter.setLoggerName(loggerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLoggerName()
|
public String getLoggerName()
|
||||||
{
|
{
|
||||||
return loggerName;
|
return _requestLogWriter.getLoggerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabled()
|
protected boolean isEnabled()
|
||||||
{
|
{
|
||||||
return logger != null;
|
return _requestLogWriter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(String requestEntry) throws IOException
|
public void write(String requestEntry) throws IOException
|
||||||
{
|
{
|
||||||
logger.info(requestEntry);
|
_requestLogWriter.write(requestEntry);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected synchronized void doStart() throws Exception
|
|
||||||
{
|
|
||||||
logger = new Slf4jLog(loggerName);
|
|
||||||
super.doStart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.log.Slf4jLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request log writer using a Slf4jLog Logger
|
||||||
|
*/
|
||||||
|
@ManagedObject("Slf4j RequestLog Writer")
|
||||||
|
public class Slf4jRequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer
|
||||||
|
{
|
||||||
|
private Slf4jLog logger;
|
||||||
|
private String loggerName;
|
||||||
|
|
||||||
|
public Slf4jRequestLogWriter()
|
||||||
|
{
|
||||||
|
// Default logger name (can be set)
|
||||||
|
this.loggerName = "org.eclipse.jetty.server.RequestLog";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoggerName(String loggerName)
|
||||||
|
{
|
||||||
|
this.loggerName = loggerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute("logger name")
|
||||||
|
public String getLoggerName()
|
||||||
|
{
|
||||||
|
return loggerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isEnabled()
|
||||||
|
{
|
||||||
|
return logger != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String requestEntry) throws IOException
|
||||||
|
{
|
||||||
|
logger.info(requestEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void doStart() throws Exception
|
||||||
|
{
|
||||||
|
logger = new Slf4jLog(loggerName);
|
||||||
|
super.doStart();
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,9 +20,10 @@ package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User object that encapsulates user identity and operations such as run-as-role actions,
|
* User object that encapsulates user identity and operations such as run-as-role actions,
|
||||||
* checking isUserInRole and getUserPrincipal.
|
* checking isUserInRole and getUserPrincipal.
|
||||||
|
@ -64,6 +65,12 @@ public interface UserIdentity
|
||||||
*/
|
*/
|
||||||
interface Scope
|
interface Scope
|
||||||
{
|
{
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return The context handler that the identity is being considered within
|
||||||
|
*/
|
||||||
|
ContextHandler getContextHandler();
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return The context path that the identity is being considered within
|
* @return The context path that the identity is being considered within
|
||||||
|
|
|
@ -0,0 +1,603 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.CustomRequestLog;
|
||||||
|
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
|
||||||
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
|
import org.eclipse.jetty.server.QuietServletException;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
|
import org.eclipse.jetty.util.DateCache;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
public class CustomRequestLogTest
|
||||||
|
{
|
||||||
|
CustomRequestLog _log;
|
||||||
|
Server _server;
|
||||||
|
LocalConnector _connector;
|
||||||
|
BlockingQueue<String> _entries = new BlockingArrayQueue<>();
|
||||||
|
BlockingQueue<Long> requestTimes = new BlockingArrayQueue<>();
|
||||||
|
ServerConnector _serverConnector;
|
||||||
|
URI _serverURI;
|
||||||
|
|
||||||
|
private final static long DELAY = 2000;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before() throws Exception
|
||||||
|
{
|
||||||
|
_server = new Server();
|
||||||
|
_connector = new LocalConnector(_server);
|
||||||
|
_serverConnector = new ServerConnector(_server);
|
||||||
|
_server.addConnector(_connector);
|
||||||
|
_server.addConnector(_serverConnector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHandlerServerStart(String formatString) throws Exception
|
||||||
|
{
|
||||||
|
_serverConnector.setPort(0);
|
||||||
|
_serverConnector.getBean(HttpConnectionFactory.class).getHttpConfiguration().addCustomizer(new ForwardedRequestCustomizer());
|
||||||
|
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||||
|
_log = new CustomRequestLog(writer, formatString);
|
||||||
|
_server.setRequestLog(_log);
|
||||||
|
_server.setHandler(new TestHandler());
|
||||||
|
_server.start();
|
||||||
|
|
||||||
|
String host = _serverConnector.getHost();
|
||||||
|
if (host == null)
|
||||||
|
{
|
||||||
|
host = "localhost";
|
||||||
|
}
|
||||||
|
int localPort = _serverConnector.getLocalPort();
|
||||||
|
_serverURI = new URI(String.format("http://%s:%d/",host,localPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModifier() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%s: %!404,301{Referer}i");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /error404 HTTP/1.0\nReferer: testReferer\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("404: -"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET /error301 HTTP/1.0\nReferer: testReferer\n\n");
|
||||||
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("301: -"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET /success HTTP/1.0\nReferer: testReferer\n\n");
|
||||||
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("200: testReferer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoublePercent() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%%%%%%a");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("%%%a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogAddress() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{local}a|%{local}p|" +
|
||||||
|
"%{remote}a|%{remote}p|" +
|
||||||
|
"%{server}a|%{server}p|" +
|
||||||
|
"%{client}a|%{client}p");
|
||||||
|
|
||||||
|
Enumeration e = NetworkInterface.getNetworkInterfaces();
|
||||||
|
while(e.hasMoreElements())
|
||||||
|
{
|
||||||
|
NetworkInterface n = (NetworkInterface) e.nextElement();
|
||||||
|
if (n.isLoopback())
|
||||||
|
{
|
||||||
|
Enumeration ee = n.getInetAddresses();
|
||||||
|
while (ee.hasMoreElements())
|
||||||
|
{
|
||||||
|
InetAddress i = (InetAddress)ee.nextElement();
|
||||||
|
try (Socket client = newSocket(i.getHostAddress(), _serverURI.getPort()))
|
||||||
|
{
|
||||||
|
OutputStream os = client.getOutputStream();
|
||||||
|
String request = "GET / HTTP/1.0\n" +
|
||||||
|
"Host: webtide.com:1234\n" +
|
||||||
|
"Forwarded: For=10.1.2.3:1337\n" +
|
||||||
|
"\n\n";
|
||||||
|
os.write(request.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
os.flush();
|
||||||
|
|
||||||
|
String[] log = _entries.poll(5, TimeUnit.SECONDS).split("\\|");
|
||||||
|
assertThat(log.length, is(8));
|
||||||
|
|
||||||
|
String localAddr = log[0];
|
||||||
|
String localPort = log[1];
|
||||||
|
String remoteAddr = log[2];
|
||||||
|
String remotePort = log[3];
|
||||||
|
String serverAddr = log[4];
|
||||||
|
String serverPort = log[5];
|
||||||
|
String clientAddr = log[6];
|
||||||
|
String clientPort = log[7];
|
||||||
|
|
||||||
|
assertThat(serverPort, is("1234"));
|
||||||
|
assertThat(clientPort, is("1337"));
|
||||||
|
assertThat(remotePort, not(clientPort));
|
||||||
|
assertThat(localPort, not(serverPort));
|
||||||
|
|
||||||
|
assertThat(serverAddr, is("webtide.com"));
|
||||||
|
assertThat(clientAddr, is("10.1.2.3"));
|
||||||
|
assertThat(InetAddress.getByName(remoteAddr), is(client.getInetAddress()));
|
||||||
|
assertThat(InetAddress.getByName(localAddr), is(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogBytesSent() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("BytesSent: %O");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\necho: hello world\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("BytesSent: 11"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogBytesReceived() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("BytesReceived: %I");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n" +
|
||||||
|
"Content-Length: 11\n\n" +
|
||||||
|
"hello world");
|
||||||
|
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("BytesReceived: 11"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogBytesTransferred() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("BytesTransferred: %S");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n" +
|
||||||
|
"echo: hello world\n" +
|
||||||
|
"Content-Length: 11\n\n" +
|
||||||
|
"hello world");
|
||||||
|
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("BytesTransferred: 22"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestCookie() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestCookies: %{cookieName}C, %{cookie2}C, %{cookie3}C");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\nCookie: cookieName=cookieValue; cookie2=value2\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("RequestCookies: cookieValue, value2, -"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestCookies() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestCookies: %C");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\nCookie: cookieName=cookieValue; cookie2=value2\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("RequestCookies: cookieName=cookieValue;cookie2=value2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogEnvironmentVar() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("EnvironmentVar: %{JAVA_HOME}e");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("EnvironmentVar: " + System.getenv("JAVA_HOME") + ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestProtocol() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%H");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("HTTP/1.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestHeader() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestHeader: %{Header1}i, %{Header2}i, %{Header3}i");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\nHeader1: value1\nHeader2: value2\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("RequestHeader: value1, value2, -"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogKeepAliveRequests() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("KeepAliveRequests: %k");
|
||||||
|
|
||||||
|
LocalConnector.LocalEndPoint connect = _connector.connect();
|
||||||
|
connect.addInput("GET /a HTTP/1.0\n" +
|
||||||
|
"Connection: keep-alive\n\n");
|
||||||
|
connect.addInput("GET /a HTTP/1.1\n" +
|
||||||
|
"Host: localhost\n\n");
|
||||||
|
|
||||||
|
assertThat(connect.getResponse(), containsString("200 OK"));
|
||||||
|
assertThat(connect.getResponse(), containsString("200 OK"));
|
||||||
|
|
||||||
|
connect.addInput("GET /a HTTP/1.0\n\n");
|
||||||
|
assertThat(connect.getResponse(), containsString("200 OK"));
|
||||||
|
|
||||||
|
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("KeepAliveRequests: 1"));
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("KeepAliveRequests: 2"));
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("KeepAliveRequests: 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
|
@Test
|
||||||
|
public void testLogKeepAliveRequestsHttp2() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("KeepAliveRequests: %k");
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestMethod() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestMethod: %m");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("RequestMethod: GET"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogResponseHeader() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("ResponseHeader: %{Header1}o, %{Header2}o, %{Header3}o");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /responseHeaders HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("ResponseHeader: value1, value2, -"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogQueryString() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("QueryString: %q");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /path?queryString HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("QueryString: ?queryString"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestFirstLine() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestFirstLin: %r");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /path?query HTTP/1.0\nHeader: null\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("RequestFirstLin: GET /path?query HTTP/1.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogResponseStatus() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("LogResponseStatus: %s");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /error404 HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("LogResponseStatus: 404"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET /error301 HTTP/1.0\n\n");
|
||||||
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("LogResponseStatus: 301"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("LogResponseStatus: 200"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestTime() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestTime: %t");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
long requestTime = requestTimes.poll(5,TimeUnit.SECONDS);
|
||||||
|
DateCache dateCache = new DateCache(_log.DEFAULT_DATE_FORMAT, Locale.getDefault(), "GMT");
|
||||||
|
assertThat(log, is("RequestTime: ["+ dateCache.format(requestTime) +"]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestTimeCustomFormats() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{EEE MMM dd HH:mm:ss zzz yyyy}t\n" +
|
||||||
|
"%{EEE MMM dd HH:mm:ss zzz yyyy|EST}t\n" +
|
||||||
|
"%{EEE MMM dd HH:mm:ss zzz yyyy|EST|ja}t");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
long requestTime = requestTimes.poll(5,TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
DateCache dateCache1 = new DateCache("EEE MMM dd HH:mm:ss zzz yyyy", Locale.getDefault(), "GMT");
|
||||||
|
DateCache dateCache2 = new DateCache("EEE MMM dd HH:mm:ss zzz yyyy", Locale.getDefault(), "EST");
|
||||||
|
DateCache dateCache3 = new DateCache("EEE MMM dd HH:mm:ss zzz yyyy", Locale.forLanguageTag("ja"), "EST");
|
||||||
|
|
||||||
|
String[] logs = log.split("\n");
|
||||||
|
assertThat(logs[0], is("["+ dateCache1.format(requestTime) +"]"));
|
||||||
|
assertThat(logs[1], is("["+ dateCache2.format(requestTime) +"]"));
|
||||||
|
assertThat(logs[2], is("["+ dateCache3.format(requestTime) +"]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogLatencyMicroseconds() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{us}T");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /delay HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
long lowerBound = requestTimes.poll(5 ,TimeUnit.SECONDS);
|
||||||
|
long upperBound = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long measuredDuration = Long.parseLong(log);
|
||||||
|
long durationLowerBound = TimeUnit.MILLISECONDS.toMicros(DELAY);
|
||||||
|
long durationUpperBound = TimeUnit.MILLISECONDS.toMicros(upperBound-lowerBound);
|
||||||
|
|
||||||
|
assertThat(measuredDuration, greaterThanOrEqualTo(durationLowerBound));
|
||||||
|
assertThat(measuredDuration, lessThanOrEqualTo(durationUpperBound));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogLatencyMilliseconds() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{ms}T");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /delay HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
long lowerBound = requestTimes.poll(5 ,TimeUnit.SECONDS);
|
||||||
|
long upperBound = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long measuredDuration = Long.parseLong(log);
|
||||||
|
long durationLowerBound = DELAY;
|
||||||
|
long durationUpperBound = upperBound-lowerBound;
|
||||||
|
|
||||||
|
assertThat(measuredDuration, greaterThanOrEqualTo(durationLowerBound));
|
||||||
|
assertThat(measuredDuration, lessThanOrEqualTo(durationUpperBound));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogLatencySeconds() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{s}T");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /delay HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
long lowerBound = requestTimes.poll(5 ,TimeUnit.SECONDS);
|
||||||
|
long upperBound = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long measuredDuration = Long.parseLong(log);
|
||||||
|
long durationLowerBound = TimeUnit.MILLISECONDS.toSeconds(DELAY);
|
||||||
|
long durationUpperBound = TimeUnit.MILLISECONDS.toSeconds(upperBound-lowerBound);
|
||||||
|
|
||||||
|
assertThat(measuredDuration, greaterThanOrEqualTo(durationLowerBound));
|
||||||
|
assertThat(measuredDuration, lessThanOrEqualTo(durationUpperBound));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogUrlRequestPath() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("UrlRequestPath: %U");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /path?query HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("UrlRequestPath: /path"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogConnectionStatus() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%U ConnectionStatus: %s %X");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /one HTTP/1.0\n\n");
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/one ConnectionStatus: 200 -"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET /two HTTP/1.1\n" +
|
||||||
|
"Host: localhost\n" +
|
||||||
|
"Connection: close\n" +
|
||||||
|
"\n");
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/two ConnectionStatus: 200 -"));
|
||||||
|
|
||||||
|
LocalConnector.LocalEndPoint connect = _connector.connect();
|
||||||
|
connect.addInput("GET /three HTTP/1.0\n" +
|
||||||
|
"Connection: keep-alive\n\n");
|
||||||
|
connect.addInput("GET /four HTTP/1.1\n" +
|
||||||
|
"Host: localhost\n\n");
|
||||||
|
connect.addInput("GET /BAD HTTP/1.1\n\n");
|
||||||
|
assertThat(connect.getResponse(), containsString("200 OK"));
|
||||||
|
assertThat(connect.getResponse(), containsString("200 OK"));
|
||||||
|
assertThat(connect.getResponse(), containsString("400 "));
|
||||||
|
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/three ConnectionStatus: 200 +"));
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/four ConnectionStatus: 200 +"));
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/BAD ConnectionStatus: 400 -"));
|
||||||
|
|
||||||
|
_connector.getResponse("GET /abort HTTP/1.1\n" +
|
||||||
|
"Host: localhost\n" +
|
||||||
|
"\n");
|
||||||
|
connect.getResponse();
|
||||||
|
assertThat(_entries.poll(5,TimeUnit.SECONDS), is("/abort ConnectionStatus: 200 X"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
|
@Test
|
||||||
|
public void testLogRequestTrailer() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{trailerName}ti");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
fail(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
|
@Test
|
||||||
|
public void testLogResponseTrailer() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("%{trailerName}to");
|
||||||
|
|
||||||
|
_connector.getResponse("GET / HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
fail(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Socket newSocket() throws Exception
|
||||||
|
{
|
||||||
|
return newSocket(_serverURI.getHost(), _serverURI.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Socket newSocket(String host, int port) throws Exception
|
||||||
|
{
|
||||||
|
Socket socket = new Socket(host, port);
|
||||||
|
socket.setSoTimeout(10000);
|
||||||
|
socket.setTcpNoDelay(true);
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestRequestLogWriter implements RequestLog.Writer
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void write(String requestEntry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_entries.add(requestEntry);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
if (request.getRequestURI().contains("error404"))
|
||||||
|
{
|
||||||
|
response.setStatus(404);
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("error301"))
|
||||||
|
{
|
||||||
|
response.setStatus(301);
|
||||||
|
}
|
||||||
|
else if (request.getHeader("echo") != null)
|
||||||
|
{
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
outputStream.print(request.getHeader("echo"));
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("responseHeaders"))
|
||||||
|
{
|
||||||
|
response.addHeader("Header1", "value1");
|
||||||
|
response.addHeader("Header2", "value2");
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("/abort"))
|
||||||
|
{
|
||||||
|
response.getOutputStream().println("data");
|
||||||
|
response.flushBuffer();
|
||||||
|
baseRequest.getHttpChannel().abort(new QuietServletException("test abort"));
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("delay"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(DELAY);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestTimes.offer(baseRequest.getTimeStamp());
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
|
||||||
|
if (request.getContentLength() > 0)
|
||||||
|
{
|
||||||
|
InputStream in = request.getInputStream();
|
||||||
|
while (in.read()>0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server.handler;
|
package org.eclipse.jetty.server.handler;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.contains;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
@ -39,7 +35,9 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.BadMessageException;
|
import org.eclipse.jetty.http.BadMessageException;
|
||||||
import org.eclipse.jetty.server.AbstractNCSARequestLog;
|
import org.eclipse.jetty.server.AbstractNCSARequestLog;
|
||||||
|
import org.eclipse.jetty.server.CustomRequestLog;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
|
import org.eclipse.jetty.server.HttpChannel;
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.RequestLog;
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
|
@ -47,30 +45,50 @@ import org.eclipse.jetty.server.Response;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Assumptions;
|
import org.junit.jupiter.api.Assumptions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
public class RequestLogTest
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
|
||||||
|
public class NcsaRequestLogTest
|
||||||
{
|
{
|
||||||
Log _log;
|
RequestLog _log;
|
||||||
Server _server;
|
Server _server;
|
||||||
LocalConnector _connector;
|
LocalConnector _connector;
|
||||||
|
BlockingQueue<String> _entries = new BlockingArrayQueue<>();
|
||||||
|
StacklessLogging stacklessLogging;
|
||||||
|
|
||||||
@BeforeEach
|
private void setup(String logType) throws Exception
|
||||||
public void before() throws Exception
|
|
||||||
{
|
{
|
||||||
_log = new Log();
|
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||||
|
|
||||||
|
switch (logType)
|
||||||
|
{
|
||||||
|
case "customNCSA":
|
||||||
|
_log = new CustomRequestLog(writer, CustomRequestLog.EXTENDED_NCSA_FORMAT);
|
||||||
|
break;
|
||||||
|
case "NCSA":
|
||||||
|
{
|
||||||
|
AbstractNCSARequestLog logNCSA = new AbstractNCSARequestLog(writer);
|
||||||
|
logNCSA.setExtended(true);
|
||||||
|
_log = logNCSA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("invalid logType");
|
||||||
|
}
|
||||||
|
|
||||||
_server = new Server();
|
_server = new Server();
|
||||||
_connector = new LocalConnector(_server);
|
_connector = new LocalConnector(_server);
|
||||||
_server.addConnector(_connector);
|
_server.addConnector(_connector);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void testHandlerServerStart() throws Exception
|
void testHandlerServerStart() throws Exception
|
||||||
|
@ -92,230 +110,273 @@ public class RequestLogTest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before() throws Exception
|
||||||
|
{
|
||||||
|
stacklessLogging = new StacklessLogging(HttpChannel.class);
|
||||||
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() throws Exception
|
public void after() throws Exception
|
||||||
{
|
{
|
||||||
_server.stop();
|
_server.stop();
|
||||||
|
stacklessLogging.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testNotHandled() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testNotHandled(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo HTTP/1.0\" 404 "));
|
assertThat(log,containsString("GET /foo HTTP/1.0\" 404 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testRequestLine() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testRequestLine(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?data=1 HTTP/1.0\nhost: host:80\n\n");
|
_connector.getResponse("GET /foo?data=1 HTTP/1.0\nhost: host:80\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?data=1 HTTP/1.0\" 200 "));
|
assertThat(log,containsString("GET /foo?data=1 HTTP/1.0\" 200 "));
|
||||||
|
|
||||||
_connector.getResponse("GET //bad/foo?data=1 HTTP/1.0\n\n");
|
_connector.getResponse("GET //bad/foo?data=1 HTTP/1.0\n\n");
|
||||||
log = _log.entries.poll(5,TimeUnit.SECONDS);
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET //bad/foo?data=1 HTTP/1.0\" 200 "));
|
assertThat(log,containsString("GET //bad/foo?data=1 HTTP/1.0\" 200 "));
|
||||||
|
|
||||||
_connector.getResponse("GET http://host:80/foo?data=1 HTTP/1.0\n\n");
|
_connector.getResponse("GET http://host:80/foo?data=1 HTTP/1.0\n\n");
|
||||||
log = _log.entries.poll(5,TimeUnit.SECONDS);
|
log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET http://host:80/foo?data=1 HTTP/1.0\" 200 "));
|
assertThat(log,containsString("GET http://host:80/foo?data=1 HTTP/1.0\" 200 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testHTTP10Host() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testHTTP10Host(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse(
|
_connector.getResponse(
|
||||||
"GET /foo?name=value HTTP/1.0\n"+
|
"GET /foo?name=value HTTP/1.0\n"+
|
||||||
"Host: servername\n"+
|
"Host: servername\n"+
|
||||||
"\n");
|
"\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?name=value"));
|
assertThat(log,containsString("GET /foo?name=value"));
|
||||||
assertThat(log,containsString(" 200 "));
|
assertThat(log,containsString(" 200 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testHTTP11() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testHTTP11(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse(
|
_connector.getResponse(
|
||||||
"GET /foo?name=value HTTP/1.1\n"+
|
"GET /foo?name=value HTTP/1.1\n"+
|
||||||
"Host: servername\n"+
|
"Host: servername\n"+
|
||||||
"\n");
|
"\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?name=value"));
|
assertThat(log,containsString("GET /foo?name=value"));
|
||||||
assertThat(log,containsString(" 200 "));
|
assertThat(log,containsString(" 200 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testAbsolute() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testAbsolute(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse(
|
_connector.getResponse(
|
||||||
"GET http://hostname:8888/foo?name=value HTTP/1.1\n"+
|
"GET http://hostname:8888/foo?name=value HTTP/1.1\n"+
|
||||||
"Host: servername\n"+
|
"Host: servername\n"+
|
||||||
"\n");
|
"\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET http://hostname:8888/foo?name=value"));
|
assertThat(log,containsString("GET http://hostname:8888/foo?name=value"));
|
||||||
assertThat(log,containsString(" 200 "));
|
assertThat(log,containsString(" 200 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testQuery() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testQuery(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?name=value HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo?name=value HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?name=value"));
|
assertThat(log,containsString("GET /foo?name=value"));
|
||||||
assertThat(log,containsString(" 200 "));
|
assertThat(log,containsString(" 200 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testSmallData() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testSmallData(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?data=42 HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo?data=42 HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?"));
|
assertThat(log,containsString("GET /foo?"));
|
||||||
assertThat(log,containsString(" 200 42 "));
|
assertThat(log,containsString(" 200 42 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testBigData() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testBigData(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?data=102400 HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo?data=102400 HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?"));
|
assertThat(log,containsString("GET /foo?"));
|
||||||
assertThat(log,containsString(" 200 102400 "));
|
assertThat(log,containsString(" 200 102400 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testStatus() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testStatus(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?status=206 HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo?status=206 HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?"));
|
assertThat(log,containsString("GET /foo?"));
|
||||||
assertThat(log,containsString(" 206 0 "));
|
assertThat(log,containsString(" 206 0 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testStatusData() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testStatusData(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo?status=206&data=42 HTTP/1.0\n\n");
|
_connector.getResponse("GET /foo?status=206&data=42 HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo?"));
|
assertThat(log,containsString("GET /foo?"));
|
||||||
assertThat(log,containsString(" 206 42 "));
|
assertThat(log,containsString(" 206 42 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testBadRequest() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testBadRequest(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("XXXXXXXXXXXX\n\n");
|
_connector.getResponse("XXXXXXXXXXXX\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("\"- - -\""));
|
assertThat(log,containsString("\"- - -\""));
|
||||||
assertThat(log,containsString(" 400 "));
|
assertThat(log,containsString(" 400 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testBadCharacter() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testBadCharacter(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("METHOD /f\00o HTTP/1.0\n\n");
|
_connector.getResponse("METHOD /f\00o HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("\"- - -\""));
|
assertThat(log,containsString("\"- - -\""));
|
||||||
assertThat(log,containsString(" 400 "));
|
assertThat(log,containsString(" 400 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testBadVersion() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testBadVersion(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("METHOD /foo HTTP/9\n\n");
|
_connector.getResponse("METHOD /foo HTTP/9\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("\"- - -\""));
|
assertThat(log,containsString("\"- - -\""));
|
||||||
assertThat(log,containsString(" 400 "));
|
assertThat(log,containsString(" 400 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testLongURI() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testLongURI(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
char[] chars = new char[10000];
|
char[] chars = new char[10000];
|
||||||
Arrays.fill(chars,'o');
|
Arrays.fill(chars,'o');
|
||||||
String ooo = new String(chars);
|
String ooo = new String(chars);
|
||||||
_connector.getResponse("METHOD /f"+ooo+" HTTP/1.0\n\n");
|
_connector.getResponse("METHOD /f"+ooo+" HTTP/1.0\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("\"- - -\""));
|
assertThat(log,containsString("\"- - -\""));
|
||||||
assertThat(log,containsString(" 414 "));
|
assertThat(log,containsString(" 414 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testLongHeader() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testLongHeader(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
char[] chars = new char[10000];
|
char[] chars = new char[10000];
|
||||||
Arrays.fill(chars,'o');
|
Arrays.fill(chars,'o');
|
||||||
String ooo = new String(chars);
|
String ooo = new String(chars);
|
||||||
_connector.getResponse("METHOD /foo HTTP/1.0\name: f+"+ooo+"\n\n");
|
_connector.getResponse("METHOD /foo HTTP/1.0\name: f+"+ooo+"\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("\"METHOD /foo HTTP/1.0\""));
|
assertThat(log,containsString("\"METHOD /foo HTTP/1.0\""));
|
||||||
assertThat(log,containsString(" 431 "));
|
assertThat(log,containsString(" 431 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testBadRequestNoHost() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testBadRequestNoHost(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET /foo HTTP/1.1\n\n");
|
_connector.getResponse("GET /foo HTTP/1.1\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET /foo "));
|
assertThat(log,containsString("GET /foo "));
|
||||||
assertThat(log,containsString(" 400 "));
|
assertThat(log,containsString(" 400 "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testUseragentWithout() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testUseragentWithout(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET http://[:1]/foo HTTP/1.1\nReferer: http://other.site\n\n");
|
_connector.getResponse("GET http://[:1]/foo HTTP/1.1\nReferer: http://other.site\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET http://[:1]/foo "));
|
assertThat(log,containsString("GET http://[:1]/foo "));
|
||||||
assertThat(log,containsString(" 400 50 \"http://other.site\" \"-\" - "));
|
assertThat(log,containsString(" 400 50 \"http://other.site\" \"-\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest()
|
||||||
public void testUseragentWith() throws Exception
|
@ValueSource(strings = {"customNCSA", "NCSA"})
|
||||||
|
public void testUseragentWith(String logType) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
testHandlerServerStart();
|
testHandlerServerStart();
|
||||||
|
|
||||||
_connector.getResponse("GET http://[:1]/foo HTTP/1.1\nReferer: http://other.site\nUser-Agent: Mozilla/5.0 (test)\n\n");
|
_connector.getResponse("GET http://[:1]/foo HTTP/1.1\nReferer: http://other.site\nUser-Agent: Mozilla/5.0 (test)\n\n");
|
||||||
String log = _log.entries.poll(5,TimeUnit.SECONDS);
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
assertThat(log,containsString("GET http://[:1]/foo "));
|
assertThat(log,containsString("GET http://[:1]/foo "));
|
||||||
assertThat(log,containsString(" 400 50 \"http://other.site\" \"Mozilla/5.0 (test)\" - "));
|
assertThat(log,containsString(" 400 50 \"http://other.site\" \"Mozilla/5.0 (test)\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -324,22 +385,28 @@ public class RequestLogTest
|
||||||
{
|
{
|
||||||
List<Object[]> data = new ArrayList<>();
|
List<Object[]> data = new ArrayList<>();
|
||||||
|
|
||||||
data.add(new Object[] { new NoopHandler(), "/noop", "\"GET /noop HTTP/1.0\" 404" });
|
for(String logType : Arrays.asList("customNCSA","NCSA"))
|
||||||
data.add(new Object[] { new HelloHandler(), "/hello", "\"GET /hello HTTP/1.0\" 200" });
|
{
|
||||||
data.add(new Object[] { new ResponseSendErrorHandler(), "/sendError", "\"GET /sendError HTTP/1.0\" 599" });
|
data.add(new Object[]{logType, new NoopHandler(), "/noop", "\"GET /noop HTTP/1.0\" 404"});
|
||||||
data.add(new Object[] { new ServletExceptionHandler(), "/sex", "\"GET /sex HTTP/1.0\" 500" });
|
data.add(new Object[]{logType, new HelloHandler(), "/hello", "\"GET /hello HTTP/1.0\" 200"});
|
||||||
data.add(new Object[] { new IOExceptionHandler(), "/ioex", "\"GET /ioex HTTP/1.0\" 500" });
|
data.add(new Object[]{logType, new ResponseSendErrorHandler(), "/sendError", "\"GET /sendError HTTP/1.0\" 599"});
|
||||||
data.add(new Object[] { new RuntimeExceptionHandler(), "/rtex", "\"GET /rtex HTTP/1.0\" 500" });
|
data.add(new Object[]{logType, new ServletExceptionHandler(), "/sex", "\"GET /sex HTTP/1.0\" 500"});
|
||||||
data.add(new Object[] { new BadMessageHandler(), "/bad", "\"GET /bad HTTP/1.0\" 499" });
|
data.add(new Object[]{logType, new IOExceptionHandler(), "/ioex", "\"GET /ioex HTTP/1.0\" 500"});
|
||||||
data.add(new Object[] { new AbortHandler(), "/bad", "\"GET /bad HTTP/1.0\" 488" });
|
data.add(new Object[]{logType, new IOExceptionPartialHandler(), "/ioex", "\"GET /ioex HTTP/1.0\" 200"});
|
||||||
|
data.add(new Object[]{logType, new RuntimeExceptionHandler(), "/rtex", "\"GET /rtex HTTP/1.0\" 500"});
|
||||||
|
data.add(new Object[]{logType, new BadMessageHandler(), "/bad", "\"GET /bad HTTP/1.0\" 499"});
|
||||||
|
data.add(new Object[]{logType, new AbortHandler(), "/bad", "\"GET /bad HTTP/1.0\" 488"});
|
||||||
|
data.add(new Object[]{logType, new AbortPartialHandler(), "/bad", "\"GET /bad HTTP/1.0\" 200"});
|
||||||
|
}
|
||||||
|
|
||||||
return data.stream().map(Arguments::of);
|
return data.stream().map(Arguments::of);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testServerRequestLog(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testServerRequestLog(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
_server.setHandler(testHandler);
|
_server.setHandler(testHandler);
|
||||||
startServer();
|
startServer();
|
||||||
|
@ -349,8 +416,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testLogHandlerWrapper(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testLogHandlerWrapper(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
RequestLogHandler handler = new RequestLogHandler();
|
RequestLogHandler handler = new RequestLogHandler();
|
||||||
handler.setRequestLog(_log);
|
handler.setRequestLog(_log);
|
||||||
handler.setHandler(testHandler);
|
handler.setHandler(testHandler);
|
||||||
|
@ -362,8 +430,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testLogHandlerCollectionFirst(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testLogHandlerCollectionFirst(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
RequestLogHandler handler = new RequestLogHandler();
|
RequestLogHandler handler = new RequestLogHandler();
|
||||||
handler.setRequestLog(_log);
|
handler.setRequestLog(_log);
|
||||||
HandlerCollection handlers = new HandlerCollection();
|
HandlerCollection handlers = new HandlerCollection();
|
||||||
|
@ -377,8 +446,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testLogHandlerCollectionLast(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testLogHandlerCollectionLast(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
RequestLogHandler handler = new RequestLogHandler();
|
RequestLogHandler handler = new RequestLogHandler();
|
||||||
handler.setRequestLog(_log);
|
handler.setRequestLog(_log);
|
||||||
// This is the old ordering of request handler and it cannot well handle thrown exception
|
// This is the old ordering of request handler and it cannot well handle thrown exception
|
||||||
|
@ -399,8 +469,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testErrorHandler(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testErrorHandler(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
||||||
{
|
{
|
||||||
|
@ -428,16 +499,14 @@ public class RequestLogTest
|
||||||
startServer();
|
startServer();
|
||||||
makeRequest(requestPath);
|
makeRequest(requestPath);
|
||||||
assertRequestLog(expectedLogEntry, _log);
|
assertRequestLog(expectedLogEntry, _log);
|
||||||
|
|
||||||
if (!(testHandler instanceof HelloHandler))
|
|
||||||
assertThat(errors,contains(requestPath));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testOKErrorHandler(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testOKErrorHandler(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
AbstractHandler.ErrorDispatchHandler wrapper = new AbstractHandler.ErrorDispatchHandler()
|
||||||
{
|
{
|
||||||
|
@ -463,8 +532,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testAsyncDispatch(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testAsyncDispatch(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
_server.setHandler(new AbstractHandler()
|
_server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
|
@ -493,8 +563,9 @@ public class RequestLogTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("data")
|
@MethodSource("data")
|
||||||
public void testAsyncComplete(Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
public void testAsyncComplete(String logType, Handler testHandler, String requestPath, String expectedLogEntry) throws Exception
|
||||||
{
|
{
|
||||||
|
setup(logType);
|
||||||
_server.setRequestLog(_log);
|
_server.setRequestLog(_log);
|
||||||
_server.setHandler(new AbstractHandler()
|
_server.setHandler(new AbstractHandler()
|
||||||
{
|
{
|
||||||
|
@ -545,12 +616,12 @@ public class RequestLogTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertRequestLog(final String expectedLogEntry, Log log) throws Exception
|
private void assertRequestLog(final String expectedLogEntry, RequestLog log) throws Exception
|
||||||
{
|
{
|
||||||
String line = log.entries.poll(5, TimeUnit.SECONDS);
|
String line = _entries.poll(5, TimeUnit.SECONDS);
|
||||||
Assertions.assertNotNull(line);
|
Assertions.assertNotNull(line);
|
||||||
assertThat(line,containsString(expectedLogEntry));
|
assertThat(line,containsString(expectedLogEntry));
|
||||||
Assertions.assertTrue(log.entries.isEmpty());
|
Assertions.assertTrue(_entries.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CaptureLog extends AbstractLifeCycle implements RequestLog
|
public static class CaptureLog extends AbstractLifeCycle implements RequestLog
|
||||||
|
@ -623,6 +694,20 @@ public class RequestLogTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class IOExceptionPartialHandler extends AbstractTestHandler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
response.setContentLength(100);
|
||||||
|
response.getOutputStream().println("You were expecting maybe a ");
|
||||||
|
response.flushBuffer();
|
||||||
|
throw new IOException("expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class RuntimeExceptionHandler extends AbstractTestHandler
|
private static class RuntimeExceptionHandler extends AbstractTestHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -652,6 +737,20 @@ public class RequestLogTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class AbortPartialHandler extends AbstractTestHandler
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
response.setContentLength(100);
|
||||||
|
response.getOutputStream().println("You were expecting maybe a ");
|
||||||
|
response.flushBuffer();
|
||||||
|
baseRequest.getHttpChannel().abort(new Throwable("bomb"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class OKErrorHandler extends ErrorHandler
|
public static class OKErrorHandler extends ErrorHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -675,30 +774,14 @@ public class RequestLogTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestRequestLogWriter implements RequestLog.Writer
|
||||||
private class Log extends AbstractNCSARequestLog
|
|
||||||
{
|
{
|
||||||
public BlockingQueue<String> entries = new BlockingArrayQueue<>();
|
|
||||||
|
|
||||||
Log()
|
|
||||||
{
|
|
||||||
super.setExtended(true);
|
|
||||||
super.setLogLatency(true);
|
|
||||||
super.setLogCookies(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabled()
|
public void write(String requestEntry)
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(String requestEntry) throws IOException
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
entries.add(requestEntry);
|
_entries.add(requestEntry);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
|
@ -32,7 +32,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
import javax.servlet.Servlet;
|
import javax.servlet.Servlet;
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
|
@ -756,6 +755,13 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
@Override
|
||||||
|
public ContextHandler getContextHandler()
|
||||||
|
{
|
||||||
|
return ContextHandler.getContextHandler(_config.getServletContext());
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
|
* @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.servlet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.CustomRequestLog;
|
||||||
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
public class CustomRequestLogTest
|
||||||
|
{
|
||||||
|
RequestLog _log;
|
||||||
|
Server _server;
|
||||||
|
LocalConnector _connector;
|
||||||
|
BlockingQueue<String> _entries = new BlockingArrayQueue<>();
|
||||||
|
String _tmpDir = System.getProperty("java.io.tmpdir");
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
_server = new Server();
|
||||||
|
_connector = new LocalConnector(_server);
|
||||||
|
_server.addConnector(_connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHandlerServerStart(String formatString) throws Exception
|
||||||
|
{
|
||||||
|
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||||
|
context.setContextPath("/context");
|
||||||
|
context.setResourceBase(_tmpDir);
|
||||||
|
context.addServlet(TestServlet.class, "/servlet/*");
|
||||||
|
|
||||||
|
TestRequestLogWriter writer = new TestRequestLogWriter();
|
||||||
|
_log = new CustomRequestLog(writer, formatString);
|
||||||
|
_server.setRequestLog(_log);
|
||||||
|
_server.setHandler(context);
|
||||||
|
_server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogFilename() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("Filename: %f");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /context/servlet/info HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, is("Filename: " + _tmpDir + "/servlet/info"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLogRequestHandler() throws Exception
|
||||||
|
{
|
||||||
|
testHandlerServerStart("RequestHandler: %R");
|
||||||
|
|
||||||
|
_connector.getResponse("GET /context/servlet/ HTTP/1.0\n\n");
|
||||||
|
String log = _entries.poll(5,TimeUnit.SECONDS);
|
||||||
|
assertThat(log, Matchers.containsString("TestServlet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequestLogWriter implements RequestLog.Writer
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void write(String requestEntry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_entries.add(requestEntry);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestServlet extends HttpServlet
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
if (request.getRequestURI().contains("error404"))
|
||||||
|
{
|
||||||
|
response.setStatus(404);
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("error301"))
|
||||||
|
{
|
||||||
|
response.setStatus(301);
|
||||||
|
}
|
||||||
|
else if (request.getHeader("echo") != null)
|
||||||
|
{
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
outputStream.print(request.getHeader("echo"));
|
||||||
|
}
|
||||||
|
else if (request.getRequestURI().contains("responseHeaders"))
|
||||||
|
{
|
||||||
|
response.addHeader("Header1", "value1");
|
||||||
|
response.addHeader("Header2", "value2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue