]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / server / AbstractNCSARequestLog.java
1 //
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.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.io.IOException;
22 import java.util.Locale;
23
24 import javax.servlet.http.Cookie;
25
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;
34
35 /**
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.
40  */
41 public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implements RequestLog
42 {
43     protected static final Logger LOG = Log.getLogger(AbstractNCSARequestLog.class);
44
45     private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
46     {
47         @Override
48         protected StringBuilder initialValue()
49         {
50             return new StringBuilder(256);
51         }
52     };
53
54
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";
66
67     /* ------------------------------------------------------------ */
68
69     /**
70      * Is logging enabled
71      */
72     protected abstract boolean isEnabled();
73     
74     /* ------------------------------------------------------------ */
75
76     /**
77      * Write requestEntry out. (to disk or slf4j log)
78      */
79     public abstract void write(String requestEntry) throws IOException;
80
81     /* ------------------------------------------------------------ */
82
83     /**
84      * Writes the request and response information to the output stream.
85      *
86      * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request,
87      *      org.eclipse.jetty.server.Response)
88      */
89     @Override
90     public void log(Request request, Response response)
91     {
92         try
93         {
94             if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null)
95                 return;
96
97             if (!isEnabled())
98                 return;
99
100             StringBuilder buf = _buffers.get();
101             buf.setLength(0);
102
103             if (_logServer)
104             {
105                 buf.append(request.getServerName());
106                 buf.append(' ');
107             }
108
109             String addr = null;
110             if (_preferProxiedForAddress)
111             {
112                 addr = request.getHeader(HttpHeader.X_FORWARDED_FOR.toString());
113             }
114
115             if (addr == null)
116                 addr = request.getRemoteAddr();
117
118             buf.append(addr);
119             buf.append(" - ");
120             Authentication authentication = request.getAuthentication();
121             if (authentication instanceof Authentication.User)
122                 buf.append(((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName());
123             else
124                 buf.append(" - ");
125
126             buf.append(" [");
127             if (_logDateCache != null)
128                 buf.append(_logDateCache.format(request.getTimeStamp()));
129             else
130                 buf.append(request.getTimeStamp());
131
132             buf.append("] \"");
133             buf.append(request.getMethod());
134             buf.append(' ');
135             buf.append(request.getUri().toString());
136             buf.append(' ');
137             buf.append(request.getProtocol());
138             buf.append("\" ");
139
140             int status = response.getStatus();
141             if (status <= 0)
142                 status = 404;
143             buf.append((char)('0' + ((status / 100) % 10)));
144             buf.append((char)('0' + ((status / 10) % 10)));
145             buf.append((char)('0' + (status % 10)));
146
147             long responseLength = response.getLongContentLength();
148             if (responseLength >= 0)
149             {
150                 buf.append(' ');
151                 if (responseLength > 99999)
152                     buf.append(responseLength);
153                 else
154                 {
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));
164                 }
165                 buf.append(' ');
166             }
167             else
168                 buf.append(" - ");
169
170
171             if (_extended)
172                 logExtended(request, response, buf);
173
174             if (_logCookies)
175             {
176                 Cookie[] cookies = request.getCookies();
177                 if (cookies == null || cookies.length == 0)
178                     buf.append(" -");
179                 else
180                 {
181                     buf.append(" \"");
182                     for (int i = 0; i < cookies.length; i++)
183                     {
184                         if (i != 0)
185                             buf.append(';');
186                         buf.append(cookies[i].getName());
187                         buf.append('=');
188                         buf.append(cookies[i].getValue());
189                     }
190                     buf.append('\"');
191                 }
192             }
193
194             if (_logLatency)
195             {
196                 long now = System.currentTimeMillis();
197
198                 if (_logLatency)
199                 {
200                     buf.append(' ');
201                     buf.append(now - request.getTimeStamp());
202                 }
203             }
204
205             String log = buf.toString();
206             write(log);
207         }
208         catch (IOException e)
209         {
210             LOG.warn(e);
211         }
212     }
213     
214     /* ------------------------------------------------------------ */
215
216     /**
217      * Writes extended request and response information to the output stream.
218      *
219      * @param request  request object
220      * @param response response object
221      * @param b        StringBuilder to write to
222      * @throws IOException
223      */
224     protected void logExtended(Request request,
225                                Response response,
226                                StringBuilder b) throws IOException
227     {
228         String referer = request.getHeader(HttpHeader.REFERER.toString());
229         if (referer == null)
230             b.append("\"-\" ");
231         else
232         {
233             b.append('"');
234             b.append(referer);
235             b.append("\" ");
236         }
237
238         String agent = request.getHeader(HttpHeader.USER_AGENT.toString());
239         if (agent == null)
240             b.append("\"-\" ");
241         else
242         {
243             b.append('"');
244             b.append(agent);
245             b.append('"');
246         }
247     }
248
249
250     /**
251      * Set request paths that will not be logged.
252      *
253      * @param ignorePaths array of request paths
254      */
255     public void setIgnorePaths(String[] ignorePaths)
256     {
257         _ignorePaths = ignorePaths;
258     }
259
260     /**
261      * Retrieve the request paths that will not be logged.
262      *
263      * @return array of request paths
264      */
265     public String[] getIgnorePaths()
266     {
267         return _ignorePaths;
268     }
269
270     /**
271      * Controls logging of the request cookies.
272      *
273      * @param logCookies true - values of request cookies will be logged, false - values of request cookies will not be
274      *                   logged
275      */
276     public void setLogCookies(boolean logCookies)
277     {
278         _logCookies = logCookies;
279     }
280
281     /**
282      * Retrieve log cookies flag
283      *
284      * @return value of the flag
285      */
286     public boolean getLogCookies()
287     {
288         return _logCookies;
289     }
290
291     /**
292      * Controls logging of the request hostname.
293      *
294      * @param logServer true - request hostname will be logged, false - request hostname will not be logged
295      */
296     public void setLogServer(boolean logServer)
297     {
298         _logServer = logServer;
299     }
300
301     /**
302      * Retrieve log hostname flag.
303      *
304      * @return value of the flag
305      */
306     public boolean getLogServer()
307     {
308         return _logServer;
309     }
310
311     /**
312      * Controls logging of request processing time.
313      *
314      * @param logLatency true - request processing time will be logged false - request processing time will not be
315      *                   logged
316      */
317     public void setLogLatency(boolean logLatency)
318     {
319         _logLatency = logLatency;
320     }
321
322     /**
323      * Retrieve log request processing time flag.
324      *
325      * @return value of the flag
326      */
327     public boolean getLogLatency()
328     {
329         return _logLatency;
330     }
331
332     /**
333      * @deprecated use {@link StatisticsHandler}
334      */
335     public void setLogDispatch(boolean value)
336     {
337     }
338
339     /**
340      * @deprecated use {@link StatisticsHandler}
341      */
342     public boolean isLogDispatch()
343     {
344         return false;
345     }
346
347     /**
348      * Controls whether the actual IP address of the connection or the IP address from the X-Forwarded-For header will
349      * be logged.
350      *
351      * @param preferProxiedForAddress true - IP address from header will be logged, false - IP address from the
352      *                                connection will be logged
353      */
354     public void setPreferProxiedForAddress(boolean preferProxiedForAddress)
355     {
356         _preferProxiedForAddress = preferProxiedForAddress;
357     }
358
359     /**
360      * Retrieved log X-Forwarded-For IP address flag.
361      *
362      * @return value of the flag
363      */
364     public boolean getPreferProxiedForAddress()
365     {
366         return _preferProxiedForAddress;
367     }
368
369     /**
370      * Set the extended request log format flag.
371      *
372      * @param extended true - log the extended request information, false - do not log the extended request information
373      */
374     public void setExtended(boolean extended)
375     {
376         _extended = extended;
377     }
378
379     /**
380      * Retrieve the extended request log format flag.
381      *
382      * @return value of the flag
383      */
384     @ManagedAttribute("use extended NCSA format")
385     public boolean isExtended()
386     {
387         return _extended;
388     }
389
390     /**
391      * Set up request logging and open log file.
392      *
393      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
394      */
395     @Override
396     protected synchronized void doStart() throws Exception
397     {
398         if (_logDateFormat != null)
399         {
400             _logDateCache = new DateCache(_logDateFormat, _logLocale ,_logTimeZone);
401         }
402
403         if (_ignorePaths != null && _ignorePaths.length > 0)
404         {
405             _ignorePathMap = new PathMap<>();
406             for (int i = 0; i < _ignorePaths.length; i++)
407                 _ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]);
408         }
409         else
410             _ignorePathMap = null;
411
412         super.doStart();
413     }
414
415     @Override
416     protected void doStop() throws Exception
417     {
418         _logDateCache = null;
419         super.doStop();
420     }
421
422     /**
423      * Set the timestamp format for request log entries in the file. If this is not set, the pre-formated request
424      * timestamp is used.
425      *
426      * @param format timestamp format string
427      */
428     public void setLogDateFormat(String format)
429     {
430         _logDateFormat = format;
431     }
432
433     /**
434      * Retrieve the timestamp format string for request log entries.
435      *
436      * @return timestamp format string.
437      */
438     public String getLogDateFormat()
439     {
440         return _logDateFormat;
441     }
442
443     /**
444      * Set the locale of the request log.
445      *
446      * @param logLocale locale object
447      */
448     public void setLogLocale(Locale logLocale)
449     {
450         _logLocale = logLocale;
451     }
452
453     /**
454      * Retrieve the locale of the request log.
455      *
456      * @return locale object
457      */
458     public Locale getLogLocale()
459     {
460         return _logLocale;
461     }
462
463     /**
464      * Set the timezone of the request log.
465      *
466      * @param tz timezone string
467      */
468     public void setLogTimeZone(String tz)
469     {
470         _logTimeZone = tz;
471     }
472
473     /**
474      * Retrieve the timezone of the request log.
475      *
476      * @return timezone string
477      */
478     @ManagedAttribute("the timezone")
479     public String getLogTimeZone()
480     {
481         return _logTimeZone;
482     }
483 }