2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server;
21 import java.io.IOException;
22 import java.util.Locale;
24 import javax.servlet.http.Cookie;
26 import org.eclipse.jetty.http.HttpHeader;
27 import org.eclipse.jetty.http.PathMap;
28 import org.eclipse.jetty.server.handler.StatisticsHandler;
29 import org.eclipse.jetty.util.DateCache;
30 import org.eclipse.jetty.util.annotation.ManagedAttribute;
31 import org.eclipse.jetty.util.component.AbstractLifeCycle;
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.util.log.Logger;
36 * Base implementation of the {@link RequestLog} outputs logs in the pseudo-standard NCSA common log format.
37 * Configuration options allow a choice between the standard Common Log Format (as used in the 3 log format) and the
38 * Combined Log Format (single log format). This log format can be output by most web servers, and almost all web log
39 * analysis software can understand these formats.
41 public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implements RequestLog
43 protected static final Logger LOG = Log.getLogger(AbstractNCSARequestLog.class);
45 private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
48 protected StringBuilder initialValue()
50 return new StringBuilder(256);
55 private String[] _ignorePaths;
56 private boolean _extended;
57 private transient PathMap<String> _ignorePathMap;
58 private boolean _logLatency = false;
59 private boolean _logCookies = false;
60 private boolean _logServer = false;
61 private boolean _preferProxiedForAddress;
62 private transient DateCache _logDateCache;
63 private String _logDateFormat = "dd/MMM/yyyy:HH:mm:ss Z";
64 private Locale _logLocale = Locale.getDefault();
65 private String _logTimeZone = "GMT";
67 /* ------------------------------------------------------------ */
72 protected abstract boolean isEnabled();
74 /* ------------------------------------------------------------ */
77 * Write requestEntry out. (to disk or slf4j log)
79 public abstract void write(String requestEntry) throws IOException;
81 /* ------------------------------------------------------------ */
84 * Writes the request and response information to the output stream.
86 * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request,
87 * org.eclipse.jetty.server.Response)
90 public void log(Request request, Response response)
94 if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null)
100 StringBuilder buf = _buffers.get();
105 buf.append(request.getServerName());
110 if (_preferProxiedForAddress)
112 addr = request.getHeader(HttpHeader.X_FORWARDED_FOR.toString());
116 addr = request.getRemoteAddr();
120 Authentication authentication = request.getAuthentication();
121 if (authentication instanceof Authentication.User)
122 buf.append(((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName());
127 if (_logDateCache != null)
128 buf.append(_logDateCache.format(request.getTimeStamp()));
130 buf.append(request.getTimeStamp());
133 buf.append(request.getMethod());
135 buf.append(request.getUri().toString());
137 buf.append(request.getProtocol());
140 int status = response.getStatus();
143 buf.append((char)('0' + ((status / 100) % 10)));
144 buf.append((char)('0' + ((status / 10) % 10)));
145 buf.append((char)('0' + (status % 10)));
147 long responseLength = response.getLongContentLength();
148 if (responseLength >= 0)
151 if (responseLength > 99999)
152 buf.append(responseLength);
155 if (responseLength > 9999)
156 buf.append((char)('0' + ((responseLength / 10000) % 10)));
157 if (responseLength > 999)
158 buf.append((char)('0' + ((responseLength / 1000) % 10)));
159 if (responseLength > 99)
160 buf.append((char)('0' + ((responseLength / 100) % 10)));
161 if (responseLength > 9)
162 buf.append((char)('0' + ((responseLength / 10) % 10)));
163 buf.append((char)('0' + (responseLength) % 10));
172 logExtended(request, response, buf);
176 Cookie[] cookies = request.getCookies();
177 if (cookies == null || cookies.length == 0)
182 for (int i = 0; i < cookies.length; i++)
186 buf.append(cookies[i].getName());
188 buf.append(cookies[i].getValue());
196 long now = System.currentTimeMillis();
201 buf.append(now - request.getTimeStamp());
205 String log = buf.toString();
208 catch (IOException e)
214 /* ------------------------------------------------------------ */
217 * Writes extended request and response information to the output stream.
219 * @param request request object
220 * @param response response object
221 * @param b StringBuilder to write to
222 * @throws IOException
224 protected void logExtended(Request request,
226 StringBuilder b) throws IOException
228 String referer = request.getHeader(HttpHeader.REFERER.toString());
238 String agent = request.getHeader(HttpHeader.USER_AGENT.toString());
251 * Set request paths that will not be logged.
253 * @param ignorePaths array of request paths
255 public void setIgnorePaths(String[] ignorePaths)
257 _ignorePaths = ignorePaths;
261 * Retrieve the request paths that will not be logged.
263 * @return array of request paths
265 public String[] getIgnorePaths()
271 * Controls logging of the request cookies.
273 * @param logCookies true - values of request cookies will be logged, false - values of request cookies will not be
276 public void setLogCookies(boolean logCookies)
278 _logCookies = logCookies;
282 * Retrieve log cookies flag
284 * @return value of the flag
286 public boolean getLogCookies()
292 * Controls logging of the request hostname.
294 * @param logServer true - request hostname will be logged, false - request hostname will not be logged
296 public void setLogServer(boolean logServer)
298 _logServer = logServer;
302 * Retrieve log hostname flag.
304 * @return value of the flag
306 public boolean getLogServer()
312 * Controls logging of request processing time.
314 * @param logLatency true - request processing time will be logged false - request processing time will not be
317 public void setLogLatency(boolean logLatency)
319 _logLatency = logLatency;
323 * Retrieve log request processing time flag.
325 * @return value of the flag
327 public boolean getLogLatency()
333 * @deprecated use {@link StatisticsHandler}
335 public void setLogDispatch(boolean value)
340 * @deprecated use {@link StatisticsHandler}
342 public boolean isLogDispatch()
348 * Controls whether the actual IP address of the connection or the IP address from the X-Forwarded-For header will
351 * @param preferProxiedForAddress true - IP address from header will be logged, false - IP address from the
352 * connection will be logged
354 public void setPreferProxiedForAddress(boolean preferProxiedForAddress)
356 _preferProxiedForAddress = preferProxiedForAddress;
360 * Retrieved log X-Forwarded-For IP address flag.
362 * @return value of the flag
364 public boolean getPreferProxiedForAddress()
366 return _preferProxiedForAddress;
370 * Set the extended request log format flag.
372 * @param extended true - log the extended request information, false - do not log the extended request information
374 public void setExtended(boolean extended)
376 _extended = extended;
380 * Retrieve the extended request log format flag.
382 * @return value of the flag
384 @ManagedAttribute("use extended NCSA format")
385 public boolean isExtended()
391 * Set up request logging and open log file.
393 * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
396 protected synchronized void doStart() throws Exception
398 if (_logDateFormat != null)
400 _logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
403 if (_ignorePaths != null && _ignorePaths.length > 0)
405 _ignorePathMap = new PathMap<>();
406 for (int i = 0; i < _ignorePaths.length; i++)
407 _ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]);
410 _ignorePathMap = null;
416 protected void doStop() throws Exception
418 _logDateCache = null;
423 * Set the timestamp format for request log entries in the file. If this is not set, the pre-formated request
426 * @param format timestamp format string
428 public void setLogDateFormat(String format)
430 _logDateFormat = format;
434 * Retrieve the timestamp format string for request log entries.
436 * @return timestamp format string.
438 public String getLogDateFormat()
440 return _logDateFormat;
444 * Set the locale of the request log.
446 * @param logLocale locale object
448 public void setLogLocale(Locale logLocale)
450 _logLocale = logLocale;
454 * Retrieve the locale of the request log.
456 * @return locale object
458 public Locale getLogLocale()
464 * Set the timezone of the request log.
466 * @param tz timezone string
468 public void setLogTimeZone(String tz)
474 * Retrieve the timezone of the request log.
476 * @return timezone string
478 @ManagedAttribute("the timezone")
479 public String getLogTimeZone()