diff --git a/jetty-server/src/main/config/etc/jetty-customrequestlog.xml b/jetty-server/src/main/config/etc/jetty-customrequestlog.xml index dd24cd80ec6..6b605261356 100644 --- a/jetty-server/src/main/config/etc/jetty-customrequestlog.xml +++ b/jetty-server/src/main/config/etc/jetty-customrequestlog.xml @@ -17,22 +17,22 @@ / jetty.customrequestlog.filePath - /yyyy_mm_dd.request.log + /yyyy_mm_dd.request.log - - - - + + + + - + - + diff --git a/jetty-server/src/main/config/modules/customrequestlog.mod b/jetty-server/src/main/config/modules/customrequestlog.mod index 0d4eb9a8c41..68517d85de9 100644 --- a/jetty-server/src/main/config/modules/customrequestlog.mod +++ b/jetty-server/src/main/config/modules/customrequestlog.mod @@ -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" diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java index d460d6af3cf..99e0a94cf63 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java @@ -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) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java index 6f3d986a06c..3290b7794d2 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java @@ -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 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncRequestLogWriter.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncRequestLogWriter.java index 8f704fd572c..4c79d50ffb0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncRequestLogWriter.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncRequestLogWriter.java @@ -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 queue) + public AsyncRequestLogWriter(String filename, BlockingQueue 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; } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java index 4bfb2448786..d8f8697d735 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java @@ -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; /** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustomRequestLog Format Codes
Format StringDescription
%%The percent sign.
%{format}a - 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 -
%aClient IP address of the request.
%{c}aUnderlying peer IP address of the connection.
%ALocal IP-address.
%hRemote hostname. Will log a dotted-string form of the IP if the Hostname cannot be resolved.
%v - todo this is now %{server}a - The canonical ServerName of the server serving the request.
%BSize of response in bytes, excluding HTTP headers.
%bSize of response in bytes, excluding HTTP headers. In CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
%{VARNAME}C - 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. -
%DThe time taken to serve the request, in microseconds.
%{VARNAME}eThe contents of the environment variable VARNAME.
%fFilename.
%HThe request protocol.
%{VARNAME}iThe contents of VARNAME: header line(s) in the request sent to the server.
%kNumber 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).
%mThe request method.
%{VARNAME}oThe contents of VARNAME: header line(s) in the response.
%pThe canonical port of the server serving the request. - todo merge this with below -
%{format}pThe 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 -
%qThe query string (prepended with a ? if a query string exists, otherwise an empty string).
%rFirst line of request.
%RThe handler generating the response (if any).
%sResponse status.
%{format}t - 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.) -
- The format parameter should be in a format supported by {@link DateCache} -
%TThe time taken to serve the request, in seconds.
%{UNIT}TThe 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.
%{d}u - 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. -
%UThe URL path requested, not including any query string.
%X - Connection status when response is completed: -
- 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.
-
%IBytes received.
%OBytes sent.
%SBytes transferred (received and sent). This is the combination of %I and %O.
%{VARNAME}^tiThe contents of VARNAME: trailer line(s) in the request sent to the server.
%{VARNAME}^toThe contents of VARNAME: trailer line(s) in the response sent from the server.
+ * 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. + *

+ * 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. + * + * + *

Percent codes are specified in the format %MODIFIERS{PARAM}CODE + *

+ * 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.
+ * 
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Format Codes
Format StringDescription
%%The percent sign.
%{format}a + * Address or Hostname. Valid formats are {server, client, local, remote} + * Optional format parameter which will be server by default. + *
+ * 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. + *
%{format}p + * Port. Valid formats are {server, client, local, remote} + * Optional format parameter which will be server by default. + *
+ * 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. + *
%{clf}I + * 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. + *
%{clf}O + * 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. + *
%{clf}S + * 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. + *
%{VARNAME}C + * 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. + *
%DThe time taken to serve the request, in microseconds.
%{VARNAME}eThe contents of the environment variable VARNAME.
%fFilename.
%HThe request protocol.
%{VARNAME}iThe contents of VARNAME: header line(s) in the request sent to the server.
%kNumber 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).
%mThe request method.
%{VARNAME}oThe contents of VARNAME: header line(s) in the response.
%qThe query string (prepended with a ? if a query string exists, otherwise an empty string).
%rFirst line of request.
%RThe handler generating the response (if any).
%sResponse status.
%{format}t + * 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.) + *
+ * The format parameter should be in a format supported by {@link DateCache} + *
%TThe time taken to serve the request, in seconds.
%{UNIT}TThe 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.
%{d}u + * 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. + *
%UThe URL path requested, not including any query string.
%X + * Connection status when response is completed: + *
+ * 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.
+ *
%{VARNAME}^tiThe contents of VARNAME: trailer line(s) in the request sent to the server.
%{VARNAME}^toThe contents of VARNAME: trailer line(s) in the response sent from the server.
*/ +@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 _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 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("^(?:%(?!?[0-9,]+)?(?:\\{(?[^}]+)})?(?(?:(?:ti)|(?:to)|[a-zA-Z%]))|(?[^%]+))(?.*)"); List 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'); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java index a8a5466543f..6a660fb3dc1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java @@ -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. * diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java index 5e59fe01139..4ad0fd64146 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java @@ -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 RequestLog can be attached to a {@link org.eclipse.jetty.server.handler.RequestLogHandler} to enable +/** + * A RequestLog 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; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogWriter.java b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogWriter.java index 7015709837d..7f508e6cf95 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogWriter.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogWriter.java @@ -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 { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java index 29388a227f9..a6340c9f399 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java @@ -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")