Issue #113 - reformat, javadoc update and changes after review

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2018-11-27 14:04:37 +01:00
parent 2cd579353c
commit b35df419bb
10 changed files with 406 additions and 396 deletions

View File

@ -17,22 +17,22 @@
<New class="org.eclipse.jetty.server.AsyncRequestLogWriter">
<Arg><Property name="jetty.base" default="." />/<Property>
<Name>jetty.customrequestlog.filePath</Name>
<Default><Property name="jetty.customrequestlog.dir" default="logs"/>/yyyy_mm_dd.request.log</Default>
<Default><Property name="jetty.requestlog.dir" default="logs"/>/yyyy_mm_dd.request.log</Default>
</Property></Arg>
<Arg/>
<Set name="filenameDateFormat"><Property name="jetty.customrequestlog.filenameDateFormat" default="yyyy_MM_dd"/></Set>
<Set name="retainDays"><Property name="jetty.customrequestlog.retainDays" default="90"/></Set>
<Set name="append"><Property name="jetty.customrequestlog.append" default="false"/></Set>
<Set name="timeZone"><Property name="jetty.customrequestlog.timezone" default="GMT"/></Set>
<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.customrequestlog.formatString">
<Property name="jetty.requestlog.formatString">
<Default>
<Get class="org.eclipse.jetty.server.CustomRequestLog" name="NCSA_FORMAT"/>
<Get class="org.eclipse.jetty.server.CustomRequestLog" name="EXTENDED_NCSA_FORMAT"/>
</Default>
</Property>
</Arg>

View File

