Issue #113 - Added Request Log Writers
Introduced the RequestLog.Writer where a RequestLog takes a writer which manages what to do with the log strings produced by the RequestLog deprecated the NCSA and SLF4J RequestLogs in favor of CustomRequestLog Implemented more format codes in CustomRequestLog Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
7dd3cfffe6
commit
e4d30b367c
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -28,7 +27,7 @@ import org.eclipse.jetty.http.pathmap.PathMappings;
|
|||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
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.Logger;
|
||||
|
||||
|
@ -37,20 +36,16 @@ 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}
|
||||
*/
|
||||
public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implements RequestLog
|
||||
@Deprecated
|
||||
public abstract class AbstractNCSARequestLog extends ContainerLifeCycle implements RequestLog
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(AbstractNCSARequestLog.class);
|
||||
|
||||
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
|
||||
{
|
||||
@Override
|
||||
protected StringBuilder initialValue()
|
||||
{
|
||||
return new StringBuilder(256);
|
||||
}
|
||||
};
|
||||
private static ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||
|
||||
protected final RequestLog.Writer _requestLogWriter;
|
||||
|
||||
private String[] _ignorePaths;
|
||||
private boolean _extended;
|
||||
|
@ -64,7 +59,11 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
|||
private Locale _logLocale = Locale.getDefault();
|
||||
private String _logTimeZone = "GMT";
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected AbstractNCSARequestLog(RequestLog.Writer requestLogWriter)
|
||||
{
|
||||
this._requestLogWriter = requestLogWriter;
|
||||
addBean(_requestLogWriter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is logging enabled
|
||||
|
@ -72,16 +71,15 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
|||
*/
|
||||
protected abstract boolean isEnabled();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Write requestEntry out. (to disk or slf4j log)
|
||||
* @param requestEntry the request entry
|
||||
* @throws IOException if unable to write the entry
|
||||
*/
|
||||
public abstract void write(String requestEntry) throws IOException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void write(String requestEntry) throws IOException
|
||||
{
|
||||
_requestLogWriter.write(requestEntry);
|
||||
}
|
||||
|
||||
private void append(StringBuilder buf,String s)
|
||||
{
|
||||
|
|
|
@ -18,112 +18,22 @@
|
|||
|
||||
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 NCSA Request Log
|
||||
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#NCSA_FORMAT} with an {@link AsyncRequestLogWriter}
|
||||
*/
|
||||
@Deprecated
|
||||
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()
|
||||
{
|
||||
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,95 @@
|
|||
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;
|
||||
|
||||
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 (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
@ -27,16 +26,17 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
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.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
import org.eclipse.jetty.http.pathmap.PathMappings;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
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.Logger;
|
||||
|
||||
|
@ -83,7 +83,10 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
|
||||
<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.</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>
|
||||
|
@ -201,8 +204,11 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top">%u</td>
|
||||
<td>Remote user if the request was authenticated. May be bogus if return status (%s) is 401 (unauthorized).</td>
|
||||
<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>
|
||||
|
@ -228,17 +234,17 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
|
||||
<tr>
|
||||
<td valign="top">%I</td>
|
||||
<td>Bytes received, including request and headers. Cannot be zero.</td>
|
||||
<td>Bytes received.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top">%O</td>
|
||||
<td>Bytes sent, including headers. May be zero in rare cases such as when a request is aborted before a response is sent.</td>
|
||||
<td>Bytes sent.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top">%S</td>
|
||||
<td>Bytes transferred (received and sent), including request and headers, cannot be zero. This is the combination of %I and %O.</td>
|
||||
<td>Bytes transferred (received and sent). This is the combination of %I and %O.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -253,25 +259,29 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
|
||||
</table>
|
||||
*/
|
||||
public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
||||
public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(CustomRequestLog.class);
|
||||
|
||||
//TODO previous NCSA format includes "" in the append, so %C would print out "cookies" if cookies exist and - without the "" if they do not
|
||||
public static final String NCSA_FORMAT = "%a - %u %t \"%r\" %s %B \"%{Referer}i\" \"%{User-Agent}i\" \"%C\"";
|
||||
|
||||
private static ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||
|
||||
private String[] _ignorePaths;
|
||||
private boolean _extended;
|
||||
private transient PathMappings<String> _ignorePathMap;
|
||||
private boolean _preferProxiedForAddress;
|
||||
private transient DateCache _logDateCache;
|
||||
private String _logDateFormat = "dd/MMM/yyyy:HH:mm:ss ZZZ";
|
||||
private final static String DEFAULT_DATE_FORMAT = "dd/MMM/yyyy:HH:mm:ss ZZZ";
|
||||
private Locale _logLocale = Locale.getDefault();
|
||||
private String _logTimeZone = "GMT";
|
||||
|
||||
private RequestLog.Writer _requestLogWriter;
|
||||
private final MethodHandle _logHandle;
|
||||
|
||||
public CustomRequestLog(String formatString)
|
||||
public CustomRequestLog(RequestLog.Writer writer, String formatString)
|
||||
{
|
||||
_requestLogWriter = writer;
|
||||
addBean(_requestLogWriter);
|
||||
|
||||
try
|
||||
{
|
||||
_logHandle = getLogHandle(formatString);
|
||||
|
@ -286,31 +296,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Is logging enabled
|
||||
* @return true if logging is enabled
|
||||
*/
|
||||
protected boolean isEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Write requestEntry out. (to disk or slf4j log)
|
||||
* @param requestEntry the request entry
|
||||
* @throws IOException if unable to write the entry
|
||||
*/
|
||||
protected void write(String requestEntry) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
|
||||
/**
|
||||
* Writes the request and response information to the output stream.
|
||||
*
|
||||
|
@ -324,16 +309,13 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null)
|
||||
return;
|
||||
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
StringBuilder sb = _buffers.get();
|
||||
sb.setLength(0);
|
||||
|
||||
_logHandle.invoke(sb, request, response);
|
||||
|
||||
String log = sb.toString();
|
||||
write(log);
|
||||
_requestLogWriter.write(log);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
|
@ -346,16 +328,23 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
* @param request The request to extract from
|
||||
* @return The string to log for authenticated user.
|
||||
*/
|
||||
protected String getAuthentication(Request request)
|
||||
protected static String getAuthentication(Request request, boolean checkDeferred)
|
||||
{
|
||||
Authentication authentication = request.getAuthentication();
|
||||
|
||||
String name = null;
|
||||
|
||||
boolean deferred = false;
|
||||
if (checkDeferred && authentication instanceof Authentication.Deferred)
|
||||
{
|
||||
authentication = ((Authentication.Deferred)authentication).authenticate(request);
|
||||
deferred = true;
|
||||
}
|
||||
|
||||
if (authentication instanceof Authentication.User)
|
||||
return ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
|
||||
name = ((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName();
|
||||
|
||||
// TODO extract the user name if it is Authentication.Deferred and return as '?username'
|
||||
|
||||
return null;
|
||||
return (name==null) ? null : (deferred ? ("?"+name):name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -378,49 +367,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
return _ignorePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether the actual IP address of the connection or the IP address from the X-Forwarded-For header will
|
||||
* be logged.
|
||||
*
|
||||
* @param preferProxiedForAddress true - IP address from header will be logged, false - IP address from the
|
||||
* connection will be logged
|
||||
*/
|
||||
public void setPreferProxiedForAddress(boolean preferProxiedForAddress)
|
||||
{
|
||||
_preferProxiedForAddress = preferProxiedForAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieved log X-Forwarded-For IP address flag.
|
||||
*
|
||||
* @return value of the flag
|
||||
*/
|
||||
public boolean getPreferProxiedForAddress()
|
||||
{
|
||||
return _preferProxiedForAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extended request log format flag.
|
||||
*
|
||||
* @param extended true - log the extended request information, false - do not log the extended request information
|
||||
*/
|
||||
public void setExtended(boolean extended)
|
||||
{
|
||||
_extended = extended;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the extended request log format flag.
|
||||
*
|
||||
* @return value of the flag
|
||||
*/
|
||||
@ManagedAttribute("use extended NCSA format")
|
||||
public boolean isExtended()
|
||||
{
|
||||
return _extended;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up request logging and open log file.
|
||||
*
|
||||
|
@ -429,11 +375,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
@Override
|
||||
protected synchronized void doStart() throws Exception
|
||||
{
|
||||
if (_logDateFormat != null)
|
||||
{
|
||||
_logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
|
||||
}
|
||||
|
||||
if (_ignorePaths != null && _ignorePaths.length > 0)
|
||||
{
|
||||
_ignorePathMap = new PathMappings<>();
|
||||
|
@ -446,34 +387,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
_logDateCache = null;
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timestamp format for request log entries in the file. If this is not set, the pre-formated request
|
||||
* timestamp is used.
|
||||
*
|
||||
* @param format timestamp format string
|
||||
*/
|
||||
public void setLogDateFormat(String format)
|
||||
{
|
||||
_logDateFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the timestamp format string for request log entries.
|
||||
*
|
||||
* @return timestamp format string.
|
||||
*/
|
||||
public String getLogDateFormat()
|
||||
{
|
||||
return _logDateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locale of the request log.
|
||||
*
|
||||
|
@ -529,7 +442,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
append(buf, s);
|
||||
}
|
||||
|
||||
|
||||
private MethodHandle getLogHandle(String formatString) throws NoSuchMethodException, IllegalAccessException
|
||||
{
|
||||
MethodHandle append = MethodHandles.lookup().findStatic(CustomRequestLog.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class));
|
||||
|
@ -549,7 +461,6 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
return logHandle;
|
||||
}
|
||||
|
||||
|
||||
private static List<Token> getTokens(String formatString)
|
||||
{
|
||||
final Pattern PATTERN = Pattern.compile("^(?:%(?<MOD>!?[0-9,]+)?(?:\\{(?<ARG>[^}]+)})?(?<CODE>(?:(?:ti)|(?:to)|[a-zA-Z%]))|(?<LITERAL>[^%]+))(?<REMAINING>.*)");
|
||||
|
@ -604,14 +515,7 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static class Token
|
||||
{
|
||||
public boolean isLiteralString()
|
||||
{
|
||||
return(literal != null);
|
||||
}
|
||||
public boolean isPercentCode()
|
||||
{
|
||||
return(code != null);
|
||||
}
|
||||
//todo make final
|
||||
public String code = null;
|
||||
public String arg = null;
|
||||
public List<String> modifiers = null;
|
||||
|
@ -630,6 +534,15 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
{
|
||||
this.literal = literal;
|
||||
}
|
||||
|
||||
public boolean isLiteralString()
|
||||
{
|
||||
return(literal != null);
|
||||
}
|
||||
public boolean isPercentCode()
|
||||
{
|
||||
return(code != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -665,6 +578,7 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
{
|
||||
case "%":
|
||||
{
|
||||
//todo use literal
|
||||
specificHandle = dropArguments(dropArguments(append.bindTo("%"), 1, Request.class), 2, Response.class);
|
||||
break;
|
||||
}
|
||||
|
@ -713,11 +627,16 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
case "C":
|
||||
{
|
||||
if (arg == null || arg.isEmpty())
|
||||
throw new IllegalArgumentException("No arg for %C");
|
||||
|
||||
String method = "logRequestCookie";
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
{
|
||||
String method = "logRequestCookies";
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
else
|
||||
{
|
||||
String method = "logRequestCookie";
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -857,7 +776,7 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
//todo is this correctly supporting the right formats
|
||||
DateCache logDateCache;
|
||||
if (arg == null || arg.isEmpty())
|
||||
logDateCache = new DateCache(_logDateFormat, _logLocale , _logTimeZone);
|
||||
logDateCache = new DateCache(DEFAULT_DATE_FORMAT, _logLocale , _logTimeZone);
|
||||
else
|
||||
logDateCache = new DateCache(arg, _logLocale , _logTimeZone);
|
||||
|
||||
|
@ -896,7 +815,12 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
case "u":
|
||||
{
|
||||
String method = "logRequestAuthentication";
|
||||
String method;
|
||||
if (arg == null || arg.isEmpty())
|
||||
method = "logRequestAuthenticationWithDeferred";
|
||||
else
|
||||
method = "logRequestAuthentication";
|
||||
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
}
|
||||
|
@ -949,25 +873,23 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
if (arg == null || arg.isEmpty())
|
||||
throw new IllegalArgumentException("No arg for %ti");
|
||||
|
||||
String method = "logRequestTrailerLines";
|
||||
String method = "logRequestTrailer";
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case "to":
|
||||
{
|
||||
if (arg == null || arg.isEmpty())
|
||||
throw new IllegalArgumentException("No arg for %to");
|
||||
|
||||
String method = "logResponseTrailerLines";
|
||||
String method = "logResponseTrailer";
|
||||
specificHandle = MethodHandles.lookup().findStatic(CustomRequestLog.class, method, logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported code %" + code);
|
||||
}
|
||||
|
@ -1000,8 +922,7 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logConnectionIP(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo don't think this is correct
|
||||
append(b, request.getHeader(HttpHeader.X_FORWARDED_FOR.toString()));
|
||||
append(b, request.getHttpChannel().getEndPoint().getRemoteAddress().getAddress().getHostAddress());
|
||||
}
|
||||
|
||||
private static void logLocalIP(StringBuilder b, Request request, Response response)
|
||||
|
@ -1012,18 +933,20 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
private static void logResponseSize(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
long written = response.getHttpChannel().getBytesWritten();
|
||||
b.append(Long.toString(written));
|
||||
b.append(written);
|
||||
}
|
||||
|
||||
private static void logResponseSizeCLF(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
long written = response.getHttpChannel().getBytesWritten();
|
||||
b.append((written==0) ? "-" : Long.toString(written));
|
||||
if (written==0)
|
||||
b.append('-');
|
||||
else
|
||||
b.append(written);
|
||||
}
|
||||
|
||||
private static void logRequestCookie(String arg, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo should this be logging full cookie or its value, can you log multiple cookies, can multiple cookies have the same name
|
||||
for (Cookie c : request.getCookies())
|
||||
{
|
||||
if (arg.equals(c.getName()))
|
||||
|
@ -1033,7 +956,25 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
}
|
||||
}
|
||||
|
||||
b.append("-");
|
||||
b.append('-');
|
||||
}
|
||||
|
||||
private static void logRequestCookies(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies == null || cookies.length == 0)
|
||||
b.append("-");
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cookies.length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
b.append(';');
|
||||
b.append(cookies[i].getName());
|
||||
b.append('=');
|
||||
b.append(cookies[i].getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void logEnvironmentVar(String arg, StringBuilder b, Request request, Response response)
|
||||
|
@ -1043,8 +984,8 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logFilename(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//TODO probably wrong, getRealPath?
|
||||
append(b, request.getContextPath());
|
||||
//TODO verify
|
||||
append(b, request.getServletContext().getRealPath(request.getPathInfo()));
|
||||
}
|
||||
|
||||
private static void logRemoteHostName(StringBuilder b, Request request, Response response)
|
||||
|
@ -1059,14 +1000,16 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logRequestHeader(String arg, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//TODO does this need to do multiple headers 'request.getHeaders(arg)'
|
||||
append(b, request.getHeader(arg));
|
||||
}
|
||||
|
||||
private static void logKeepAliveRequests(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo verify this "number of requests on this connection? what about http2?"
|
||||
b.append(request.getHttpChannel().getRequests());
|
||||
long requests = request.getHttpChannel().getConnection().getMessagesIn();
|
||||
if (requests >= 0)
|
||||
b.append(requests);
|
||||
else
|
||||
b.append('-');
|
||||
}
|
||||
|
||||
private static void logRequestMethod(StringBuilder b, Request request, Response response)
|
||||
|
@ -1076,27 +1019,22 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logResponseHeader(String arg, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//TODO does this need to do multiple headers 'Response.getHeaders(arg)'
|
||||
append(b, response.getHeader(arg));
|
||||
}
|
||||
|
||||
|
||||
private static void logCanonicalPort(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
b.append(request.getServerPort());
|
||||
}
|
||||
|
||||
private static void logLocalPort(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
b.append(request.getLocalPort());
|
||||
}
|
||||
|
||||
private static void logRemotePort(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
b.append(request.getRemotePort());
|
||||
}
|
||||
|
||||
private static void logQueryString(StringBuilder b, Request request, Response response)
|
||||
|
@ -1106,8 +1044,11 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logRequestFirstLine(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo is there a better way to do this
|
||||
append(b, request.getMethod() + " " + request.getOriginalURI() + " " + request.getProtocol());
|
||||
append(b, request.getMethod());
|
||||
b.append(" ");
|
||||
append(b, request.getOriginalURI());
|
||||
b.append(" ");
|
||||
append(b, request.getProtocol());
|
||||
}
|
||||
|
||||
private static void logRequestHandler(StringBuilder b, Request request, Response response)
|
||||
|
@ -1118,16 +1059,20 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logResponseStatus(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
b.append(response.getStatus());
|
||||
//todo can getCommittedMetaData be null? check what happens when its aborted
|
||||
b.append(response.getCommittedMetaData().getStatus());
|
||||
}
|
||||
|
||||
private static void logRequestTime(DateCache dateCache, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
b.append(dateCache.format(request.getTimeStamp()));
|
||||
b.append('[');
|
||||
append(b, dateCache.format(request.getTimeStamp()));
|
||||
b.append(']');
|
||||
}
|
||||
|
||||
private static void logLatencyMicroseconds(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo can we use nanotime?
|
||||
long latency = System.currentTimeMillis() - request.getTimeStamp();
|
||||
b.append(TimeUnit.MILLISECONDS.toMicros(latency));
|
||||
}
|
||||
|
@ -1140,20 +1085,22 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logLatencySeconds(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo should this give decimal places
|
||||
long latency = System.currentTimeMillis() - request.getTimeStamp();
|
||||
b.append(TimeUnit.MILLISECONDS.toSeconds(latency));
|
||||
}
|
||||
|
||||
private static void logRequestAuthentication(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
append(b, getAuthentication(request, false));
|
||||
}
|
||||
|
||||
private static void logRequestAuthenticationWithDeferred(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
append(b, getAuthentication(request, true));
|
||||
}
|
||||
|
||||
private static void logUrlRequestPath(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo verify if this contains the query string
|
||||
append(b, request.getRequestURI());
|
||||
}
|
||||
|
||||
|
@ -1164,19 +1111,18 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
|
||||
private static void logConnectionStatus(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
b.append(request.getHttpChannel().isResponseCompleted() ? (request.getHttpChannel().isPersistent() ? '+' : '-') : 'X');
|
||||
}
|
||||
|
||||
private static void logBytesReceived(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
//todo should this be content received rather than consumed
|
||||
b.append(request.getHttpInput().getContentConsumed());
|
||||
}
|
||||
|
||||
private static void logBytesSent(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
//todo redirect to logResponseSize
|
||||
append(b, "?");
|
||||
}
|
||||
|
||||
|
@ -1186,15 +1132,28 @@ public class CustomRequestLog extends AbstractLifeCycle implements RequestLog
|
|||
append(b, "?");
|
||||
}
|
||||
|
||||
private static void logRequestTrailerLines(String arg, StringBuilder b, Request request, Response response)
|
||||
private static void logRequestTrailer(String arg, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
HttpFields trailers = request.getTrailers();
|
||||
if (trailers != null)
|
||||
append(b, trailers.get(arg));
|
||||
else
|
||||
b.append('-');
|
||||
}
|
||||
|
||||
private static void logResponseTrailerLines(String arg, StringBuilder b, Request request, Response response)
|
||||
private static void logResponseTrailer(String arg, StringBuilder b, Request request, Response response)
|
||||
{
|
||||
//todo implement
|
||||
append(b, "?");
|
||||
Supplier<HttpFields> supplier = response.getTrailers();
|
||||
if (supplier != null)
|
||||
{
|
||||
HttpFields trailers = supplier.get();
|
||||
|
||||
if (trailers != null)
|
||||
append(b, trailers.get(arg));
|
||||
else
|
||||
b.append('-');
|
||||
}
|
||||
else
|
||||
b.append("-");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,9 @@
|
|||
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.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
||||
|
@ -36,18 +32,13 @@ 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
|
||||
@ManagedObject("NCSA standard format request log")
|
||||
public class NCSARequestLog extends AbstractNCSARequestLog
|
||||
{
|
||||
private String _filename;
|
||||
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;
|
||||
private final RequestLogWriter _requestLogWriter;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -55,9 +46,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public NCSARequestLog()
|
||||
{
|
||||
setExtended(true);
|
||||
_append = true;
|
||||
_retainDays = 31;
|
||||
this((String)null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -70,10 +59,18 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public NCSARequestLog(String filename)
|
||||
{
|
||||
this(new RequestLogWriter(filename));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create request log object with specified output file name.
|
||||
*/
|
||||
public NCSARequestLog(RequestLogWriter writer)
|
||||
{
|
||||
super(writer);
|
||||
_requestLogWriter = writer;
|
||||
setExtended(true);
|
||||
_append = true;
|
||||
_retainDays = 31;
|
||||
setFilename(filename);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -87,13 +84,15 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
if (filename != null)
|
||||
{
|
||||
filename = filename.trim();
|
||||
if (filename.length() == 0)
|
||||
filename = null;
|
||||
}
|
||||
_filename = filename;
|
||||
_requestLogWriter.setFilename(filename);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setLogTimeZone(String tz)
|
||||
{
|
||||
super.setLogTimeZone(tz);
|
||||
_requestLogWriter.setTimeZone(tz);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -105,7 +104,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
@ManagedAttribute("file of log")
|
||||
public String getFilename()
|
||||
{
|
||||
return _filename;
|
||||
return _requestLogWriter.getFileName();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -118,16 +117,14 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public String getDatedFilename()
|
||||
{
|
||||
if (_fileOut instanceof RolloverFileOutputStream)
|
||||
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
||||
return null;
|
||||
return _requestLogWriter.getDatedFilename();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected boolean isEnabled()
|
||||
{
|
||||
return (_fileOut != null);
|
||||
return _requestLogWriter.isEnabled();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -138,7 +135,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public void setRetainDays(int retainDays)
|
||||
{
|
||||
_retainDays = retainDays;
|
||||
_requestLogWriter.setRetainDays(retainDays);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -150,7 +147,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
@ManagedAttribute("number of days that log files are kept")
|
||||
public int getRetainDays()
|
||||
{
|
||||
return _retainDays;
|
||||
return _requestLogWriter.getRetainDays();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -162,7 +159,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public void setAppend(boolean append)
|
||||
{
|
||||
_append = append;
|
||||
_requestLogWriter.setAppend(append);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -174,7 +171,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
@ManagedAttribute("existing log files are appends to the new one")
|
||||
public boolean isAppend()
|
||||
{
|
||||
return _append;
|
||||
return _requestLogWriter.isAppend();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -186,7 +183,7 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public void setFilenameDateFormat(String logFileDateFormat)
|
||||
{
|
||||
_filenameDateFormat = logFileDateFormat;
|
||||
_requestLogWriter.setFilenameDateFormat(logFileDateFormat);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -197,21 +194,14 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
*/
|
||||
public String getFilenameDateFormat()
|
||||
{
|
||||
return _filenameDateFormat;
|
||||
return _requestLogWriter.getFilenameDateFormat();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void write(String requestEntry) throws IOException
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if (_writer==null)
|
||||
return;
|
||||
_writer.write(requestEntry);
|
||||
_writer.write(StringUtil.__LINE_SEPARATOR);
|
||||
_writer.flush();
|
||||
}
|
||||
_requestLogWriter.write(requestEntry);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -223,21 +213,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -253,29 +228,6 @@ public class NCSARequestLog extends AbstractNCSARequestLog
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +30,6 @@ import org.eclipse.jetty.server.handler.RequestLogHandler;
|
|||
*/
|
||||
public interface RequestLog
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param request The request to log.
|
||||
* @param response The response to log. Note that for some requests
|
||||
|
@ -37,5 +38,29 @@ public interface RequestLog
|
|||
* log information it is best to consult {@link Response#getCommittedMetaData()}
|
||||
* and {@link Response#getHttpChannel()} directly.
|
||||
*/
|
||||
public void log(Request request, Response response);
|
||||
void log(Request request, Response response);
|
||||
|
||||
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,245 @@
|
|||
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.StringUtil;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public String getDatedFilename()
|
||||
{
|
||||
if (_fileOut instanceof RolloverFileOutputStream)
|
||||
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
||||
return null;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public boolean isAppend()
|
||||
{
|
||||
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}
|
||||
*/
|
||||
public void setFilenameDateFormat(String logFileDateFormat)
|
||||
{
|
||||
_filenameDateFormat = logFileDateFormat;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the file name date format string.
|
||||
*
|
||||
* @return the log File 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(StringUtil.__LINE_SEPARATOR);
|
||||
_writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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);
|
||||
_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;
|
||||
}
|
||||
|
||||
public String getTimeZone()
|
||||
{
|
||||
return _timeZone;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Close the log file and perform cleanup.
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
|
||||
*/
|
||||
@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 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"
|
||||
* @deprecated use {@link CustomRequestLog} given format string {@link CustomRequestLog#NCSA_FORMAT} with an {@link Slf4jRequestLogWriter}
|
||||
*/
|
||||
@Deprecated
|
||||
@ManagedObject("NCSA standard format request log to slf4j bridge")
|
||||
public class Slf4jRequestLog extends AbstractNCSARequestLog
|
||||
{
|
||||
private Slf4jLog logger;
|
||||
private String loggerName;
|
||||
private final Slf4jRequestLogWriter _requestLogWriter;
|
||||
|
||||
public Slf4jRequestLog()
|
||||
{
|
||||
// Default logger name (can be set)
|
||||
this.loggerName = "org.eclipse.jetty.server.RequestLog";
|
||||
this(new Slf4jRequestLogWriter());
|
||||
}
|
||||
|
||||
public Slf4jRequestLog(Slf4jRequestLogWriter writer)
|
||||
{
|
||||
super(writer);
|
||||
_requestLogWriter = writer;
|
||||
}
|
||||
|
||||
public void setLoggerName(String loggerName)
|
||||
{
|
||||
this.loggerName = loggerName;
|
||||
_requestLogWriter.setLoggerName(loggerName);
|
||||
}
|
||||
|
||||
public String getLoggerName()
|
||||
{
|
||||
return loggerName;
|
||||
return _requestLogWriter.getLoggerName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled()
|
||||
{
|
||||
return logger != null;
|
||||
return _requestLogWriter.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String requestEntry) throws IOException
|
||||
{
|
||||
logger.info(requestEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void doStart() throws Exception
|
||||
{
|
||||
logger = new Slf4jLog(loggerName);
|
||||
super.doStart();
|
||||
_requestLogWriter.write(requestEntry);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Slf4jLog;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue