You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2007/02/19 13:19:09 UTC
svn commit: r509179 - in
/tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves: AccessLogValve.java
ExtendedAccessLogValve.java
Author: remm
Date: Mon Feb 19 04:19:08 2007
New Revision: 509179
URL: http://svn.apache.org/viewvc?view=rev&rev=509179
Log:
- Refactoring of ExtendedAccessLogValve, which now extends AccessLogValve.
- Submitted by Takayuki Kaneko.
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/AccessLogValve.java
tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/AccessLogValve.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/AccessLogValve.java?view=diff&rev=509179&r1=509178&r2=509179
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/AccessLogValve.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/AccessLogValve.java Mon Feb 19 04:19:08 2007
@@ -43,6 +43,8 @@
import org.apache.catalina.connector.Response;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
/**
@@ -116,17 +118,7 @@
extends ValveBase
implements Lifecycle {
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Construct a new instance of this class with default property values.
- */
- public AccessLogValve() {
- setPattern("common");
- }
-
+ private static Log log = LogFactory.getLog(AccessLogValve.class);
// ----------------------------------------------------- Instance Variables
@@ -168,19 +160,19 @@
/**
* The pattern used to format our access log lines.
*/
- private String pattern = null;
+ protected String pattern = null;
/**
* The prefix that is added to log file filenames.
*/
- private String prefix = "access_log.";
+ protected String prefix = "access_log.";
/**
* Should we rotate our log file? Default is true (like old behavior)
*/
- private boolean rotatable = true;
+ protected boolean rotatable = true;
/**
@@ -192,33 +184,33 @@
/**
* The string manager for this package.
*/
- private StringManager sm =
+ protected StringManager sm =
StringManager.getManager(Constants.Package);
/**
* Has this component been started yet?
*/
- private boolean started = false;
+ protected boolean started = false;
/**
* The suffix that is added to log file filenames.
*/
- private String suffix = "";
+ protected String suffix = "";
/**
* The PrintWriter to which we are currently logging, if any.
*/
- private PrintWriter writer = null;
+ protected PrintWriter writer = null;
/**
* A date formatter to format a Date into a date in the format
* "yyyy-MM-dd".
*/
- private SimpleDateFormat dateFormatter = null;
+ protected SimpleDateFormat fileDateFormatter = null;
/**
@@ -270,6 +262,12 @@
/**
+ * The current log file we are writing to. Helpful when checkExists
+ * is true.
+ */
+ protected File currentLogFile = null;
+
+ /**
* The system time when we last updated the Date that this valve
* uses for log lines.
*/
@@ -289,22 +287,28 @@
*/
private long rotationLastChecked = 0L;
-
+ /**
+ * Do we check for log file existence? Helpful if an external
+ * agent renames the log file so we can automagically recreate it.
+ */
+ private boolean checkExists = false;
+
+
/**
* Are we doing conditional logging. default false.
*/
- private String condition = null;
+ protected String condition = null;
/**
* Date format to place in log file name. Use at your own risk!
*/
- private String fileDateFormat = null;
+ protected String fileDateFormat = null;
/**
* Array of AccessLogElement, they will be used to make log message.
*/
- private AccessLogElement[] logElements = null;
+ protected AccessLogElement[] logElements = null;
// ------------------------------------------------------------- Properties
@@ -361,6 +365,28 @@
/**
+ * Check for file existence before logging.
+ */
+ public boolean isCheckExists() {
+
+ return checkExists;
+
+ }
+
+
+ /**
+ * Set whether to check for log file existence before logging.
+ *
+ * @param checkExists true meaning to check for file existence.
+ */
+ public void setCheckExists(boolean checkExists) {
+
+ this.checkExists = checkExists;
+
+ }
+
+
+ /**
* Return the log file prefix.
*/
public String getPrefix() {
@@ -519,7 +545,7 @@
long t2 = System.currentTimeMillis();
long time = t2 - t1;
- if (condition != null
+ if (logElements == null || condition != null
&& null != request.getRequest().getAttribute(condition)) {
return;
}
@@ -534,6 +560,38 @@
log(result.toString());
}
+
+ /**
+ * Rename the existing log file to something else. Then open the
+ * old log file name up once again. Intended to be called by a JMX
+ * agent.
+ *
+ *
+ * @param newFileName The file name to move the log file entry to
+ * @return true if a file was rotated with no error
+ */
+ public synchronized boolean rotate(String newFileName) {
+
+ if (currentLogFile != null) {
+ File holder = currentLogFile;
+ close();
+ try {
+ holder.renameTo(new File(newFileName));
+ } catch (Throwable e) {
+ log.error("rotate failed", e);
+ }
+
+ /* Make sure date is correct */
+ currentDate = new Date(System.currentTimeMillis());
+ dateStamp = fileDateFormatter.format(currentDate);
+
+ open();
+ return true;
+ } else {
+ return false;
+ }
+
+ }
// -------------------------------------------------------- Private Methods
@@ -549,6 +607,7 @@
writer.close();
writer = null;
dateStamp = "";
+ currentLogFile = null;
}
@@ -569,7 +628,7 @@
rotationLastChecked = systime;
// Check for a change of date
- String tsDate = dateFormatter.format(currentDate);
+ String tsDate = fileDateFormatter.format(currentDate);
// If the date has changed, switch log files
if (!dateStamp.equals(tsDate)) {
@@ -583,6 +642,25 @@
}
}
}
+
+ /* In case something external rotated the file instead */
+ if (checkExists) {
+ synchronized (this) {
+ if (currentLogFile != null && !currentLogFile.exists()) {
+ try {
+ close();
+ } catch (Throwable e) {
+ log.info("at least this wasn't swallowed", e);
+ }
+
+ /* Make sure date is correct */
+ currentDate = new Date(System.currentTimeMillis());
+ dateStamp = fileDateFormatter.format(currentDate);
+
+ open();
+ }
+ }
+ }
// Log this message
if (writer != null) {
@@ -615,7 +693,7 @@
/**
* Open the new log file for the date specified by <code>dateStamp</code>.
*/
- private synchronized void open() {
+ protected synchronized void open() {
// Create the directory if necessary
File dir = new File(directory);
if (!dir.isAbsolute())
@@ -635,8 +713,11 @@
}
writer = new PrintWriter(new BufferedWriter(new FileWriter(
pathname, true), 128000), false);
+
+ currentLogFile = new File(pathname);
} catch (IOException e) {
writer = null;
+ currentLogFile = null;
}
}
@@ -755,8 +836,8 @@
if (fileDateFormat == null || fileDateFormat.length() == 0)
fileDateFormat = "yyyy-MM-dd";
- dateFormatter = new SimpleDateFormat(fileDateFormat);
- dateFormatter.setTimeZone(timezone);
+ fileDateFormatter = new SimpleDateFormat(fileDateFormat);
+ fileDateFormatter.setTimeZone(timezone);
dayFormatter = new SimpleDateFormat("dd");
dayFormatter.setTimeZone(timezone);
monthFormatter = new SimpleDateFormat("MM");
@@ -766,7 +847,7 @@
timeFormatter = new SimpleDateFormat("HH:mm:ss");
timeFormatter.setTimeZone(timezone);
currentDate = new Date();
- dateStamp = dateFormatter.format(currentDate);
+ dateStamp = fileDateFormatter.format(currentDate);
open();
}
@@ -793,7 +874,7 @@
/**
* AccessLogElement writes the partial message into the buffer.
*/
- private interface AccessLogElement {
+ protected interface AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time);
@@ -802,14 +883,20 @@
/**
* write local IP address - %A
*/
- private class LocalAddrElement implements AccessLogElement {
+ protected class LocalAddrElement implements AccessLogElement {
+
+ private String value = null;
+
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
- String value;
- try {
- value = InetAddress.getLocalHost().getHostAddress();
- } catch (Throwable e) {
- value = "127.0.0.1";
+ if (value == null) {
+ synchronized (this) {
+ try {
+ value = InetAddress.getLocalHost().getHostAddress();
+ } catch (Throwable e) {
+ value = "127.0.0.1";
+ }
+ }
}
buf.append(value);
}
@@ -818,7 +905,7 @@
/**
* write remote IP address - %a
*/
- private class RemoteAddrElement implements AccessLogElement {
+ protected class RemoteAddrElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(request.getRemoteAddr());
@@ -828,7 +915,7 @@
/**
* write remote host name - %h
*/
- private class HostElement implements AccessLogElement {
+ protected class HostElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(request.getRemoteHost());
@@ -838,7 +925,7 @@
/**
* write remote logical username from identd (always returns '-') - %l
*/
- private class LogicalUserNameElement implements AccessLogElement {
+ protected class LogicalUserNameElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append('-');
@@ -848,7 +935,7 @@
/**
* write request protocol - %H
*/
- private class ProtocolElement implements AccessLogElement {
+ protected class ProtocolElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(request.getProtocol());
@@ -858,7 +945,7 @@
/**
* write remote user that was authenticated (if any), else '-' - %u
*/
- private class UserElement implements AccessLogElement {
+ protected class UserElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (request != null) {
@@ -877,7 +964,7 @@
/**
* write date and time, in Common Log Format - %t
*/
- private class DateAndTimeElement implements AccessLogElement {
+ protected class DateAndTimeElement implements AccessLogElement {
private Date currentDate = new Date(0);
private String currentDateString = null;
@@ -911,7 +998,7 @@
/**
* write first line of the request (method and request URI) - %r
*/
- private class RequestElement implements AccessLogElement {
+ protected class RequestElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (request != null) {
@@ -934,7 +1021,7 @@
/**
* write HTTP status code of the response - %s
*/
- private class HttpStatusCodeElement implements AccessLogElement {
+ protected class HttpStatusCodeElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (response != null) {
@@ -948,7 +1035,7 @@
/**
* write local port on which this request was received - %p
*/
- private class LocalPortElement implements AccessLogElement {
+ protected class LocalPortElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(request.getServerPort());
@@ -958,7 +1045,7 @@
/**
* write bytes sent, excluding HTTP headers - %b, %B
*/
- private class ByteSentElement implements AccessLogElement {
+ protected class ByteSentElement implements AccessLogElement {
private boolean conversion;
/**
@@ -982,7 +1069,7 @@
/**
* write request method (GET, POST, etc.) - %m
*/
- private class MethodElement implements AccessLogElement {
+ protected class MethodElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (request != null) {
@@ -994,7 +1081,7 @@
/**
* write time taken to process the request - %D, %T
*/
- private class ElapsedTimeElement implements AccessLogElement {
+ protected class ElapsedTimeElement implements AccessLogElement {
private boolean millis;
/**
@@ -1025,7 +1112,7 @@
/**
* write Query string (prepended with a '?' if it exists) - %q
*/
- private class QueryElement implements AccessLogElement {
+ protected class QueryElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
String query = null;
@@ -1041,7 +1128,7 @@
/**
* write user session ID - %S
*/
- private class SessionIdElement implements AccessLogElement {
+ protected class SessionIdElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (request != null) {
@@ -1060,7 +1147,7 @@
/**
* write requested URL path - %U
*/
- private class RequestURIElement implements AccessLogElement {
+ protected class RequestURIElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (request != null) {
@@ -1074,7 +1161,7 @@
/**
* write local server name - %v
*/
- private class LocalServerNameElement implements AccessLogElement {
+ protected class LocalServerNameElement implements AccessLogElement {
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(request.getServerName());
@@ -1084,7 +1171,7 @@
/**
* write any string
*/
- private class StringElement implements AccessLogElement {
+ protected class StringElement implements AccessLogElement {
private String str;
public StringElement(String str) {
@@ -1100,7 +1187,7 @@
/**
* write incoming headers - %{xxx}i
*/
- private class HeaderElement implements AccessLogElement {
+ protected class HeaderElement implements AccessLogElement {
private String header;
public HeaderElement(String header) {
@@ -1116,7 +1203,7 @@
/**
* write a specific cookie - %{xxx}c
*/
- private class CookieElement implements AccessLogElement {
+ protected class CookieElement implements AccessLogElement {
private String header;
public CookieElement(String header) {
@@ -1142,7 +1229,7 @@
/**
* write an attribute in the ServletRequest - %{xxx}r
*/
- private class RequestAttributeElement implements AccessLogElement {
+ protected class RequestAttributeElement implements AccessLogElement {
private String header;
public RequestAttributeElement(String header) {
@@ -1172,7 +1259,7 @@
/**
* write an attribute in the HttpSession - %{xxx}s
*/
- private class SessionAttributeElement implements AccessLogElement {
+ protected class SessionAttributeElement implements AccessLogElement {
private String header;
public SessionAttributeElement(String header) {
@@ -1207,8 +1294,8 @@
/**
* parse pattern string and create the array of AccessLogElement
*/
- private AccessLogElement[] createLogElements() {
- List list = new ArrayList();
+ protected AccessLogElement[] createLogElements() {
+ List<AccessLogElement> list = new ArrayList<AccessLogElement>();
boolean replace = false;
StringBuffer buf = new StringBuffer();
for (int i = 0; i < pattern.length(); i++) {
Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java?view=diff&rev=509179&r1=509178&r2=509179
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java Mon Feb 19 04:19:08 2007
@@ -19,31 +19,23 @@
package org.apache.catalina.valves;
-import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
-import java.io.PrintWriter;
+import java.io.StringReader;
import java.net.InetAddress;
import java.net.URLEncoder;
-import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.List;
import java.util.TimeZone;
-import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.LifecycleListener;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
-import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.ServerInfo;
-import org.apache.catalina.util.StringManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
@@ -103,7 +95,7 @@
* </p>
*
* <p>
- * For UNIX users, another field called <code>checkExists</code>is also
+ * For UvNIX users, another field called <code>checkExists</code>is also
* available. If set to true, the log file's existence will be checked before
* each logging. This way an external log rotator can move the file
* somewhere and tomcat will start with a new file.
@@ -134,650 +126,37 @@
*/
public class ExtendedAccessLogValve
- extends ValveBase
+ extends AccessLogValve
implements Lifecycle {
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Construct a new instance of this class with default property values.
- */
- public ExtendedAccessLogValve() {
-
- super();
-
-
- }
-
+ private static Log log = LogFactory.getLog(ExtendedAccessLogValve.class);
// ----------------------------------------------------- Instance Variables
- private static Log log = LogFactory.getLog(ExtendedAccessLogValve.class);
/**
* The descriptive information about this implementation.
*/
- protected static final String info =
+ protected static final String extendedAccessLogInfo =
"org.apache.catalina.valves.ExtendedAccessLogValve/1.0";
- /**
- * The lifecycle event support for this component.
- */
- protected LifecycleSupport lifecycle = new LifecycleSupport(this);
-
-
-
- /**
- * The string manager for this package.
- */
- private StringManager sm =
- StringManager.getManager(Constants.Package);
-
-
- /**
- * Has this component been started yet?
- */
- private boolean started = false;
-
-
- /**
- * The as-of date for the currently open log file, or a zero-length
- * string if there is no open log file.
- */
- private String dateStamp = "";
-
-
- /**
- * The PrintWriter to which we are currently logging, if any.
- */
- private PrintWriter writer = null;
-
-
- /**
- * The formatter for the date contained in the file name.
- */
- private SimpleDateFormat fileDateFormatter = null;
-
-
- /**
- * A date formatter to format a Date into a date in the format
- * "yyyy-MM-dd".
- */
- private SimpleDateFormat dateFormatter = null;
-
-
- /**
- * A date formatter to format a Date into a time in the format
- * "kk:mm:ss" (kk is a 24-hour representation of the hour).
- */
- private SimpleDateFormat timeFormatter = null;
-
-
- /**
- * Time taken formatter for 3 decimal places.
- */
- private DecimalFormat timeTakenFormatter = null;
-
-
- /**
- * My ip address. Look it up once and remember it. Dump this if we can
- * determine another reliable way to get server ip address since this
- * server may have many ip's.
- */
- private String myIpAddress = null;
-
-
- /**
- * My dns name. Look it up once and remember it. Dump this if we can
- * determine another reliable way to get server name address since this
- * server may have many ip's.
- */
- private String myDNSName = null;
-
-
- /**
- * Holder for all of the fields to log after the pattern is decoded.
- */
- private FieldInfo[] fieldInfos;
-
-
- /**
- * The current log file we are writing to. Helpful when checkExists
- * is true.
- */
- private File currentLogFile = null;
-
-
-
- /**
- * The system time when we last updated the Date that this valve
- * uses for log lines.
- */
- private Date currentDate = null;
-
-
- /**
- * Instant when the log daily rotation was last checked.
- */
- private long rotationLastChecked = 0L;
-
-
- /**
- * The directory in which log files are created.
- */
- private String directory = "logs";
-
-
- /**
- * The pattern used to format our access log lines.
- */
- private String pattern = null;
-
-
- /**
- * The prefix that is added to log file filenames.
- */
- private String prefix = "access_log.";
-
-
- /**
- * Should we rotate our log file? Default is true (like old behavior)
- */
- private boolean rotatable = true;
-
-
- /**
- * The suffix that is added to log file filenames.
- */
- private String suffix = "";
-
-
- /**
- * Are we doing conditional logging. default false.
- */
- private String condition = null;
-
-
- /**
- * Do we check for log file existence? Helpful if an external
- * agent renames the log file so we can automagically recreate it.
- */
- private boolean checkExists = false;
-
-
- /**
- * Date format to place in log file name. Use at your own risk!
- */
- private String fileDateFormat = null;
-
-
// ------------------------------------------------------------- Properties
/**
- * Return the directory in which we create log files.
- */
- public String getDirectory() {
-
- return (directory);
-
- }
-
-
- /**
- * Set the directory in which we create log files.
- *
- * @param directory The new log file directory
- */
- public void setDirectory(String directory) {
-
- this.directory = directory;
-
- }
-
-
- /**
* Return descriptive information about this implementation.
*/
public String getInfo() {
-
- return (info);
-
- }
-
-
- /**
- * Return the format pattern.
- */
- public String getPattern() {
-
- return (this.pattern);
-
- }
-
-
- /**
- * Set the format pattern, first translating any recognized alias.
- *
- * @param pattern The new pattern pattern
- */
- public void setPattern(String pattern) {
-
- FieldInfo[] f= decodePattern(pattern);
- if (f!=null) {
- this.pattern = pattern;
- this.fieldInfos = f;
- }
- }
-
-
- /**
- * Return the log file prefix.
- */
- public String getPrefix() {
-
- return (prefix);
-
- }
-
-
- /**
- * Set the log file prefix.
- *
- * @param prefix The new log file prefix
- */
- public void setPrefix(String prefix) {
-
- this.prefix = prefix;
-
- }
-
-
- /**
- * Return true if logs are automatically rotated.
- */
- public boolean isRotatable() {
-
- return rotatable;
-
- }
-
-
- /**
- * Set the value is we should we rotate the logs
- *
- * @param rotatable true is we should rotate.
- */
- public void setRotatable(boolean rotatable) {
-
- this.rotatable = rotatable;
-
- }
-
-
- /**
- * Return the log file suffix.
- */
- public String getSuffix() {
-
- return (suffix);
-
- }
-
-
- /**
- * Set the log file suffix.
- *
- * @param suffix The new log file suffix
- */
- public void setSuffix(String suffix) {
-
- this.suffix = suffix;
-
- }
-
-
-
- /**
- * Return whether the attribute name to look for when
- * performing conditional loggging. If null, every
- * request is logged.
- */
- public String getCondition() {
-
- return condition;
-
- }
-
-
- /**
- * Set the ServletRequest.attribute to look for to perform
- * conditional logging. Set to null to log everything.
- *
- * @param condition Set to null to log everything
- */
- public void setCondition(String condition) {
-
- this.condition = condition;
-
- }
-
-
-
- /**
- * Check for file existence before logging.
- */
- public boolean isCheckExists() {
-
- return checkExists;
-
- }
-
-
- /**
- * Set whether to check for log file existence before logging.
- *
- * @param checkExists true meaning to check for file existence.
- */
- public void setCheckExists(boolean checkExists) {
-
- this.checkExists = checkExists;
-
- }
-
-
- /**
- * Return the date format date based log rotation.
- */
- public String getFileDateFormat() {
- return fileDateFormat;
- }
-
-
- /**
- * Set the date format date based log rotation.
- */
- public void setFileDateFormat(String fileDateFormat) {
- this.fileDateFormat = fileDateFormat;
+ return (extendedAccessLogInfo);
}
// --------------------------------------------------------- Public Methods
- /**
- * Log a message summarizing the specified request and response, according
- * to the format specified by the <code>pattern</code> property.
- *
- * @param request Request being processed
- * @param response Response being processed
- *
- * @exception IOException if an input/output error has occurred
- * @exception ServletException if a servlet error has occurred
- */
- public void invoke(Request request, Response response)
- throws IOException, ServletException {
-
- // Pass this request on to the next valve in our pipeline
- long endTime;
- long runTime;
- long startTime=System.currentTimeMillis();
-
- getNext().invoke(request, response);
-
- endTime = System.currentTimeMillis();
- runTime = endTime-startTime;
-
- if (fieldInfos==null || condition!=null &&
- null!=request.getRequest().getAttribute(condition)) {
- return;
- }
-
-
- Date date = getDate(endTime);
- StringBuffer result = new StringBuffer();
-
- for (int i=0; fieldInfos!=null && i<fieldInfos.length; i++) {
- switch(fieldInfos[i].type) {
- case FieldInfo.DATA_CLIENT:
- if (FieldInfo.FIELD_IP==fieldInfos[i].location)
- result.append(request.getRequest().getRemoteAddr());
- else if (FieldInfo.FIELD_DNS==fieldInfos[i].location)
- result.append(request.getRequest().getRemoteHost());
- else
- result.append("?WTF?"); /* This should never happen! */
- break;
- case FieldInfo.DATA_SERVER:
- if (FieldInfo.FIELD_IP==fieldInfos[i].location)
- result.append(myIpAddress);
- else if (FieldInfo.FIELD_DNS==fieldInfos[i].location)
- result.append(myDNSName);
- else
- result.append("?WTF?"); /* This should never happen! */
- break;
- case FieldInfo.DATA_REMOTE:
- result.append('?'); /* I don't know how to handle these! */
- break;
- case FieldInfo.DATA_CLIENT_TO_SERVER:
- result.append(getClientToServer(fieldInfos[i], request));
- break;
- case FieldInfo.DATA_SERVER_TO_CLIENT:
- result.append(getServerToClient(fieldInfos[i], response));
- break;
- case FieldInfo.DATA_SERVER_TO_RSERVER:
- result.append('-');
- break;
- case FieldInfo.DATA_RSERVER_TO_SERVER:
- result.append('-');
- break;
- case FieldInfo.DATA_APP_SPECIFIC:
- result.append(getAppSpecific(fieldInfos[i], request));
- break;
- case FieldInfo.DATA_SPECIAL:
- if (FieldInfo.SPECIAL_DATE==fieldInfos[i].location)
- result.append(dateFormatter.format(date));
- else if (FieldInfo.SPECIAL_TIME_TAKEN==fieldInfos[i].location)
- result.append(timeTakenFormatter.format(runTime/1000d));
- else if (FieldInfo.SPECIAL_TIME==fieldInfos[i].location)
- result.append(timeFormatter.format(date));
- else if (FieldInfo.SPECIAL_BYTES==fieldInfos[i].location) {
- int length = response.getContentCount();
- if (length > 0)
- result.append(length);
- else
- result.append("-");
- } else if (FieldInfo.SPECIAL_CACHED==fieldInfos[i].location)
- result.append('-'); /* I don't know how to evaluate this! */
- else
- result.append("?WTF?"); /* This should never happen! */
- break;
- default:
- result.append("?WTF?"); /* This should never happen! */
- }
-
- if (fieldInfos[i].postWhiteSpace!=null) {
- result.append(fieldInfos[i].postWhiteSpace);
- }
- }
- log(result.toString(), date);
-
- }
-
-
- /**
- * Rename the existing log file to something else. Then open the
- * old log file name up once again. Intended to be called by a JMX
- * agent.
- *
- *
- * @param newFileName The file name to move the log file entry to
- * @return true if a file was rotated with no error
- */
- public synchronized boolean rotate(String newFileName) {
-
- if (currentLogFile!=null) {
- File holder = currentLogFile;
- close();
- try {
- holder.renameTo(new File(newFileName));
- } catch(Throwable e){
- log.error("rotate failed", e);
- }
-
- /* Make sure date is correct */
- currentDate = new Date(System.currentTimeMillis());
- dateStamp = fileDateFormatter.format(currentDate);
-
- open();
- return true;
- } else {
- return false;
- }
-
- }
-
// -------------------------------------------------------- Private Methods
-
- /**
- * Return the client to server data.
- * @param fieldInfo The field to decode.
- * @param request The object we pull data from.
- * @return The appropriate value.
- */
- private String getClientToServer(FieldInfo fieldInfo, Request request) {
-
- switch(fieldInfo.location) {
- case FieldInfo.FIELD_METHOD:
- return request.getMethod();
- case FieldInfo.FIELD_URI:
- if (null==request.getQueryString())
- return request.getRequestURI();
- else
- return request.getRequestURI() + "?" + request.getQueryString();
- case FieldInfo.FIELD_URI_STEM:
- return request.getRequestURI();
- case FieldInfo.FIELD_URI_QUERY:
- if (null==request.getQueryString())
- return "-";
- return request.getQueryString();
- case FieldInfo.FIELD_HEADER:
- return wrap(request.getHeader(fieldInfo.value));
- default:
- ;
- }
-
- return "-";
-
- }
-
-
- /**
- * Return the server to client data.
- * @param fieldInfo The field to decode.
- * @param response The object we pull data from.
- * @return The appropriate value.
- */
- private String getServerToClient(FieldInfo fieldInfo, Response response) {
- switch(fieldInfo.location) {
- case FieldInfo.FIELD_STATUS:
- return "" + response.getStatus();
- case FieldInfo.FIELD_COMMENT:
- return "?"; /* Not coded yet*/
- case FieldInfo.FIELD_HEADER:
- return wrap(response.getHeader(fieldInfo.value));
- default:
- ;
- }
-
- return "-";
-
- }
-
-
- /**
- * Get app specific data.
- * @param fieldInfo The field to decode
- * @param request Where we will pull the data from.
- * @return The appropriate value
- */
- private String getAppSpecific(FieldInfo fieldInfo, Request request) {
-
- switch(fieldInfo.xType) {
- case FieldInfo.X_PARAMETER:
- return wrap(urlEncode(request.getParameter(fieldInfo.value)));
- case FieldInfo.X_REQUEST:
- return wrap(request.getAttribute(fieldInfo.value));
- case FieldInfo.X_SESSION:
- HttpSession session = null;
- if (request!=null){
- session = request.getSession(false);
- if (session!=null)
- return wrap(session.getAttribute(fieldInfo.value));
- }
- break;
- case FieldInfo.X_COOKIE:
- Cookie[] c = request.getCookies();
- for (int i=0; c != null && i < c.length; i++){
- if (fieldInfo.value.equals(c[i].getName())){
- return wrap(c[i].getValue());
- }
- }
- case FieldInfo.X_APP:
- return wrap(request.getContext().getServletContext()
- .getAttribute(fieldInfo.value));
- case FieldInfo.X_SERVLET_REQUEST:
- if (fieldInfo.location==FieldInfo.X_LOC_AUTHTYPE) {
- return wrap(request.getAuthType());
- } else if (fieldInfo.location==FieldInfo.X_LOC_REMOTEUSER) {
- return wrap(request.getRemoteUser());
- } else if (fieldInfo.location==
- FieldInfo.X_LOC_REQUESTEDSESSIONID) {
- return wrap(request.getRequestedSessionId());
- } else if (fieldInfo.location==
- FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE) {
- return wrap(""+request.isRequestedSessionIdFromCookie());
- } else if (fieldInfo.location==
- FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID) {
- return wrap(""+request.isRequestedSessionIdValid());
- } else if (fieldInfo.location==FieldInfo.X_LOC_CONTENTLENGTH) {
- return wrap(""+request.getContentLength());
- } else if (fieldInfo.location==
- FieldInfo.X_LOC_CHARACTERENCODING) {
- return wrap(request.getCharacterEncoding());
- } else if (fieldInfo.location==FieldInfo.X_LOC_LOCALE) {
- return wrap(request.getLocale());
- } else if (fieldInfo.location==FieldInfo.X_LOC_PROTOCOL) {
- return wrap(request.getProtocol());
- } else if (fieldInfo.location==FieldInfo.X_LOC_SCHEME) {
- return wrap(request.getScheme());
- } else if (fieldInfo.location==FieldInfo.X_LOC_SECURE) {
- return wrap(""+request.isSecure());
- }
- break;
- default:
- ;
- }
-
- return "-";
-
- }
-
-
- /**
- * urlEncode the given string. If null or empty, return null.
- */
- private String urlEncode(String value) {
- if (null==value || value.length()==0) {
- return null;
- }
- return URLEncoder.encode(value);
- }
-
-
/**
* Wrap the incoming value into quotes and escape any inner
* quotes with double quotes.
@@ -789,642 +168,640 @@
* sets of quotes.
*/
private String wrap(Object value) {
-
String svalue;
// Does the value contain a " ? If so must encode it
- if (value==null || "-".equals(value))
+ if (value == null || "-".equals(value))
return "-";
-
try {
svalue = value.toString();
if ("".equals(svalue))
return "-";
- } catch(Throwable e){
+ } catch (Throwable e) {
/* Log error */
return "-";
}
/* Wrap all quotes in double quotes. */
- StringBuffer buffer = new StringBuffer(svalue.length()+2);
- buffer.append('"');
- int i=0;
- while (i<svalue.length()) {
- int j = svalue.indexOf('"', i);
- if (j==-1) {
+ StringBuffer buffer = new StringBuffer(svalue.length() + 2);
+ buffer.append('\'');
+ int i = 0;
+ while (i < svalue.length()) {
+ int j = svalue.indexOf('\'', i);
+ if (j == -1) {
buffer.append(svalue.substring(i));
- i=svalue.length();
+ i = svalue.length();
} else {
- buffer.append(svalue.substring(i, j+1));
+ buffer.append(svalue.substring(i, j + 1));
buffer.append('"');
- i=j+2;
+ i = j + 2;
}
}
- buffer.append('"');
+ buffer.append('\'');
return buffer.toString();
-
}
-
/**
- * Close the currently open log file (if any)
+ * Open the new log file for the date specified by <code>dateStamp</code>.
*/
- private synchronized void close() {
-
- if (writer == null)
- return;
- writer.flush();
- writer.close();
- writer = null;
- currentLogFile = null;
-
+ protected synchronized void open() {
+ super.open();
+ if (currentLogFile.length()==0) {
+ writer.println("#Fields: " + pattern);
+ writer.println("#Version: 1.0");
+ writer.println("#Software: " + ServerInfo.getServerInfo());
+ }
}
- /**
- * Log the specified message to the log file, switching files if the date
- * has changed since the previous log call.
- *
- * @param message Message to be logged
- * @param date the current Date object (so this method doesn't need to
- * create a new one)
- */
- private void log(String message, Date date) {
+ // ------------------------------------------------------ Lifecycle Methods
- if (rotatable){
- // Only do a logfile switch check once a second, max.
- long systime = System.currentTimeMillis();
- if ((systime - rotationLastChecked) > 1000) {
-
- // We need a new currentDate
- currentDate = new Date(systime);
- rotationLastChecked = systime;
-
- // Check for a change of date
- String tsDate = fileDateFormatter.format(currentDate);
-
- // If the date has changed, switch log files
- if (!dateStamp.equals(tsDate)) {
- synchronized (this) {
- if (!dateStamp.equals(tsDate)) {
- close();
- dateStamp = tsDate;
- open();
- }
+
+ protected class DateElement implements AccessLogElement {
+ private Date currentDate = new Date(0);
+
+ private String currentDateString = null;
+
+ /**
+ * A date formatter to format a Date into a date in the format
+ * "yyyy-MM-dd".
+ */
+ private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
+
+ public DateElement() {
+ dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ if (currentDate != date) {
+ synchronized (this) {
+ if (currentDate != date) {
+ currentDateString = dateFormatter.format(date);
+ currentDate = date;
}
}
}
+ buf.append(currentDateString);
}
-
- /* In case something external rotated the file instead */
- if (checkExists){
- synchronized (this) {
- if (currentLogFile!=null && !currentLogFile.exists()) {
- try {
- close();
- } catch (Throwable e){
- log.info("at least this wasn't swallowed", e);
+ }
+
+ protected class TimeElement implements AccessLogElement {
+ private Date currentDate = new Date(0);
+
+ private String currentTimeString = null;
+
+ /**
+ * A date formatter to format a Date into a time in the format
+ * "kk:mm:ss" (kk is a 24-hour representation of the hour).
+ */
+ private SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
+
+ public TimeElement() {
+ timeFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ if (currentDate != date) {
+ synchronized (this) {
+ if (currentDate != date) {
+ currentTimeString = timeFormatter.format(date);
+ currentDate = date;
}
-
- /* Make sure date is correct */
- currentDate = new Date(System.currentTimeMillis());
- dateStamp = fileDateFormatter.format(currentDate);
-
- open();
}
}
+ buf.append(currentTimeString);
}
-
- // Log this message
- if (writer != null) {
- writer.println(message);
+ }
+
+ protected class RequestHeaderElement implements AccessLogElement {
+ private String header;
+
+ public RequestHeaderElement(String header) {
+ this.header = header;
+ }
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ buf.append(wrap(request.getHeader(header)));
+ }
+ }
+
+ protected class ResponseHeaderElement implements AccessLogElement {
+ private String header;
+
+ public ResponseHeaderElement(String header) {
+ this.header = header;
+ }
+
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ buf.append(wrap(response.getHeader(header)));
+ }
+ }
+
+ protected class ServletContextElement implements AccessLogElement {
+ private String attribute;
+
+ public ServletContextElement(String attribute) {
+ this.attribute = attribute;
+ }
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ buf.append(wrap(request.getContext().getServletContext()
+ .getAttribute(attribute)));
+ }
+ }
+
+ protected class CookieElement implements AccessLogElement {
+ private String name;
+
+ public CookieElement(String name) {
+ this.name = name;
+ }
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ Cookie[] c = request.getCookies();
+ for (int i = 0; c != null && i < c.length; i++) {
+ if (name.equals(c[i].getName())) {
+ buf.append(wrap(c[i].getValue()));
+ }
+ }
}
-
}
-
-
- /**
- * Open the new log file for the date specified by <code>dateStamp</code>.
- */
- private synchronized void open() {
-
- // Create the directory if necessary
- File dir = new File(directory);
- if (!dir.isAbsolute())
- dir = new File(System.getProperty("catalina.base"), directory);
- dir.mkdirs();
-
- // Open the current log file
- try {
- String pathname;
-
- // If no rotate - no need for dateStamp in fileName
- if (rotatable){
- pathname = dir.getAbsolutePath() + File.separator +
- prefix + dateStamp + suffix;
+
+ protected class RequestAttributeElement implements AccessLogElement {
+ private String attribute;
+
+ public RequestAttributeElement(String attribute) {
+ this.attribute = attribute;
+ }
+
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ buf.append(wrap(request.getAttribute(attribute)));
+ }
+ }
+
+ protected class SessionAttributeElement implements AccessLogElement {
+ private String attribute;
+
+ public SessionAttributeElement(String attribute) {
+ this.attribute = attribute;
+ }
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ HttpSession session = null;
+ if (request != null) {
+ session = request.getSession(false);
+ if (session != null)
+ buf.append(wrap(session.getAttribute(attribute)));
+ }
+ }
+ }
+
+ protected class RequestParameterElement implements AccessLogElement {
+ private String parameter;
+
+ public RequestParameterElement(String parameter) {
+ this.parameter = parameter;
+ }
+ /**
+ * urlEncode the given string. If null or empty, return null.
+ */
+ private String urlEncode(String value) {
+ if (null==value || value.length()==0) {
+ return null;
+ }
+ return URLEncoder.encode(value);
+ }
+
+ public void addElement(StringBuffer buf, Date date, Request request,
+ Response response, long time) {
+ buf.append(wrap(urlEncode(request.getParameter(parameter))));
+ }
+ }
+
+ protected class PatternTokenizer {
+ private StringReader sr = null;
+ private StringBuffer buf = new StringBuffer();
+ private boolean ended = false;
+ private boolean subToken;
+ private boolean parameter;
+
+ public PatternTokenizer(String str) {
+ sr = new StringReader(str);
+ }
+
+ public boolean hasSubToken() {
+ return subToken;
+ }
+
+ public boolean hasParameter() {
+ return parameter;
+ }
+
+ public String getToken() throws IOException {
+ String result = null;
+ subToken = false;
+ parameter = false;
+
+ int c = sr.read();
+ while (c != -1) {
+ switch (c) {
+ case ' ':
+ result = buf.toString();
+ buf = new StringBuffer();
+ buf.append((char) c);
+ return result;
+ case '-':
+ result = buf.toString();
+ buf = new StringBuffer();
+ subToken = true;
+ return result;
+ case '(':
+ result = buf.toString();
+ buf = new StringBuffer();
+ parameter = true;
+ return result;
+ case ')':
+ result = buf.toString();
+ buf = new StringBuffer();
+ break;
+ default:
+ buf.append((char) c);
+ }
+ c = sr.read();
+ }
+ ended = true;
+ if (buf.length() != 0) {
+ return buf.toString();
} else {
- pathname = dir.getAbsolutePath() + File.separator +
- prefix + suffix;
+ return null;
}
-
- currentLogFile = new File(pathname);
- writer = new PrintWriter(new FileWriter(pathname, true), true);
- if (currentLogFile.length()==0) {
- writer.println("#Fields: " + pattern);
- writer.println("#Version: 1.0");
- writer.println("#Software: " + ServerInfo.getServerInfo());
+ }
+
+ public String getParameter()throws IOException {
+ String result;
+ if (!parameter) {
+ return null;
}
-
-
- } catch (IOException e) {
- writer = null;
- currentLogFile = null;
+ parameter = false;
+ int c = sr.read();
+ while (c != -1) {
+ if (c == ')') {
+ result = buf.toString();
+ buf = new StringBuffer();
+ return result;
+ }
+ buf.append((char) c);
+ c = sr.read();
+ }
+ return null;
}
-
- }
-
-
- /**
- * This method returns a Date object that is accurate to within one
- * second. If a thread calls this method to get a Date and it's been
- * less than 1 second since a new Date was created, this method
- * simply gives out the same Date again so that the system doesn't
- * spend time creating Date objects unnecessarily.
- */
- private Date getDate(long systime) {
- /* Avoid extra call to System.currentTimeMillis(); */
- if (0==systime) {
- systime = System.currentTimeMillis();
+
+ public String getWhiteSpaces() throws IOException {
+ StringBuffer whiteSpaces = new StringBuffer();
+ if (buf.length() > 0) {
+ whiteSpaces.append(buf);
+ buf = new StringBuffer();
+ }
+ int c = sr.read();
+ while (Character.isWhitespace((char) c)) {
+ whiteSpaces.append((char) c);
+ c = sr.read();
+ }
+ if (c == -1) {
+ ended = true;
+ } else {
+ buf.append((char) c);
+ }
+ return whiteSpaces.toString();
}
-
- // Only create a new Date once per second, max.
- if ((systime - currentDate.getTime()) > 1000) {
- currentDate.setTime(systime);
+
+ public boolean isEnded() {
+ return ended;
}
-
- return currentDate;
-
- }
-
-
- // ------------------------------------------------------ Lifecycle Methods
-
-
- /**
- * Add a lifecycle event listener to this component.
- *
- * @param listener The listener to add
- */
- public void addLifecycleListener(LifecycleListener listener) {
-
- lifecycle.addLifecycleListener(listener);
-
- }
-
-
- /**
- * Get the lifecycle listeners associated with this lifecycle. If this
- * Lifecycle has no listeners registered, a zero-length array is returned.
- */
- public LifecycleListener[] findLifecycleListeners() {
-
- return lifecycle.findLifecycleListeners();
-
- }
-
-
- /**
- * Remove a lifecycle event listener from this component.
- *
- * @param listener The listener to add
- */
- public void removeLifecycleListener(LifecycleListener listener) {
-
- lifecycle.removeLifecycleListener(listener);
-
- }
-
-
- /**
- * Prepare for the beginning of active use of the public methods of this
- * component. This method should be called after <code>configure()</code>,
- * and before any of the public methods of the component are utilized.
- *
- * @exception LifecycleException if this component detects a fatal error
- * that prevents this component from being used
- */
- public void start() throws LifecycleException {
-
- // Validate and update our current component state
- if (started)
- throw new LifecycleException
- (sm.getString("extendedAccessLogValve.alreadyStarted"));
- lifecycle.fireLifecycleEvent(START_EVENT, null);
- started = true;
-
- // Initialize the timeZone, Date formatters, and currentDate
- TimeZone tz = TimeZone.getTimeZone("GMT");
- dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
- dateFormatter.setTimeZone(tz);
- timeFormatter = new SimpleDateFormat("HH:mm:ss");
- timeFormatter.setTimeZone(tz);
- currentDate = new Date(System.currentTimeMillis());
- if (fileDateFormat==null || fileDateFormat.length()==0)
- fileDateFormat = "yyyy-MM-dd";
- fileDateFormatter = new SimpleDateFormat(fileDateFormat);
- dateStamp = fileDateFormatter.format(currentDate);
- timeTakenFormatter = new DecimalFormat("0.000");
-
- /* Everybody say ick ... ick */
- try {
- InetAddress inetAddress = InetAddress.getLocalHost();
- myIpAddress = inetAddress.getHostAddress();
- myDNSName = inetAddress.getHostName();
- } catch(Throwable e){
- myIpAddress="127.0.0.1";
- myDNSName="localhost";
+
+ public String getRemains() throws IOException {
+ StringBuffer remains = new StringBuffer();
+ for(int c = sr.read(); c != -1; c = sr.read()) {
+ remains.append((char) c);
+ }
+ return remains.toString();
}
-
- open();
-
+
}
+
+ protected AccessLogElement[] createLogElements() {
+ if (log.isDebugEnabled()) {
+ log.debug("decodePattern, pattern =" + pattern);
+ }
+ List<AccessLogElement> list = new ArrayList<AccessLogElement>();
+ PatternTokenizer tokenizer = new PatternTokenizer(pattern);
+ try {
- /**
- * Gracefully terminate the active use of the public methods of this
- * component. This method should be the last one called on a given
- * instance of this component.
- *
- * @exception LifecycleException if this component detects a fatal error
- * that needs to be reported
- */
- public void stop() throws LifecycleException {
-
- // Validate and update our current component state
- if (!started)
- throw new LifecycleException
- (sm.getString("extendedAccessLogValve.notStarted"));
- lifecycle.fireLifecycleEvent(STOP_EVENT, null);
- started = false;
-
- close();
-
- }
-
-
- /**
- * Decode the given pattern. Is public so a pattern may
- * allows to be validated.
- * @param fields The pattern to decode
- * @return null on error. Otherwise array of decoded fields
- */
- public FieldInfo[] decodePattern(String fields) {
-
- if (log.isDebugEnabled())
- log.debug("decodePattern, fields=" + fields);
-
- LinkedList list = new LinkedList();
+ // Ignore leading whitespace.
+ tokenizer.getWhiteSpaces();
- //Ignore leading whitespace.
- int i=0;
- for (;i<fields.length() && Character.isWhitespace(fields.charAt(i));i++);
+ if (tokenizer.isEnded()) {
+ log.info("pattern was just empty or whitespace");
+ return null;
+ }
- if (i>=fields.length()) {
- log.info("fields was just empty or whitespace");
+ String token = tokenizer.getToken();
+ while (token != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("token = " + token);
+ }
+ AccessLogElement element = getLogElement(token, tokenizer);
+ if (element == null) {
+ break;
+ }
+ list.add(element);
+ String whiteSpaces = tokenizer.getWhiteSpaces();
+ if (whiteSpaces.length() > 0) {
+ list.add(new StringElement(whiteSpaces));
+ }
+ if (tokenizer.isEnded()) {
+ break;
+ }
+ token = tokenizer.getToken();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("finished decoding with element size of: " + list.size());
+ }
+ return (AccessLogElement[]) list.toArray(new AccessLogElement[0]);
+ } catch (IOException e) {
+ log.error("parse error", e);
return null;
}
-
- int j;
- while(i<fields.length()) {
- if (log.isDebugEnabled())
- log.debug("fields.substring(i)=" + fields.substring(i));
-
- FieldInfo currentFieldInfo = new FieldInfo();
-
-
- if (fields.startsWith("date",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
- currentFieldInfo.location = FieldInfo.SPECIAL_DATE;
- i+="date".length();
- } else if (fields.startsWith("time-taken",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
- currentFieldInfo.location = FieldInfo.SPECIAL_TIME_TAKEN;
- i+="time-taken".length();
- } else if (fields.startsWith("time",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
- currentFieldInfo.location = FieldInfo.SPECIAL_TIME;
- i+="time".length();
- } else if (fields.startsWith("bytes",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
- currentFieldInfo.location = FieldInfo.SPECIAL_BYTES;
- i+="bytes".length();
- } else if (fields.startsWith("cached",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
- currentFieldInfo.location = FieldInfo.SPECIAL_CACHED;
- i+="cached".length();
- } else if (fields.startsWith("c-ip",i)) {
- currentFieldInfo.type = FieldInfo.DATA_CLIENT;
- currentFieldInfo.location = FieldInfo.FIELD_IP;
- i+="c-ip".length();
- } else if (fields.startsWith("c-dns",i)) {
- currentFieldInfo.type = FieldInfo.DATA_CLIENT;
- currentFieldInfo.location = FieldInfo.FIELD_DNS;
- i+="c-dns".length();
- } else if (fields.startsWith("s-ip",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SERVER;
- currentFieldInfo.location = FieldInfo.FIELD_IP;
- i+="s-ip".length();
- } else if (fields.startsWith("s-dns",i)) {
- currentFieldInfo.type = FieldInfo.DATA_SERVER;
- currentFieldInfo.location = FieldInfo.FIELD_DNS;
- i+="s-dns".length();
- } else if (fields.startsWith("cs",i)) {
- i = decode(fields, i+2, currentFieldInfo,
- FieldInfo.DATA_CLIENT_TO_SERVER);
- if (i<0)
- return null;
- } else if (fields.startsWith("sc",i)) {
- i = decode(fields, i+2, currentFieldInfo,
- FieldInfo.DATA_SERVER_TO_CLIENT);
- if (i<0)
- return null;
- } else if (fields.startsWith("sr",i)) {
- i = decode(fields, i+2, currentFieldInfo,
- FieldInfo.DATA_SERVER_TO_RSERVER);
- if (i<0)
- return null;
- } else if (fields.startsWith("rs",i)) {
- i = decode(fields, i+2, currentFieldInfo,
- FieldInfo.DATA_RSERVER_TO_SERVER);
- if (i<0)
- return null;
- } else if (fields.startsWith("x",i)) {
- i = decodeAppSpecific(fields, i, currentFieldInfo);
+ }
+
+ protected AccessLogElement getLogElement(String token, PatternTokenizer tokenizer) throws IOException {
+ if ("date".equals(token)) {
+ return new DateElement();
+ } else if ("time".equals(token)) {
+ if (tokenizer.hasSubToken()) {
+ String nextToken = tokenizer.getToken();
+ if ("taken".equals(nextToken)) {
+ return new ElapsedTimeElement(false);
+ }
} else {
- // Unable to decode ...
- log.error("unable to decode with rest of chars being: " +
- fields.substring(i));
- return null;
+ return new TimeElement();
}
-
- // By this point we should have the field, get the whitespace
- j=i;
- for (;j<fields.length() && Character.isWhitespace(fields.charAt(j));j++);
-
- if (j>=fields.length()) {
- if (j==i) {
- // Special case - end of string
- currentFieldInfo.postWhiteSpace = "";
+ } else if ("bytes".equals(token)) {
+ return new ByteSentElement(true);
+ } else if ("cached".equals(token)) {
+ /* I don't know how to evaluate this! */
+ return new StringElement("-");
+ } else if ("c".equals(token)) {
+ String nextToken = tokenizer.getToken();
+ if ("ip".equals(nextToken)) {
+ return new RemoteAddrElement();
+ } else if ("dns".equals(nextToken)) {
+ return new HostElement();
+ }
+ } else if ("s".equals(token)) {
+ String nextToken = tokenizer.getToken();
+ if ("ip".equals(nextToken)) {
+ return new LocalAddrElement();
+ } else if ("dns".equals(nextToken)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ String value;
+ try {
+ value = InetAddress.getLocalHost().getHostName();
+ } catch (Throwable e) {
+ value = "localhost";
+ }
+ buf.append(value);
+ }
+ };
+ }
+ } else if ("cs".equals(token)) {
+ return getClientToServerElement(tokenizer);
+ } else if ("sc".equals(token)) {
+ return getServerToClientElement(tokenizer);
+ } else if ("sr".equals(token) || "rs".equals(token)) {
+ return getProxyElement(tokenizer);
+ } else if ("x".equals(token)) {
+ return getXParameterElement(tokenizer);
+ }
+ log.error("unable to decode with rest of chars starting: " + token);
+ return null;
+ }
+
+ protected AccessLogElement getClientToServerElement(
+ PatternTokenizer tokenizer) throws IOException {
+ if (tokenizer.hasSubToken()) {
+ String token = tokenizer.getToken();
+ if ("method".equals(token)) {
+ return new MethodElement();
+ } else if ("uri".equals(token)) {
+ if (tokenizer.hasSubToken()) {
+ token = tokenizer.getToken();
+ if ("stem".equals(token)) {
+ return new RequestURIElement();
+ } else if ("query".equals(token)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response,
+ long time) {
+ String query = request.getQueryString();
+ if (query != null) {
+ buf.append(query);
+ } else {
+ buf.append('-');
+ }
+ }
+ };
+ }
} else {
- currentFieldInfo.postWhiteSpace = fields.substring(i);
- i=j;
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ String query = request.getQueryString();
+ if (query != null) {
+ buf.append(request.getRequestURI());
+ } else {
+ buf.append(request.getRequestURI());
+ buf.append('?');
+ buf.append(request.getQueryString());
+ }
+ }
+ };
}
- } else {
- currentFieldInfo.postWhiteSpace = fields.substring(i,j);
- i=j;
}
-
- list.add(currentFieldInfo);
+ } else if (tokenizer.hasParameter()) {
+ String parameter = tokenizer.getParameter();
+ if (parameter == null) {
+ log.error("No closing ) found for in decode");
+ return null;
+ }
+ return new RequestHeaderElement(parameter);
}
-
- i=0;
- FieldInfo[] f = new FieldInfo[list.size()];
- for (Iterator k = list.iterator(); k.hasNext();)
- f[i++] = (FieldInfo)k.next();
-
- if (log.isDebugEnabled())
- log.debug("finished decoding with length of: " + i);
-
- return f;
- }
-
- /**
- * Decode the cs or sc fields.
- * Returns negative on error.
- *
- * @param fields The pattern to decode
- * @param i The string index where we are decoding.
- * @param fieldInfo Where to store the results
- * @param type The type we are decoding.
- * @return -1 on error. Otherwise the new String index.
- */
- private int decode(String fields, int i, FieldInfo fieldInfo, short type) {
-
- if (fields.startsWith("-status",i)) {
- fieldInfo.location = FieldInfo.FIELD_STATUS;
- i+="-status".length();
- } else if (fields.startsWith("-comment",i)) {
- fieldInfo.location = FieldInfo.FIELD_COMMENT;
- i+="-comment".length();
- } else if (fields.startsWith("-uri-query",i)) {
- fieldInfo.location = FieldInfo.FIELD_URI_QUERY;
- i+="-uri-query".length();
- } else if (fields.startsWith("-uri-stem",i)) {
- fieldInfo.location = FieldInfo.FIELD_URI_STEM;
- i+="-uri-stem".length();
- } else if (fields.startsWith("-uri",i)) {
- fieldInfo.location = FieldInfo.FIELD_URI;
- i+="-uri".length();
- } else if (fields.startsWith("-method",i)) {
- fieldInfo.location = FieldInfo.FIELD_METHOD;
- i+="-method".length();
- } else if (fields.startsWith("(",i)) {
- fieldInfo.location = FieldInfo.FIELD_HEADER;
- i++; /* Move past the ( */
- int j = fields.indexOf(')', i);
- if (j==-1) { /* Not found */
+ log.error("The next characters couldn't be decoded: "
+ + tokenizer.getRemains());
+ return null;
+ }
+
+ protected AccessLogElement getServerToClientElement(
+ PatternTokenizer tokenizer) throws IOException {
+ if (tokenizer.hasSubToken()) {
+ String token = tokenizer.getToken();
+ if ("status".equals(token)) {
+ return new HttpStatusCodeElement();
+ } else if ("comment".equals(token)) {
+ return new StringElement("?");
+ }
+ } else if (tokenizer.hasParameter()) {
+ String parameter = tokenizer.getParameter();
+ if (parameter == null) {
log.error("No closing ) found for in decode");
- return -1;
+ return null;
}
- fieldInfo.value = fields.substring(i,j);
- i=j+1; // Move pointer past ) */
- } else {
- log.error("The next characters couldn't be decoded: " + fields.substring(i));
- return -1;
+ return new ResponseHeaderElement(parameter);
}
-
- fieldInfo.type = type;
- return i;
-
- }
-
-
- /**
- * Decode app specific log entry.
- *
- * Special fields are of the form:
- * x-C(...) - For cookie
- * x-A(...) - Value in servletContext
- * x-S(...) - Value in session
- * x-R(...) - Value in servletRequest
- * @param fields The pattern to decode
- * @param i The string index where we are decoding.
- * @param fieldInfo Where to store the results
- * @return -1 on error. Otherwise the new String index.
- */
- private int decodeAppSpecific(String fields, int i, FieldInfo fieldInfo) {
-
- fieldInfo.type = FieldInfo.DATA_APP_SPECIFIC;
- /* Move past 'x-' */
- i+=2;
-
- if (i>=fields.length()) {
- log.error("End of line reached before decoding x- param");
- return -1;
- }
-
- switch(fields.charAt(i)) {
- case 'A':
- fieldInfo.xType = FieldInfo.X_APP;
- break;
- case 'C':
- fieldInfo.xType = FieldInfo.X_COOKIE;
- break;
- case 'R':
- fieldInfo.xType = FieldInfo.X_REQUEST;
- break;
- case 'S':
- fieldInfo.xType = FieldInfo.X_SESSION;
- break;
- case 'H':
- fieldInfo.xType = FieldInfo.X_SERVLET_REQUEST;
- break;
- case 'P':
- fieldInfo.xType = FieldInfo.X_PARAMETER;
- break;
- default:
- return -1;
+ log.error("The next characters couldn't be decoded: "
+ + tokenizer.getRemains());
+ return null;
+ }
+
+ protected AccessLogElement getProxyElement(PatternTokenizer tokenizer)
+ throws IOException {
+ String token = null;
+ if (tokenizer.hasSubToken()) {
+ token = tokenizer.getToken();
+ return new StringElement("-");
+ } else if (tokenizer.hasParameter()) {
+ tokenizer.getParameter();
+ return new StringElement("-");
+ }
+ log.error("The next characters couldn't be decoded: " + token);
+ return null;
+ }
+
+ protected AccessLogElement getXParameterElement(PatternTokenizer tokenizer)
+ throws IOException {
+ if (!tokenizer.hasSubToken()) {
+ log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
+ return null;
}
-
- /* test that next char is a ( */
- if (i+1!=fields.indexOf('(',i)) {
+ String token = tokenizer.getToken();
+ if (!tokenizer.hasParameter()) {
log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
- return -1;
+ return null;
}
- i+=2; /* Move inside of the () */
-
- /* Look for ending ) and return error if not found. */
- int j = fields.indexOf(')',i);
- if (j==-1) {
- log.error("x param in wrong format. No closing ')'!");
- return -1;
- }
-
- fieldInfo.value = fields.substring(i,j);
-
- if (fieldInfo.xType == FieldInfo.X_SERVLET_REQUEST) {
- if ("authType".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_AUTHTYPE;
- } else if ("remoteUser".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_REMOTEUSER;
- } else if ("requestedSessionId".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONID;
- } else if ("requestedSessionIdFromCookie".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE;
- } else if ("requestedSessionIdValid".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID;
- } else if ("contentLength".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_CONTENTLENGTH;
- } else if ("characterEncoding".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_CHARACTERENCODING;
- } else if ("locale".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_LOCALE;
- } else if ("protocol".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_PROTOCOL;
- } else if ("scheme".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_SCHEME;
- } else if ("secure".equals(fieldInfo.value)){
- fieldInfo.location = FieldInfo.X_LOC_SECURE;
- } else {
- log.error("x param for servlet request, couldn't decode value: " +
- fieldInfo.location);
- return -1;
- }
+ String parameter = tokenizer.getParameter();
+ if (parameter == null) {
+ log.error("No closing ) found for in decode");
+ return null;
}
-
- return j+1;
-
+ if ("A".equals(token)) {
+ return new ServletContextElement(parameter);
+ } else if ("C".equals(token)) {
+ return new CookieElement(parameter);
+ } else if ("R".equals(token)) {
+ return new RequestAttributeElement(parameter);
+ } else if ("S".equals(token)) {
+ return new SessionAttributeElement(parameter);
+ } else if ("H".equals(token)) {
+ return getServletRequestElement(parameter);
+ } else if ("P".equals(token)) {
+ return new RequestParameterElement(parameter);
+ }
+ log.error("x param for servlet request, couldn't decode value: "
+ + token);
+ return null;
+ }
+
+ protected AccessLogElement getServletRequestElement(String parameter) {
+ if ("authType".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getAuthType()));
+ }
+ };
+ } else if ("remoteUser".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getRemoteUser()));
+ }
+ };
+ } else if ("requestedSessionId".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getRequestedSessionId()));
+ }
+ };
+ } else if ("requestedSessionIdFromCookie".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(""
+ + request.isRequestedSessionIdFromCookie()));
+ }
+ };
+ } else if ("requestedSessionIdValid".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap("" + request.isRequestedSessionIdValid()));
+ }
+ };
+ } else if ("contentLength".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap("" + request.getContentLength()));
+ }
+ };
+ } else if ("characterEncoding".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getCharacterEncoding()));
+ }
+ };
+ } else if ("locale".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getLocale()));
+ }
+ };
+ } else if ("protocol".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap(request.getProtocol()));
+ }
+ };
+ } else if ("scheme".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(request.getScheme());
+ }
+ };
+ } else if ("secure".equals(parameter)) {
+ return new AccessLogElement() {
+ public void addElement(StringBuffer buf, Date date,
+ Request request, Response response, long time) {
+ buf.append(wrap("" + request.isSecure()));
+ }
+ };
+ }
+ log.error("x param for servlet request, couldn't decode value: "
+ + parameter);
+ return null;
}
-
-
-}
-
-/**
- * A simple helper for decoding the pattern.
- */
-class FieldInfo {
- /*
- The goal of the constants listed below is to make the construction of the log
- entry as quick as possible via numerci decodings of the methods to call instead
- of performing many String comparisons on each logging request.
- */
-
- /* Where the data is located. */
- static final short DATA_CLIENT = 0;
- static final short DATA_SERVER = 1;
- static final short DATA_REMOTE = 2;
- static final short DATA_CLIENT_TO_SERVER = 3;
- static final short DATA_SERVER_TO_CLIENT = 4;
- static final short DATA_SERVER_TO_RSERVER = 5; /* Here to honor the spec. */
- static final short DATA_RSERVER_TO_SERVER = 6; /* Here to honor the spec. */
- static final short DATA_APP_SPECIFIC = 7;
- static final short DATA_SPECIAL = 8;
-
- /* The type of special fields. */
- static final short SPECIAL_DATE = 1;
- static final short SPECIAL_TIME_TAKEN = 2;
- static final short SPECIAL_TIME = 3;
- static final short SPECIAL_BYTES = 4;
- static final short SPECIAL_CACHED = 5;
-
- /* Where to pull the data for prefixed values */
- static final short FIELD_IP = 1;
- static final short FIELD_DNS = 2;
- static final short FIELD_STATUS = 3;
- static final short FIELD_COMMENT = 4;
- static final short FIELD_METHOD = 5;
- static final short FIELD_URI = 6;
- static final short FIELD_URI_STEM = 7;
- static final short FIELD_URI_QUERY = 8;
- static final short FIELD_HEADER = 9;
-
-
- /* Application Specific parameters */
- static final short X_REQUEST = 1; /* For x app specific */
- static final short X_SESSION = 2; /* For x app specific */
- static final short X_COOKIE = 3; /* For x app specific */
- static final short X_APP = 4; /* For x app specific */
- static final short X_SERVLET_REQUEST = 5; /* For x app specific */
- static final short X_PARAMETER = 6; /* For x app specific */
-
- static final short X_LOC_AUTHTYPE = 1;
- static final short X_LOC_REMOTEUSER = 2;
- static final short X_LOC_REQUESTEDSESSIONID = 3;
- static final short X_LOC_REQUESTEDSESSIONIDFROMCOOKIE = 4;
- static final short X_LOC_REQUESTEDSESSIONIDVALID = 5;
- static final short X_LOC_CONTENTLENGTH = 6;
- static final short X_LOC_CHARACTERENCODING = 7;
- static final short X_LOC_LOCALE = 8;
- static final short X_LOC_PROTOCOL = 9;
- static final short X_LOC_SCHEME = 10;
- static final short X_LOC_SECURE = 11;
-
-
-
- /** The field type */
- short type;
-
- /** Where to pull the data from? Icky variable name. */
- short location;
-
- /** The x- specific place to pull the data from. */
- short xType;
-
- /** The field value if needed. Needed for headers and app specific. */
- String value;
-
- /** Any white space after this field? Put it here. */
- String postWhiteSpace = null;
-
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org