@ -7,7 +7,7 @@ Enables a format string style request log.
requestlog
[tags]
customrequestlog
requestlog
[depend]
server
@ -20,22 +20,22 @@ logs/
[ini-template]
## Logging directory (relative to $jetty.base)
# jetty.customrequestlog.dir=logs
# jetty.requestlog.dir=logs
## File path
# jetty.customrequestlog.filePath=${jetty.customrequestlog.dir}/yyyy_mm_dd.request.log
# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
## Date format for rollovered files (uses SimpleDateFormat syntax)
# jetty.customrequestlog.filenameDateFormat=yyyy_MM_dd
# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
## How many days to retain old log files
# jetty.customrequestlog.retainDays=90
# jetty.requestlog.retainDays=90
## Whether to append to existing file
# jetty.customrequestlog.append=false
# jetty.requestlog.append=false
## Timezone of the log entries
# jetty.customrequestlog.timezone=GMT
# jetty.requestlog.timezone=GMT
## Format string
# jetty.customrequestlog.formatString=%a - %u %t "%r" %s %B "%{Referer}i" "%{User-Agent}i" "%C"
# jetty.requestlog.formatString=%a - %u %t "%r" %s %B "%{Referer}i" "%{User-Agent}i" "%C"

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.util.Locale;
import javax.servlet.http.Cookie;
import org.eclipse.jetty.http.HttpHeader;
@ -36,7 +37,8 @@ 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
* 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.
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#NCSA_FORMAT} with a {@link RequestLog.Writer}
*
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with a {@link RequestLog.Writer}
*/
@Deprecated
public class AbstractNCSARequestLog extends ContainerLifeCycle implements RequestLog
@ -67,6 +69,7 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
/**
* Is logging enabled
*
* @return true if logging is enabled
*/
protected boolean isEnabled()
@ -76,6 +79,7 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
/**
* Write requestEntry out. (to disk or slf4j log)
*
* @param requestEntry the request entry
* @throws IOException if unable to write the entry
*/
@ -84,9 +88,9 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
_requestLogWriter.write(requestEntry);
}
private void append(StringBuilder buf,String s)
private void append(StringBuilder buf, String s)
{
if (s==null || s.length()==0)
if (s == null || s.length() == 0)
buf.append('-');
else
buf.append(s);
@ -113,7 +117,7 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
if (_logServer)
{
append(buf,request.getServerName());
append(buf, request.getServerName());
buf.append(' ');
}
@ -128,9 +132,9 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
buf.append(addr);
buf.append(" - ");
String auth = getAuthentication(request);
append(buf,auth==null?"-":auth);
append(buf, auth == null ? "-" : auth);
buf.append(" [");
if (_logDateCache != null)
@ -139,15 +143,15 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
buf.append(request.getTimeStamp());
buf.append("] \"");
append(buf,request.getMethod());
append(buf, request.getMethod());
buf.append(' ');
append(buf,request.getOriginalURI());
append(buf, request.getOriginalURI());
buf.append(' ');
append(buf,request.getProtocol());
append(buf, request.getProtocol());
buf.append("\" ");
int status = response.getCommittedMetaData().getStatus();
if (status >=0)
if (status >= 0)
{
buf.append((char)('0' + ((status / 100) % 10)));
buf.append((char)('0' + ((status / 10) % 10)));
@ -222,21 +226,22 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
LOG.warn(e);
}
}
/**
* Extract the user authentication
*
* @param request The request to extract from
* @return The string to log for authenticated user.
*/
protected String getAuthentication(Request request)
{
Authentication authentication = request.getAuthentication();
if (authentication instanceof Authentication.User)
return ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
// TODO extract the user name if it is Authentication.Deferred and return as '?username'
return null;
}
@ -425,7 +430,7 @@ public class AbstractNCSARequestLog extends ContainerLifeCycle implements Reques
{
if (_logDateFormat != null)
{
_logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
_logDateCache = new DateCache(_logDateFormat, _logLocale, _logTimeZone);
}
if (_ignorePaths != null && _ignorePaths.length > 0)

View File

@ -22,7 +22,7 @@ import java.util.concurrent.BlockingQueue;
/**
* An asynchronously writing NCSA Request Log
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#NCSA_FORMAT} with an {@link AsyncRequestLogWriter}
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with an {@link AsyncRequestLogWriter}
*/
@Deprecated
public class AsyncNCSARequestLog extends NCSARequestLog

View File

@ -26,6 +26,10 @@ 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);
@ -38,19 +42,19 @@ public class AsyncRequestLogWriter extends RequestLogWriter
this(null, null);
}
public AsyncRequestLogWriter(String filename,BlockingQueue<String> queue)
public AsyncRequestLogWriter(String filename, BlockingQueue<String> queue)
{
super(filename);
if (queue==null)
queue=new BlockingArrayQueue<>(1024);
_queue=queue;
if (queue == null)
queue = new BlockingArrayQueue<>(1024);
_queue = queue;
}
private class WriterThread extends Thread
{
WriterThread()
{
setName("AsyncRequestLogWriter@"+Integer.toString(AsyncRequestLogWriter.this.hashCode(),16));
setName("AsyncRequestLogWriter@" + Integer.toString(AsyncRequestLogWriter.this.hashCode(), 16));
}
@Override
@ -61,13 +65,13 @@ public class AsyncRequestLogWriter extends RequestLogWriter
try
{
String log = _queue.poll(10, TimeUnit.SECONDS);
if (log!=null)
if (log != null)
AsyncRequestLogWriter.super.write(log);
while(!_queue.isEmpty())
while (!_queue.isEmpty())
{
log=_queue.poll();
if (log!=null)
log = _queue.poll();
if (log != null)
AsyncRequestLogWriter.super.write(log);
}
}
@ -97,7 +101,7 @@ public class AsyncRequestLogWriter extends RequestLogWriter
_thread.interrupt();
_thread.join();
super.doStop();
_thread=null;
_thread = null;
}
@Override
@ -107,7 +111,7 @@ public class AsyncRequestLogWriter extends RequestLogWriter
{
if (_warnedFull)
LOG.warn("Log Queue overflow");
_warnedFull=true;
_warnedFull = true;
}
}
}

View File

