1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty;
16
17 import java.io.IOException;
18 import java.io.OutputStream;
19 import java.io.OutputStreamWriter;
20 import java.io.Writer;
21 import java.util.ArrayList;
22 import java.util.Locale;
23 import java.util.TimeZone;
24
25 import javax.servlet.http.Cookie;
26
27 import org.mortbay.component.AbstractLifeCycle;
28 import org.mortbay.jetty.servlet.PathMap;
29 import org.mortbay.log.Log;
30 import org.mortbay.util.DateCache;
31 import org.mortbay.util.RolloverFileOutputStream;
32 import org.mortbay.util.StringUtil;
33 import org.mortbay.util.TypeUtil;
34 import org.mortbay.util.Utf8StringBuilder;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
50 {
51 private String _filename;
52 private boolean _extended;
53 private boolean _append;
54 private int _retainDays;
55 private boolean _closeOut;
56 private boolean _preferProxiedForAddress;
57 private String _logDateFormat = "dd/MMM/yyyy:HH:mm:ss Z";
58 private String _filenameDateFormat = null;
59 private Locale _logLocale = Locale.getDefault();
60 private String _logTimeZone = "GMT";
61 private String[] _ignorePaths;
62 private boolean _logLatency = false;
63 private boolean _logCookies = false;
64 private boolean _logServer = false;
65
66 private transient OutputStream _out;
67 private transient OutputStream _fileOut;
68 private transient DateCache _logDateCache;
69 private transient PathMap _ignorePathMap;
70 private transient Writer _writer;
71 private transient ArrayList _buffers;
72 private transient char[] _copy;
73
74 public NCSARequestLog()
75 {
76 _extended = true;
77 _append = true;
78 _retainDays = 31;
79 }
80
81
82
83
84
85
86
87 public NCSARequestLog(String filename)
88 {
89 _extended = true;
90 _append = true;
91 _retainDays = 31;
92 setFilename(filename);
93 }
94
95
96
97
98
99
100
101 public void setFilename(String filename)
102 {
103 if (filename != null)
104 {
105 filename = filename.trim();
106 if (filename.length() == 0)
107 filename = null;
108 }
109 _filename = filename;
110 }
111
112 public String getFilename()
113 {
114 return _filename;
115 }
116
117 public String getDatedFilename()
118 {
119 if (_fileOut instanceof RolloverFileOutputStream)
120 return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
121 return null;
122 }
123
124
125
126
127
128
129
130 public void setLogDateFormat(String format)
131 {
132 _logDateFormat = format;
133 }
134
135 public String getLogDateFormat()
136 {
137 return _logDateFormat;
138 }
139
140 public void setLogTimeZone(String tz)
141 {
142 _logTimeZone = tz;
143 }
144
145 public String getLogTimeZone()
146 {
147 return _logTimeZone;
148 }
149
150 public void setRetainDays(int retainDays)
151 {
152 _retainDays = retainDays;
153 }
154
155 public int getRetainDays()
156 {
157 return _retainDays;
158 }
159
160 public void setExtended(boolean extended)
161 {
162 _extended = extended;
163 }
164
165 public boolean isExtended()
166 {
167 return _extended;
168 }
169
170 public void setAppend(boolean append)
171 {
172 _append = append;
173 }
174
175 public boolean isAppend()
176 {
177 return _append;
178 }
179
180 public void setIgnorePaths(String[] ignorePaths)
181 {
182 _ignorePaths = ignorePaths;
183 }
184
185 public String[] getIgnorePaths()
186 {
187 return _ignorePaths;
188 }
189
190 public void setLogCookies(boolean logCookies)
191 {
192 _logCookies = logCookies;
193 }
194
195 public boolean getLogCookies()
196 {
197 return _logCookies;
198 }
199
200 public boolean getLogServer()
201 {
202 return _logServer;
203 }
204
205 public void setLogServer(boolean logServer)
206 {
207 _logServer = logServer;
208 }
209
210 public void setLogLatency(boolean logLatency)
211 {
212 _logLatency = logLatency;
213 }
214
215 public boolean getLogLatency()
216 {
217 return _logLatency;
218 }
219
220 public void setPreferProxiedForAddress(boolean preferProxiedForAddress)
221 {
222 _preferProxiedForAddress = preferProxiedForAddress;
223 }
224
225
226 public void log(Request request, Response response)
227 {
228 if (!isStarted())
229 return;
230
231 try
232 {
233 if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null)
234 return;
235
236 if (_fileOut == null)
237 return;
238
239 Utf8StringBuilder u8buf;
240 StringBuilder buf;
241 synchronized(_writer)
242 {
243 int size=_buffers.size();
244 u8buf = size==0?new Utf8StringBuilder(160):(Utf8StringBuilder)_buffers.remove(size-1);
245 buf = u8buf.getStringBuilder();
246 }
247
248 if (_logServer)
249 {
250 buf.append(request.getServerName());
251 buf.append(' ');
252 }
253
254 String addr = null;
255 if (_preferProxiedForAddress)
256 {
257 addr = request.getHeader(HttpHeaders.X_FORWARDED_FOR);
258 }
259
260 if (addr == null)
261 addr = request.getRemoteAddr();
262
263 buf.append(addr);
264 buf.append(" - ");
265 String user = request.getRemoteUser();
266 buf.append((user == null)?" - ":user);
267 buf.append(" [");
268 if (_logDateCache != null)
269 buf.append(_logDateCache.format(request.getTimeStamp()));
270 else
271 buf.append(request.getTimeStampBuffer().toString());
272
273 buf.append("] \"");
274 buf.append(request.getMethod());
275 buf.append(' ');
276 request.getUri().writeTo(u8buf);
277 buf.append(request.getUri());
278 buf.append(' ');
279 buf.append(request.getProtocol());
280 buf.append("\" ");
281 if (request.isSuspended())
282 buf.append("SUS");
283 else
284 {
285 int status = response.getStatus();
286 if (status <= 0)
287 status = 404;
288 buf.append((char)('0' + ((status / 100) % 10)));
289 buf.append((char)('0' + ((status / 10) % 10)));
290 buf.append((char)('0' + (status % 10)));
291 }
292
293 long responseLength = response.getContentCount();
294 if (responseLength >= 0)
295 {
296 buf.append(' ');
297 if (responseLength > 99999)
298 buf.append(Long.toString(responseLength));
299 else
300 {
301 if (responseLength > 9999)
302 buf.append((char)('0' + ((responseLength / 10000) % 10)));
303 if (responseLength > 999)
304 buf.append((char)('0' + ((responseLength / 1000) % 10)));
305 if (responseLength > 99)
306 buf.append((char)('0' + ((responseLength / 100) % 10)));
307 if (responseLength > 9)
308 buf.append((char)('0' + ((responseLength / 10) % 10)));
309 buf.append((char)('0' + (responseLength) % 10));
310 }
311 buf.append(' ');
312 }
313 else
314 buf.append(" - ");
315
316 if (!_extended && !_logCookies && !_logLatency)
317 {
318 synchronized(_writer)
319 {
320 int l=buf.length();
321 if (l>_copy.length)
322 l=_copy.length;
323 buf.append(StringUtil.__LINE_SEPARATOR);
324 buf.getChars(0,l,_copy,0);
325 _writer.write(_copy,0,l);
326 _writer.flush();
327 u8buf.reset();
328 _buffers.add(u8buf);
329 }
330 }
331 else
332 {
333 synchronized(_writer)
334 {
335 int l=buf.length();
336 if (l>_copy.length)
337 l=_copy.length;
338 buf.getChars(0,l,_copy,0);
339 _writer.write(_copy,0,l);
340 u8buf.reset();
341 _buffers.add(u8buf);
342
343
344 if (_extended)
345 logExtended(request, response, _writer);
346
347
348 if (_logCookies)
349 {
350 Cookie[] cookies = request.getCookies();
351 if (cookies == null || cookies.length == 0)
352 _writer.write(" -");
353 else
354 {
355 _writer.write(" \"");
356 for (int i = 0; i < cookies.length; i++)
357 {
358 if (i != 0)
359 _writer.write(';');
360 _writer.write(cookies[i].getName());
361 _writer.write('=');
362 _writer.write(cookies[i].getValue());
363 }
364 _writer.write('\"');
365 }
366 }
367
368 if (_logLatency)
369 {
370 _writer.write(' ');
371 _writer.write(TypeUtil.toString(System.currentTimeMillis() - request.getTimeStamp()));
372 }
373
374 _writer.write(StringUtil.__LINE_SEPARATOR);
375 _writer.flush();
376 }
377 }
378 }
379 catch (IOException e)
380 {
381 Log.warn(e);
382 }
383
384 }
385
386
387 protected void logExtended(Request request,
388 Response response,
389 Writer writer) throws IOException
390 {
391 String referer = request.getHeader(HttpHeaders.REFERER);
392 if (referer == null)
393 writer.write("\"-\" ");
394 else
395 {
396 writer.write('"');
397 writer.write(referer);
398 writer.write("\" ");
399 }
400
401 String agent = request.getHeader(HttpHeaders.USER_AGENT);
402 if (agent == null)
403 writer.write("\"-\" ");
404 else
405 {
406 writer.write('"');
407 writer.write(agent);
408 writer.write('"');
409 }
410 }
411
412
413 protected void doStart() throws Exception
414 {
415 if (_logDateFormat != null)
416 {
417 _logDateCache = new DateCache(_logDateFormat,_logLocale);
418 _logDateCache.setTimeZoneID(_logTimeZone);
419 }
420
421 if (_filename != null)
422 {
423 _fileOut = new RolloverFileOutputStream(_filename,_append,_retainDays,TimeZone.getTimeZone(_logTimeZone),_filenameDateFormat,null);
424 _closeOut = true;
425 Log.info("Opened " + getDatedFilename());
426 }
427 else
428 _fileOut = System.err;
429
430 _out = _fileOut;
431
432 if (_ignorePaths != null && _ignorePaths.length > 0)
433 {
434 _ignorePathMap = new PathMap();
435 for (int i = 0; i < _ignorePaths.length; i++)
436 _ignorePathMap.put(_ignorePaths[i],_ignorePaths[i]);
437 }
438 else
439 _ignorePathMap = null;
440
441 _writer = new OutputStreamWriter(_out);
442 _buffers = new ArrayList();
443 _copy = new char[1024];
444 super.doStart();
445 }
446
447
448 protected void doStop() throws Exception
449 {
450 super.doStop();
451 try
452 {
453 if (_writer != null)
454 _writer.flush();
455 }
456 catch (IOException e)
457 {
458 Log.ignore(e);
459 }
460 if (_out != null && _closeOut)
461 try
462 {
463 _out.close();
464 }
465 catch (IOException e)
466 {
467 Log.ignore(e);
468 }
469
470 _out = null;
471 _fileOut = null;
472 _closeOut = false;
473 _logDateCache = null;
474 _writer = null;
475 _buffers = null;
476 _copy = null;
477 }
478
479
480
481
482
483 public String getFilenameDateFormat()
484 {
485 return _filenameDateFormat;
486 }
487
488
489
490
491
492
493
494
495
496
497 public void setFilenameDateFormat(String logFileDateFormat)
498 {
499 _filenameDateFormat = logFileDateFormat;
500 }
501
502 }