costin 01/04/28 14:31:15
Added: src/share/org/apache/tomcat/modules/loggers
AccessLogInterceptor.java
Log:
Access log module, submited by Jochen Wiedmann <[EMAIL PROTECTED]>.
Initial checking, slightly modified for 3.3.
Submitted by: Jochen Wiedmann <[EMAIL PROTECTED]>
Revision Changes Path
1.1
jakarta-tomcat/src/share/org/apache/tomcat/modules/loggers/AccessLogInterceptor.java
Index: AccessLogInterceptor.java
===================================================================
package org.apache.tomcat.modules.logging;
import java.io.*;
import java.text.*;
import java.util.*;
import org.apache.tomcat.core.BaseInterceptor;
import org.apache.tomcat.core.ContextManager;
import org.apache.tomcat.core.Request;
import org.apache.tomcat.core.Response;
import org.apache.tomcat.core.TomcatException;
/** <p>This is a TomCat RequestInterceptor that creates log files
* in the style of the Apache servers "AccessLog". It used by
* embedding a line like the following into <code>server.xml</code>:</p>
* <pre>
* <RequestInterceptor
* className="org.apache.tomcat.logging.AccessLogInterceptor"
* logFile="logs/AccessLog" format="combined"/>
* </pre>
* <p>Possible attributes of the above XML element are:
* <table>
* <tr>
* <th valign="top">logFile</th>
* <td>Name of the logfile being generated. Defaults to "logs/AccessLog".
* Tomcat.home is prepended, if the file name is relative.</td>
* </tr>
* <tr>
* <th valign="top">flush</th>
* <td>An optional boolean attribute, that enables (value = "true")
* or disables (value="false", default) flushing the log file
* after every request. For performance reasons, you should
* not enable flushing unless you are debugging this class.
* </td>
* </tr>
* <tr>
* <th valign="top">format</th>
* <td>
* A string describing the logfile format. Possible values are
* "combined" (Apache httpd combined format, default), "common"
* (Apache httpd common format) or a format string like
* <pre>
* '%h %l %u %t "%r" %>s %b "%{Referer}" "%{User-Agent}"'
* '%h %l %u %t "%r" %>s %b'
* </pre>
* (The above examples are used when "combined" or "common"
* format is requested.) Possible patterns are:
* <table>
* <tr><th valign="top">%%</th>
* <td>The percent character itself</td>
* </tr>
* <tr>
* <th valign="top">%{var}</th>
* <td>The value of <code>request.getHeader("var")</code> or
* empty string for null.<td>
* </tr>
* <tr>
* <th valign="top">%b</th>
* <td>The value of <code>response.getContentLength()</code>.</td>
* </tr>
* <tr>
* <th valign="top">%h</th>
* <td>The value of <code>request.getRemoteHost()</code>.</td>
* </tr>
* <tr>
* <th valign="top">%l</th>
* <td>Should be the remote users name, as indicated by an
* identd lookup. Currently it is always "-".</td>
* </tr>
* <tr>
* <th valign="top">%r</th>
* <td>First line of the request submitted by the client, for
* example
* <pre>
* GET /index.html?frame=main HTTP/1.0
* </pre>
* The first line is rebuilt from the values of
* <code>request.getMethod()</code>,
* <code>request.getRequestURI()</code>,
* <code>request.getQueryString()</code> and
* <code>request.getProtocol()</code>. It should probably
* better be recorded while reading the headers.
* </td>
* </tr>
* <tr>
* <th valign="top">%s</th>
* <td>The value of <code>response.getStatus()</code>.</td>
* </tr>
* <tr>
* <th valign="top">%>s</th>
* <td>The value of <code>response.getStatus()</code>.
* Should differ between different internal requests, as
* Apache httpd does, but this is currently not supported.</td>
* </tr>
* <tr>
* <th valign="top">%t</th>
* <td>The current time and date in the format
* <pre>
* [20/Apr/2001:19:45:23 0200]
* </pre>
* </td>
* </tr>
* <tr>
* <th valign="top">%u</th>
* <td>The value of <code>request.getRemoteUser()</code> or
* "-" for null.</td>.
* </tr>
* <tr>
* </table>
* </td>
* </tr>
* </table>
* </p>
*
* @author Jochen Wiedmann, [EMAIL PROTECTED]
*/
public class AccessLogInterceptor extends BaseInterceptor {
private static final String LOGFORMAT_COMBINED = "%h %l %u %t \"%r\" %>s %b
\"%{Referer}\" \"%{User-Agent}\"";
private static final String LOGFORMAT_COMMON = "%h %l %u %t \"%r\" %>s %b";
private static FileWriter fw = null;
private static String fileName = "logs/AccessLog";
private static boolean useFlush = false;
private static String logformat = LOGFORMAT_COMBINED;
private static DateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss");
/** Creates a new AccessLogInterceptor */
public AccessLogInterceptor() {}
/** <p>Sets the logfile name.</p>
*/
public static void setLogFile(String logFile) {
synchronized (AccessLogInterceptor.class) {
fileName = logFile;
}
}
/** <p>Enables (true) or disables (false, default) flushing
* the log file after any request.</p>
*/
public static void setFlush(boolean flush) {
synchronized (AccessLogInterceptor.class) {
useFlush = flush;
}
}
/** <p>Sets the logfile format.</p>
*/
public static void setFormat(String format) {
synchronized (AccessLogInterceptor.class) {
if (format.equalsIgnoreCase("combined")) {
logformat = LOGFORMAT_COMBINED;
} else if (format.equalsIgnoreCase("common")) {
logformat = LOGFORMAT_COMMON;
} else {
logformat = format;
}
}
}
/** <p>This method <strong>must</strong> be called while
* synchronizing on <code>AccessLogIntercepror.class</code>!</p>
*/
private FileWriter getFileWriter() {
if (fw != null) {
return fw;
}
if (fileName != null) {
try {
File f = new File(fileName);
if (!f.isAbsolute()) {
f=new File( cm.getHome());
f=new File( f, fileName );
//f = cm.getAbsolute(f);
}
fw = new FileWriter(f.getAbsolutePath(), true);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
return fw;
}
/** <p>This method is actually creating an entry in the log file.</p>
*/
public int beforeCommit(Request request, Response response) {
synchronized (AccessLogInterceptor.class) {
FileWriter fw = getFileWriter();
if (fw != null) {
try {
for (int i = 0; i < logformat.length(); i++) {
char c = logformat.charAt(i);
if (c == '%' && ++i < logformat.length()) {
c = logformat.charAt(i);
switch (c) {
case 'h':
fw.write(request.remoteHost().toString());
break;
case 'l':
fw.write('-');
break; // identd not supported
case 'u':
String user = request.getRemoteUser();
fw.write(user == null ? "-" : user);
break;
case 't':
Calendar cal =
Calendar.getInstance();
fw.write('[');
fw.write(df.format(cal.getTime()));
fw.write(' ');
long millis =
cal.get(Calendar.ZONE_OFFSET) +
cal.get(Calendar.DST_OFFSET);
String msecstr =
Long.toString((millis+60*500)/(60*1000));
for (int j = msecstr.length(); j < 4; j++) {
fw.write('0');
}
fw.write(msecstr);
fw.write(']');
break;
case 'r':
fw.write(request.method().toString());
fw.write(' ');
fw.write(request.requestURI().toString());
String q = request.queryString().toString();
if (q != null) {
fw.write('?');
fw.write(q);
}
fw.write(' ');
fw.write(request.protocol().toString().trim());
break;
case 'b':
int len = response.getContentLength();
fw.write(Integer.toString(len));
break;
case 's':
fw.write(Integer.
toString(response.getStatus()));
break;
case '>':
if (++i < logformat.length()) {
c = logformat.charAt(i);
if (c == 's') {
fw.write(Integer.toString(response.getStatus()));
} else {
fw.write('>');
fw.write(c);
}
} else {
fw.write(c);
}
break;
case '{':
int offset = logformat.indexOf('}', i);
if (offset == -1) {
fw.write(c);
} else {
String var =
logformat.substring(i+1, offset);
String val = request.getHeader(var);
if (val != null) {
fw.write(val);
}
i = offset;
}
break;
default: fw.write(c); break;
}
} else {
fw.write(c);
}
}
fw.write('\n');
if (useFlush) {
fw.flush();
}
} catch (IOException e) {
}
}
}
return 0;
}
}