@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.Cookie;
import org.eclipse.jetty.http.HttpFields;
@ -37,6 +38,7 @@ import org.eclipse.jetty.http.pathmap.PathMappings;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.DateCache;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -46,237 +48,223 @@ import static java.lang.invoke.MethodHandles.foldArguments;
import static java.lang.invoke.MethodType.methodType;
/**
<table>
<caption>CustomRequestLog Format Codes</caption>
<tr>
<td><b>Format String</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>%%</td>
<td>The percent sign.</td>
</tr>
<tr>
<td valign="top">%{format}a</td>
<td>
Client IP address of the request.
Valid formats are {server, client, local, remote}
where server and client are the logical addresses
where local and remote are the physical addresses
</td>
</tr>
<tr>
<td valign="top">%a</td>
<td>Client IP address of the request.</td>
</tr>
<tr>
<td valign="top">%{c}a</td>
<td>Underlying peer IP address of the connection.</td>
</tr>
<tr>
<td valign="top">%A</td>
<td>Local IP-address.</td>
</tr>
<tr>
<td valign="top">%h</td>
<td>Remote hostname. Will log a dotted-string form of the IP if the Hostname cannot be resolved.</td>
</tr>
<tr>
<td valign="top">%v</td>
<td>
todo this is now %{server}a
The canonical ServerName of the server serving the request.</td>
</tr>
<tr>
<td valign="top">%B</td>
<td>Size of response in bytes, excluding HTTP headers.</td>
</tr>
<tr>
<td valign="top">%b</td>
<td>Size of response in bytes, excluding HTTP headers. In CLF format, i.e. a '-' rather than a 0 when no bytes are sent.</td>
</tr>
<tr>
<td valign="top">%{VARNAME}C</td>
<td>
The contents of cookie VARNAME in the request sent to the server. Only version 0 cookies are fully supported.
Optional VARNAME parameter, without this parameter %C will log all cookies from the request.
</td>
</tr>
<tr>
<td valign="top">%D</td>
<td>The time taken to serve the request, in microseconds.</td>
</tr>
<tr>
<td valign="top">%{VARNAME}e</td>
<td>The contents of the environment variable VARNAME.</td>
</tr>
<tr>
<td valign="top">%f</td>
<td>Filename.</td>
</tr>
<tr>
<td valign="top">%H</td>
<td>The request protocol.</td>
</tr>
<tr>
<td valign="top">%{VARNAME}i</td>
<td>The contents of VARNAME: header line(s) in the request sent to the server.</td>
</tr>
<tr>
<td valign="top">%k</td>
<td>Number of keepalive requests handled on this connection.
Interesting if KeepAlive is being used, so that, for example, a '1' means the first keepalive request
after the initial one, '2' the second, etc...; otherwise this is always 0 (indicating the initial request).</td>
</tr>
<tr>
<td valign="top">%m</td>
<td>The request method.</td>
</tr>
<tr>
<td valign="top">%{VARNAME}o</td>
<td>The contents of VARNAME: header line(s) in the response.</td>
</tr>
<tr>
<td valign="top">%p</td>
<td>The canonical port of the server serving the request.
todo merge this with below
</td>
</tr>
<tr>
<td valign="top">%{format}p</td>
<td>The canonical port of the server serving the request, or the server's actual port, or the client's actual port.
Valid formats are canonical, local, or remote.
todo update this documenatation
server, client logical
local, remote physical
</td>
</tr>
<tr>
<td valign="top">%q</td>
<td>The query string (prepended with a ? if a query string exists, otherwise an empty string).</td>
</tr>
<tr>
<td valign="top">%r</td>
<td>First line of request.</td>
</tr>
<tr>
<td valign="top">%R</td>
<td>The handler generating the response (if any).</td>
</tr>
<tr>
<td valign="top">%s</td>
<td>Response status.</td>
</tr>
<tr>
<td valign="top">%{format}t</td>
<td>
The time, in the form given by an optional format, parameter (default format [18/Sep/2011:19:18:28 -0400] where
the last number indicates the timezone offset from GMT.)
<br>
The format parameter should be in a format supported by {@link DateCache}
</td>
</tr>
<tr>
<td valign="top">%T</td>
<td>The time taken to serve the request, in seconds.</td>
</tr>
<tr>
<td valign="top">%{UNIT}T</td>
<td>The time taken to serve the request, in a time unit given by UNIT.
Valid units are ms for milliseconds, us for microseconds, and s for seconds.
Using s gives the same result as %T without any format; using us gives the same result as %D.</td>
</tr>
<tr>
<td valign="top">%{d}u</td>
<td>
Remote user if the request was authenticated. May be bogus if return status (%s) is 401 (unauthorized).
Optional parameter d, with this parameter deferred authentication will also be checked.
</td>
</tr>
<tr>
<td valign="top">%U</td>
<td>The URL path requested, not including any query string.</td>
</tr>
<tr>
<td valign="top">%X</td>
<td>
Connection status when response is completed:
<pre>
X = Connection aborted before the response completed.
+ = Connection may be kept alive after the response is sent.
- = Connection will be closed after the response is sent.</pre>
</td>
</tr>
<tr>
<td valign="top">%I</td>
<td>Bytes received.</td>
</tr>
<tr>
<td valign="top">%O</td>
<td>Bytes sent.</td>
</tr>
<tr>
<td valign="top">%S</td>
<td>Bytes transferred (received and sent). This is the combination of %I and %O.</td>
</tr>
<tr>
<td valign="top">%{VARNAME}^ti</td>
<td>The contents of VARNAME: trailer line(s) in the request sent to the server.</td>
</tr>
<tr>
<td>%{VARNAME}^to</td>
<td>The contents of VARNAME: trailer line(s) in the response sent from the server.</td>
</tr>
</table>
* A flexible RequestLog, which produces log strings in a customizable format.
* The Logger takes a format string where request characteristics can be added using "%" format codes which are
* replaced by the corresponding value in the log output.
* <p>
* The terms server, client, local and remote are used to refer to the different addresses and ports
* which can be logged. Server and client refer to the logical addresses which can be modified in the request
* headers. Where local and remote refer to the physical addresses which may be a proxy between the
* end-user and the server.
*
*
* <br><br>Percent codes are specified in the format %MODIFIERS{PARAM}CODE
*<pre>
* MODIFIERS:
* Optional list of comma separated HTTP status codes which may be preceded by a single "!" to indicate
* negation. If the status code is not in the list the literal string "-" will be logged instead of
* the resulting value from the percent code.
* {PARAM}:
* Parameter string which may be optional depending on the percent code used.
* CODE:
* A one or two character code specified by the {@link CustomRequestLog} table of format codes.
* </pre>
*
* <table>
* <caption>Format Codes</caption>
* <tr>
* <td><b>Format String</b></td>
* <td><b>Description</b></td>
* </tr>
*
* <tr>
* <td>%%</td>
* <td>The percent sign.</td>
* </tr>
*
* <tr>
* <td valign="top">%{format}a</td>
* <td>
* Address or Hostname. Valid formats are {server, client, local, remote}
* Optional format parameter which will be server by default.
* <br>
* Where server and client are the logical addresses which can be modified in the request headers, while local and
* remote are the physical addresses so may be a proxy between the end-user and the server.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{format}p</td>
* <td>
* Port. Valid formats are {server, client, local, remote}
* Optional format parameter which will be server by default.
* <br>
* Where server and client are the logical ports which can be modified in the request headers, while local and
* remote are the physical ports so may be to a proxy between the end-user and the server.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{clf}I</td>
* <td>
* Size of request in bytes, excluding HTTP headers.
* Optional parameter with value of clf to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{clf}O</td>
* <td>
* Size of response in bytes, excluding HTTP headers.
* Optional parameter with value of clf to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{clf}S</td>
* <td>
* Bytes transferred (received and sent). This is the combination of %I and %O.
* Optional parameter with value of clf to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{VARNAME}C</td>
* <td>
* The contents of cookie VARNAME in the request sent to the server. Only version 0 cookies are fully supported.
* Optional VARNAME parameter, without this parameter %C will log all cookies from the request.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%D</td>
* <td>The time taken to serve the request, in microseconds.</td>
* </tr>
*
* <tr>
* <td valign="top">%{VARNAME}e</td>
* <td>The contents of the environment variable VARNAME.</td>
* </tr>
*
* <tr>
* <td valign="top">%f</td>
* <td>Filename.</td>
* </tr>
*
* <tr>
* <td valign="top">%H</td>
* <td>The request protocol.</td>
* </tr>
*
* <tr>
* <td valign="top">%{VARNAME}i</td>
* <td>The contents of VARNAME: header line(s) in the request sent to the server.</td>
* </tr>
*
* <tr>
* <td valign="top">%k</td>
* <td>Number of keepalive requests handled on this connection.
* Interesting if KeepAlive is being used, so that, for example, a '1' means the first keepalive request
* after the initial one, '2' the second, etc...; otherwise this is always 0 (indicating the initial request).</td>
* </tr>
*
* <tr>
* <td valign="top">%m</td>
* <td>The request method.</td>
* </tr>
*
* <tr>
* <td valign="top">%{VARNAME}o</td>
* <td>The contents of VARNAME: header line(s) in the response.</td>
* </tr>
*
* <tr>
* <td valign="top">%q</td>
* <td>The query string (prepended with a ? if a query string exists, otherwise an empty string).</td>
* </tr>
*
* <tr>
* <td valign="top">%r</td>
* <td>First line of request.</td>
* </tr>
*
* <tr>
* <td valign="top">%R</td>
* <td>The handler generating the response (if any).</td>
* </tr>
*
* <tr>
* <td valign="top">%s</td>
* <td>Response status.</td>
* </tr>
*
* <tr>
* <td valign="top">%{format}t</td>
* <td>
* The time, in the form given by an optional format, parameter (default format [18/Sep/2011:19:18:28 -0400] where
* the last number indicates the timezone offset from GMT.)
* <br>
* The format parameter should be in a format supported by {@link DateCache}
* </td>
* </tr>
*
* <tr>
* <td valign="top">%T</td>
* <td>The time taken to serve the request, in seconds.</td>
* </tr>
*
* <tr>
* <td valign="top">%{UNIT}T</td>
* <td>The time taken to serve the request, in a time unit given by UNIT.
* Valid units are ms for milliseconds, us for microseconds, and s for seconds.
* Using s gives the same result as %T without any format; using us gives the same result as %D.</td>
* </tr>
*
* <tr>
* <td valign="top">%{d}u</td>
* <td>
* Remote user if the request was authenticated. May be bogus if return status (%s) is 401 (unauthorized).
* Optional parameter d, with this parameter deferred authentication will also be checked.
* </td>
* </tr>
*
* <tr>
* <td valign="top">%U</td>
* <td>The URL path requested, not including any query string.</td>
* </tr>
*
* <tr>
* <td valign="top">%X</td>
* <td>
* Connection status when response is completed:
* <pre>
* X = Connection aborted before the response completed.
* + = Connection may be kept alive after the response is sent.
* - = Connection will be closed after the response is sent.</pre>
* </td>
* </tr>
*
* <tr>
* <td valign="top">%{VARNAME}^ti</td>
* <td>The contents of VARNAME: trailer line(s) in the request sent to the server.</td>
* </tr>
*
* <tr>
* <td>%{VARNAME}^to</td>
* <td>The contents of VARNAME: trailer line(s) in the response sent from the server.</td>
* </tr>
* </table>
*/
@ManagedObject("Custom format request log")
public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
{
protected static final Logger LOG = Log.getLogger(CustomRequestLog.class);
public static final String NCSA_FORMAT = "%a - %u %t \"%r\" %s %B \"%{Referer}i\" \"%{User-Agent}i\" \"%C\"";
public static final String DEFAULT_DATE_FORMAT = "dd/MMM/yyyy:HH:mm:ss ZZZ";
public static final String NCSA_FORMAT = "%{client}a - %u %t \"%r\" %s %O";
public static final String EXTENDED_NCSA_FORMAT = "%{client}a - %u %t \"%r\" %s %O \"%{Referer}i\" \"%{User-Agent}i\"";
private static ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
private String[] _ignorePaths;
@ -286,9 +274,11 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private RequestLog.Writer _requestLogWriter;
private final MethodHandle _logHandle;
private final String _formatString;
public CustomRequestLog(RequestLog.Writer writer, String formatString)
{
_formatString = formatString;
_requestLogWriter = writer;
addBean(_requestLogWriter);
@ -335,7 +325,8 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
/**
* Extract the user authentication
* @param request The request to extract from
*
* @param request The request to extract from
* @param checkDeferred Whether to check for deferred authentication
* @return The string to log for authenticated user.
*/
@ -346,7 +337,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
String name = null;
boolean deferred = false;
if (checkDeferred && authentication instanceof Authentication.Deferred)
if (checkDeferred && authentication instanceof Authentication.Deferred)
{
authentication = ((Authentication.Deferred)authentication).authenticate(request);
deferred = true;
@ -355,7 +346,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
if (authentication instanceof Authentication.User)
name = ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
return (name==null) ? null : (deferred ? ("?"+name):name);
return (name == null) ? null : (deferred ? ("?" + name) : name);
}
/**
@ -378,6 +369,18 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
return _ignorePaths;
}
/**
* Retrieve the format string.
*
* @return the format string
*/
@ManagedAttribute("format string")
public String getFormatString()
{
return _formatString;
}
/**
* Set up request logging and open log file.
*
@ -442,7 +445,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void append(StringBuilder buf, String s)
{
if (s==null || s.length()==0)
if (s == null || s.length() == 0)
buf.append('-');
else
buf.append(s);
@ -474,11 +477,21 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static List<Token> getTokens(String formatString)
{
/*
Extracts literal strings and percent codes out of the format string.
We will either match a percent code of the format %MODIFIERS{PARAM}CODE, or a literal string
until the next percent code or the end of the formatString is reached.
where
MODIFIERS is an optional comma separated list of numbers.
{PARAM} is an optional string parameter to the percent code.
CODE is a 1 to 2 character string corresponding to a format code.
*/
final Pattern PATTERN = Pattern.compile("^(?:%(?<MOD>!?[0-9,]+)?(?:\\{(?<ARG>[^}]+)})?(?<CODE>(?:(?:ti)|(?:to)|[a-zA-Z%]))|(?<LITERAL>[^%]+))(?<REMAINING>.*)");
List<Token> tokens = new ArrayList<>();
String remaining = formatString;
while(remaining.length()>0)
while (remaining.length() > 0)
{
Matcher m = PATTERN.matcher(remaining);
if (m.matches())
@ -542,6 +555,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
this.literal = null;
}
public Token(String literal)
{
this.code = null;
@ -554,17 +568,16 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
public boolean isLiteralString()
{
return(literal != null);
return (literal != null);
}
public boolean isPercentCode()
{
return(code != null);
return (code != null);
}
}
private MethodHandle updateLogHandle(MethodHandle logHandle, MethodHandle append, String literal)
{
return foldArguments(logHandle, dropArguments(dropArguments(append.bindTo(literal), 1, Request.class), 2, Response.class));
@ -577,11 +590,11 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
String responseCode = Integer.toString(response.getStatus());
if (negated)
{
return(!modifiers.contains(responseCode));
return (!modifiers.contains(responseCode));
}
else
{
return(modifiers.contains(responseCode));
return (modifiers.contains(responseCode));
}
}
@ -602,6 +615,9 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
case "a":
{
if (arg == null || arg.isEmpty())
arg = "server";
String method;
switch (arg)
{
@ -629,23 +645,35 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
break;
}
case "h":
case "p":
{
String method = "logRemoteHostName";
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
if (arg == null || arg.isEmpty())
arg = "server";
case "B":
{
String method = "logResponseSize";
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
String method;
switch (arg)
{
case "server":
method = "logServerPort";
break;
case "client":
method = "logClientPort";
break;
case "local":
method = "logLocalPort";
break;
case "remote":
method = "logRemotePort";
break;
default:
throw new IllegalArgumentException("Invalid arg for %p");
}
case "b":
{
String method = "logResponseSizeCLF";
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
@ -656,9 +684,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
if (arg == null || arg.isEmpty())
method = "logBytesReceived";
else if (arg.equals("CLF"))
{
method = "logBytesReceivedCLF";
}
else
throw new IllegalArgumentException("Invalid argument for %I");
@ -672,11 +698,23 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
if (arg == null || arg.isEmpty())
method = "logBytesSent";
else if (arg.equals("CLF"))
{
method = "logBytesSentCLF";
}
else
throw new IllegalArgumentException("Invalid argument for %I");
throw new IllegalArgumentException("Invalid argument for %O");
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
case "S":
{
String method;
if (arg == null || arg.isEmpty())
method = "logBytesTransferred";
else if (arg.equals("CLF"))
method = "logBytesTransferredCLF";
else
throw new IllegalArgumentException("Invalid argument for %S");
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
@ -767,36 +805,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
break;
}
case "p":
{
String method;
switch (arg)
{
case "server":
method = "logServerPort";
break;
case "client":
method = "logClientPort";
break;
case "local":
method = "logLocalPort";
break;
case "remote":
method = "logRemotePort";
break;
default:
throw new IllegalArgumentException("Invalid arg for %p");
}
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
case "q":
{
String method = "logQueryString";
@ -829,9 +837,9 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
{
DateCache logDateCache;
if (arg == null || arg.isEmpty())
logDateCache = new DateCache(DEFAULT_DATE_FORMAT, _logLocale , _logTimeZone);
logDateCache = new DateCache(DEFAULT_DATE_FORMAT, _logLocale, _logTimeZone);
else
logDateCache = new DateCache(arg, _logLocale , _logTimeZone);
logDateCache = new DateCache(arg, _logLocale, _logTimeZone);
String method = "logRequestTime";
MethodType logTypeDateCache = methodType(Void.TYPE, DateCache.class, StringBuilder.class, Request.class, Response.class);
@ -891,14 +899,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
break;
}
case "S":
{
String method = "logBytesTransferred";
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
break;
}
case "ti":
{
if (arg == null || arg.isEmpty())
@ -940,7 +940,6 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
}
//-----------------------------------------------------------------------------------//
private static void logNothing(StringBuilder b, Request request, Response response)
@ -996,7 +995,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void logResponseSizeCLF(StringBuilder b, Request request, Response response)
{
long written = response.getHttpChannel().getBytesWritten();
if (written==0)
if (written == 0)
b.append('-');
else
b.append(written);
@ -1007,17 +1006,47 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
b.append(response.getHttpChannel().getBytesWritten());
}
private static void logBytesSentCLF(StringBuilder b, Request request, Response response)
{
long sent = response.getHttpChannel().getBytesWritten();
if (sent == 0)
b.append('-');
else
b.append(sent);
}
private static void logBytesReceived(StringBuilder b, Request request, Response response)
{
//todo this be content received rather than consumed
b.append(request.getHttpInput().getContentConsumed());
}
private static void logBytesReceivedCLF(StringBuilder b, Request request, Response response)
{
//todo this be content received rather than consumed
long received = request.getHttpInput().getContentConsumed();
if (received == 0)
b.append('-');
else
b.append(received);
}
private static void logBytesTransferred(StringBuilder b, Request request, Response response)
{
//todo this be content received rather than consumed
b.append(request.getHttpInput().getContentConsumed() + response.getHttpOutput().getWritten());
}
private static void logBytesTransferredCLF(StringBuilder b, Request request, Response response)
{
//todo this be content received rather than consumed
long transferred = request.getHttpInput().getContentConsumed() + response.getHttpOutput().getWritten();
if (transferred == 0)
b.append('-');
else
b.append(transferred);
}
private static void logRequestCookie(String arg, StringBuilder b, Request request, Response response)
{
@ -1059,12 +1088,12 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void logFilename(StringBuilder b, Request request, Response response)
{
UserIdentity.Scope scope = request.getUserIdentityScope();
if (scope==null || scope.getContextHandler()==null)
if (scope == null || scope.getContextHandler() == null)
b.append('-');
else
{
ContextHandler context = scope.getContextHandler();
int lengthToStrip = scope.getContextPath().length()>1 ? scope.getContextPath().length() : 0;
int lengthToStrip = scope.getContextPath().length() > 1 ? scope.getContextPath().length() : 0;
String filename = context.getServletContext().getRealPath(request.getPathInfo().substring(lengthToStrip));
append(b, filename);
}
@ -1101,7 +1130,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void logQueryString(StringBuilder b, Request request, Response response)
{
append(b, "?"+request.getQueryString());
append(b, "?" + request.getQueryString());
}
private static void logRequestFirstLine(StringBuilder b, Request request, Response response)
@ -1166,7 +1195,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void logConnectionStatus(StringBuilder b, Request request, Response response)
{
b.append(request.getHttpChannel().isResponseCompleted() ? (request.getHttpChannel().isPersistent() ? '+' : '-') : 'X');
b.append(request.getHttpChannel().isResponseCompleted() ? (request.getHttpChannel().isPersistent() ? '+' : '-') : 'X');
}

View File

@ -32,7 +32,8 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
* 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.
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#NCSA_FORMAT} with a {@link RequestLogWriter}
*
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#EXTENDED_NCSA_FORMAT} with a {@link RequestLogWriter}
*/
@Deprecated
@ManagedObject("NCSA standard format request log")
@ -40,7 +41,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
{
private final RequestLogWriter _requestLogWriter;
/* ------------------------------------------------------------ */
/**
* Create request log object with default settings.
*/
@ -49,7 +49,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
this((String)null);
}
/* ------------------------------------------------------------ */
/**
* Create request log object with specified output file name.
*
@ -62,7 +61,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
this(new RequestLogWriter(filename));
}
/* ------------------------------------------------------------ */
/**
* Create request log object given a RequestLogWriter file name.
*
@ -76,21 +74,18 @@ public class NCSARequestLog extends AbstractNCSARequestLog
setExtended(true);
}
/* ------------------------------------------------------------ */
/**
* 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)
{
_requestLogWriter.setFilename(filename);
}
/* ------------------------------------------------------------ */
@Override
public void setLogTimeZone(String tz)
{
@ -98,7 +93,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
_requestLogWriter.setTimeZone(tz);
}
/* ------------------------------------------------------------ */
/**
* Retrieve the output file name of the request log.
*
@ -109,8 +103,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
{
return _requestLogWriter.getFileName();
}
/* ------------------------------------------------------------ */
/**
* Retrieve the file name of the request log with the expanded
* date wildcard if the output is written to the disk using
@ -123,14 +116,12 @@ public class NCSARequestLog extends AbstractNCSARequestLog
return _requestLogWriter.getDatedFilename();
}
/* ------------------------------------------------------------ */
@Override
protected boolean isEnabled()
{
return _requestLogWriter.isEnabled();
}
/* ------------------------------------------------------------ */
/**
* Set the number of days before rotated log files are deleted.
*
@ -141,7 +132,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
_requestLogWriter.setRetainDays(retainDays);
}
/* ------------------------------------------------------------ */
/**
* Retrieve the number of days before rotated log files are deleted.
*
@ -153,7 +143,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
return _requestLogWriter.getRetainDays();
}
/* ------------------------------------------------------------ */
/**
* Set append to log flag.
*
@ -165,7 +154,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
_requestLogWriter.setAppend(append);
}
/* ------------------------------------------------------------ */
/**
* Retrieve append to log flag.
*
@ -177,19 +165,17 @@ public class NCSARequestLog extends AbstractNCSARequestLog
return _requestLogWriter.isAppend();
}
/* ------------------------------------------------------------ */
/**
* 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}
* @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
*/
public void setFilenameDateFormat(String logFileDateFormat)
{
_requestLogWriter.setFilenameDateFormat(logFileDateFormat);
}
/* ------------------------------------------------------------ */
/**
* Retrieve the file name date format string.
*
@ -200,14 +186,12 @@ public class NCSARequestLog extends AbstractNCSARequestLog
return _requestLogWriter.getFilenameDateFormat();
}
/* ------------------------------------------------------------ */
@Override
public void write(String requestEntry) throws IOException
{
_requestLogWriter.write(requestEntry);
}
/* ------------------------------------------------------------ */
/**
* Set up request logging and open log file.
*
@ -219,7 +203,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
super.doStart();
}
/* ------------------------------------------------------------ */
/**
* Close the log file and perform cleanup.
*

View File

@ -16,30 +16,34 @@
// ========================================================================
//
package org.eclipse.jetty.server;
package org.eclipse.jetty.server;
import java.io.IOException;
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.
*
* @see RequestLogHandler#setRequestLog(RequestLog)
* @see Server#setRequestLog(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
* the response instance may not have been fully populated (Eg 400 bad request
* responses are sent without a servlet response object). Thus for basic
* log information it is best to consult {@link Response#getCommittedMetaData()}
* and {@link Response#getHttpChannel()} directly.
* the response instance may not have been fully populated (Eg 400 bad request
* responses are sent without a servlet response object). Thus for basic
* log information it is best to consult {@link Response#getCommittedMetaData()}
* and {@link Response#getHttpChannel()} directly.
*/
void log(Request request, Response response);
/**
* Writes the generated log string to a log sink
*/
interface Writer
{
void write(String requestEntry) throws IOException;

View File

@ -29,6 +29,9 @@ 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}.
*/
public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer
{
private static final Logger LOG = Log.getLogger(RequestLogWriter.class);
@ -53,7 +56,7 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
setAppend(true);
setRetainDays(31);
if(filename != null)
if (filename != null)
setFilename(filename);
}
@ -63,7 +66,6 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
* {@link RolloverFileOutputStream}.
*
* @param filename file name of the request log
*
*/
public void setFilename(String filename)
{
@ -86,7 +88,6 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
return _filename;
}
/**
* Retrieve the file name of the request log with the expanded
* date wildcard if the output is written to the disk using
@ -126,7 +127,6 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
return _retainDays;
}
/**
* Set append to log flag.
*
@ -148,19 +148,17 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
return _append;
}
/**
* 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}
* @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)
*/
public void setFilenameDateFormat(String logFileDateFormat)
{
_filenameDateFormat = logFileDateFormat;
}
/* ------------------------------------------------------------ */
/**
* Retrieve the file name date format string.
*
@ -171,13 +169,12 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
return _filenameDateFormat;
}
/* ------------------------------------------------------------ */
@Override
public void write(String requestEntry) throws IOException
{
synchronized(this)
synchronized (this)
{
if (_writer==null)
if (_writer == null)
return;
_writer.write(requestEntry);
_writer.write(System.lineSeparator());
@ -185,18 +182,12 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
}
}
/* ------------------------------------------------------------ */
/**
* Set up request logging and open log file.
*
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
@Override
protected synchronized void doStart() throws Exception
{
if (_filename != null)
{
_fileOut = new RolloverFileOutputStream(_filename,_append,_retainDays,TimeZone.getTimeZone(getTimeZone()),_filenameDateFormat,null);
_fileOut = new RolloverFileOutputStream(_filename, _append, _retainDays, TimeZone.getTimeZone(getTimeZone()), _filenameDateFormat, null);
_closeOut = true;
LOG.info("Opened " + getDatedFilename());
}
@ -205,7 +196,7 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
_out = _fileOut;
synchronized(this)
synchronized (this)
{
_writer = new OutputStreamWriter(_out);
}
@ -222,12 +213,6 @@ public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Wr
return _timeZone;
}
/* ------------------------------------------------------------ */
/**
* Close the log file and perform cleanup.
*
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
*/
@Override
protected void doStop() throws Exception
{

View File

@ -24,7 +24,7 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
/**
* 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#NCSA_FORMAT} with an {@link Slf4jRequestLogWriter}
* @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")