From: remm Date: Mon, 8 Jan 2007 20:51:00 +0000 (+0000) Subject: - Replace AccessLogValve with the new fast one (since I don't think 3 valves doing... X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=533b158de1471056669a1a3374a06fffa5e40049;p=tomcat7.0 - Replace AccessLogValve with the new fast one (since I don't think 3 valves doing the same thing are needed). - Remove FastCommon, which has the same optimizations. - Add a new buffered field to allow flushing on each request, which should make the behavior equivalent to the old AccessLogValve. git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@494191 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/catalina/valves/AccessLogValve.java b/java/org/apache/catalina/valves/AccessLogValve.java index 0afdd212e..1c4484aec 100644 --- a/java/org/apache/catalina/valves/AccessLogValve.java +++ b/java/org/apache/catalina/valves/AccessLogValve.java @@ -19,15 +19,17 @@ package org.apache.catalina.valves; +import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; -import java.text.DecimalFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.List; import java.util.TimeZone; import javax.servlet.ServletException; @@ -105,7 +107,9 @@ import org.apache.catalina.util.StringManager; * * @author Craig R. McClanahan * @author Jason Brittain - * @version $Revision$ $Date$ + * @author Remy Maucherat + * @author Takayuki Kaneko + * @version $Revision$ $Date: 2007-01-04 12:17:11 +0900 */ public class AccessLogValve @@ -120,11 +124,7 @@ public class AccessLogValve * Construct a new instance of this class with default property values. */ public AccessLogValve() { - - super(); setPattern("common"); - - } @@ -148,7 +148,7 @@ public class AccessLogValve * The descriptive information about this implementation. */ protected static final String info = - "org.apache.catalina.valves.AccessLogValve/1.0"; + "org.apache.catalina.valves.FastAccessLogValve/1.0"; /** @@ -166,21 +166,6 @@ public class AccessLogValve /** - * If the current log pattern is the same as the common access log - * format pattern, then we'll set this variable to true and log in - * a more optimal and hard-coded way. - */ - private boolean common = false; - - - /** - * For the combined format (common, plus useragent and referer), we do - * the same - */ - private boolean combined = false; - - - /** * The pattern used to format our access log lines. */ private String pattern = null; @@ -199,6 +184,12 @@ public class AccessLogValve /** + * Buffered logging. + */ + private boolean buffered = true; + + + /** * The string manager for this package. */ private StringManager sm = @@ -245,12 +236,6 @@ public class AccessLogValve /** - * Time taken formatter for 3 decimal places. - */ - private DecimalFormat timeTakenFormatter = null; - - - /** * A date formatter to format a Date into a year string in the format * "yyyy". */ @@ -289,12 +274,8 @@ public class AccessLogValve * uses for log lines. */ private Date currentDate = null; - - - /** - * When formatting log lines, we often use strings like this one (" "). - */ - private String space = " "; + + private long currentMillis = 0; /** @@ -319,6 +300,11 @@ public class AccessLogValve * Date format to place in log file name. Use at your own risk! */ private String fileDateFormat = null; + + /** + * Array of AccessLogElement, they will be used to make log message. + */ + private AccessLogElement[] logElements = null; // ------------------------------------------------------------- Properties @@ -327,9 +313,7 @@ public class AccessLogValve * Return the directory in which we create log files. */ public String getDirectory() { - return (directory); - } @@ -339,9 +323,7 @@ public class AccessLogValve * @param directory The new log file directory */ public void setDirectory(String directory) { - this.directory = directory; - } @@ -349,9 +331,7 @@ public class AccessLogValve * Return descriptive information about this implementation. */ public String getInfo() { - return (info); - } @@ -359,9 +339,7 @@ public class AccessLogValve * Return the format pattern. */ public String getPattern() { - return (this.pattern); - } @@ -371,7 +349,6 @@ public class AccessLogValve * @param pattern The new pattern */ public void setPattern(String pattern) { - if (pattern == null) pattern = ""; if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) @@ -379,17 +356,7 @@ public class AccessLogValve if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) pattern = Constants.AccessLog.COMBINED_PATTERN; this.pattern = pattern; - - if (this.pattern.equals(Constants.AccessLog.COMMON_PATTERN)) - common = true; - else - common = false; - - if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) - combined = true; - else - combined = false; - + logElements = createLogElements(); } @@ -397,9 +364,7 @@ public class AccessLogValve * Return the log file prefix. */ public String getPrefix() { - return (prefix); - } @@ -409,9 +374,7 @@ public class AccessLogValve * @param prefix The new log file prefix */ public void setPrefix(String prefix) { - this.prefix = prefix; - } @@ -419,9 +382,7 @@ public class AccessLogValve * Should we rotate the logs */ public boolean isRotatable() { - return rotatable; - } @@ -431,9 +392,25 @@ public class AccessLogValve * @param rotatable true is we should rotate. */ public void setRotatable(boolean rotatable) { - this.rotatable = rotatable; + } + + /** + * Is the logging buffered + */ + public boolean isBuffered() { + return buffered; + } + + + /** + * Set the value if the logging should be buffered + * + * @param buffered true if buffered. + */ + public void setBuffered(boolean buffered) { + this.buffered = buffered; } @@ -441,9 +418,7 @@ public class AccessLogValve * Return the log file suffix. */ public String getSuffix() { - return (suffix); - } @@ -453,9 +428,7 @@ public class AccessLogValve * @param suffix The new log file suffix */ public void setSuffix(String suffix) { - this.suffix = suffix; - } @@ -465,9 +438,7 @@ public class AccessLogValve * @param resolveHosts The new resolve hosts value */ public void setResolveHosts(boolean resolveHosts) { - this.resolveHosts = resolveHosts; - } @@ -475,9 +446,7 @@ public class AccessLogValve * Get the value of the resolve hosts flag. */ public boolean isResolveHosts() { - return resolveHosts; - } @@ -487,9 +456,7 @@ public class AccessLogValve * request is logged. */ public String getCondition() { - return condition; - } @@ -500,9 +467,7 @@ public class AccessLogValve * @param condition Set to null to log everything */ public void setCondition(String condition) { - this.condition = condition; - } /** @@ -522,6 +487,16 @@ public class AccessLogValve // --------------------------------------------------------- Public Methods + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + if (writer != null && buffered) { + writer.flush(); + } + } /** * Log a message summarizing the specified request and response, according @@ -533,141 +508,30 @@ public class AccessLogValve * @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 { + public void invoke(Request request, Response response) throws IOException, + ServletException { // Pass this request on to the next valve in our pipeline - long t1=System.currentTimeMillis(); + long t1 = System.currentTimeMillis(); getNext().invoke(request, response); - long t2=System.currentTimeMillis(); - long time=t2-t1; + long t2 = System.currentTimeMillis(); + long time = t2 - t1; - if (condition!=null && - null!=request.getRequest().getAttribute(condition)) { + if (condition != null + && null != request.getRequest().getAttribute(condition)) { return; } - Date date = getDate(); StringBuffer result = new StringBuffer(); - // Check to see if we should log using the "common" access log pattern - if (common || combined) { - String value = null; - - if (isResolveHosts()) - result.append(request.getRemoteHost()); - else - result.append(request.getRemoteAddr()); - - result.append(" - "); - - value = request.getRemoteUser(); - if (value == null) - result.append("- "); - else { - result.append(value); - result.append(space); - } - - result.append("["); - result.append(dayFormatter.format(date)); // Day - result.append('/'); - result.append(lookup(monthFormatter.format(date))); // Month - result.append('/'); - result.append(yearFormatter.format(date)); // Year - result.append(':'); - result.append(timeFormatter.format(date)); // Time - result.append(space); - result.append(getTimeZone(date)); // Time Zone - result.append("] \""); - - result.append(request.getMethod()); - result.append(space); - result.append(request.getRequestURI()); - if (request.getQueryString() != null) { - result.append('?'); - result.append(request.getQueryString()); - } - result.append(space); - result.append(request.getProtocol()); - result.append("\" "); - - result.append(response.getStatus()); - - result.append(space); - - int length = response.getContentCount(); - - if (length <= 0) - value = "-"; - else - value = "" + length; - result.append(value); - - if (combined) { - result.append(space); - result.append("\""); - String referer = request.getHeader("referer"); - if(referer != null) - result.append(referer); - else - result.append("-"); - result.append("\""); - - result.append(space); - result.append("\""); - String ua = request.getHeader("user-agent"); - if(ua != null) - result.append(ua); - else - result.append("-"); - result.append("\""); - } - - } else { - // Generate a message based on the defined pattern - boolean replace = false; - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (replace) { - /* For code that processes {, the behavior will be ... if I - * do not enounter a closing } - then I ignore the { - */ - if ('{' == ch){ - StringBuffer name = new StringBuffer(); - int j = i + 1; - for(;j < pattern.length() && '}' != pattern.charAt(j); j++) { - name.append(pattern.charAt(j)); - } - if (j+1 < pattern.length()) { - /* the +1 was to account for } which we increment now */ - j++; - result.append(replace(name.toString(), - pattern.charAt(j), - request, - response)); - i=j; /*Since we walked more than one character*/ - } else { - //D'oh - end of string - pretend we never did this - //and do processing the "old way" - result.append(replace(ch, date, request, response, time)); - } - } else { - result.append(replace(ch, date, request, response,time )); - } - replace = false; - } else if (ch == '%') { - replace = true; - } else { - result.append(ch); - } - } + for (int i = 0; i < logElements.length; i++) { + logElements[i].addElement(result, date, request, response, time); } - log(result.toString(), date); + log(result.toString()); } @@ -678,14 +542,13 @@ public class AccessLogValve * Close the currently open log file (if any) */ private synchronized void close() { - - if (writer == null) + if (writer == null) { return; + } writer.flush(); writer.close(); writer = null; dateStamp = ""; - } @@ -694,12 +557,9 @@ public class AccessLogValve * 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) */ - public void log(String message, Date date) { - - if (rotatable){ + public void log(String message) { + if (rotatable) { // Only do a logfile switch check once a second, max. long systime = System.currentTimeMillis(); if ((systime - rotationLastChecked) > 1000) { @@ -721,13 +581,15 @@ public class AccessLogValve } } } - } } // Log this message if (writer != null) { writer.println(message); + if (!buffered) { + writer.flush(); + } } } @@ -740,7 +602,6 @@ public class AccessLogValve * @param month Month number ("01" .. "12"). */ private String lookup(String month) { - int index; try { index = Integer.parseInt(month) - 1; @@ -748,7 +609,6 @@ public class AccessLogValve index = 0; // Can not happen, in theory } return (months[index]); - } @@ -756,7 +616,6 @@ public class AccessLogValve * Open the new log file for the date specified by dateStamp. */ private synchronized void open() { - // Create the directory if necessary File dir = new File(directory); if (!dir.isAbsolute()) @@ -767,228 +626,40 @@ public class AccessLogValve try { String pathname; // If no rotate - no need for dateStamp in fileName - if (rotatable){ - pathname = dir.getAbsolutePath() + File.separator + - prefix + dateStamp + suffix; + if (rotatable) { + pathname = dir.getAbsolutePath() + File.separator + prefix + + dateStamp + suffix; } else { - pathname = dir.getAbsolutePath() + File.separator + - prefix + suffix; + pathname = dir.getAbsolutePath() + File.separator + prefix + + suffix; } - writer = new PrintWriter(new FileWriter(pathname, true), true); + writer = new PrintWriter(new BufferedWriter(new FileWriter( + pathname, true), 128000), false); } catch (IOException e) { writer = null; } - } - - + /** - * Return the replacement text for the specified pattern character. - * - * @param pattern Pattern character identifying the desired text - * @param date the current Date so that this method doesn't need to - * create one - * @param request Request being processed - * @param response Response being processed + * 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. + * + * @return Date */ - private String replace(char pattern, Date date, Request request, - Response response, long time) { - - String value = null; - - if (pattern == 'a') { - value = request.getRemoteAddr(); - } else if (pattern == 'A') { - try { - value = InetAddress.getLocalHost().getHostAddress(); - } catch(Throwable e){ - value = "127.0.0.1"; - } - } else if (pattern == 'b') { - int length = response.getContentCount(); - if (length <= 0) - value = "-"; - else - value = "" + length; - } else if (pattern == 'B') { - value = "" + response.getContentLength(); - } else if (pattern == 'h') { - value = request.getRemoteHost(); - } else if (pattern == 'H') { - value = request.getProtocol(); - } else if (pattern == 'l') { - value = "-"; - } else if (pattern == 'm') { - if (request != null) - value = request.getMethod(); - else - value = ""; - } else if (pattern == 'p') { - value = "" + request.getServerPort(); - } else if (pattern == 'D') { - value = "" + time; - } else if (pattern == 'q') { - String query = null; - if (request != null) - query = request.getQueryString(); - if (query != null) - value = "?" + query; - else - value = ""; - } else if (pattern == 'r') { - StringBuffer sb = new StringBuffer(); - if (request != null) { - sb.append(request.getMethod()); - sb.append(space); - sb.append(request.getRequestURI()); - if (request.getQueryString() != null) { - sb.append('?'); - sb.append(request.getQueryString()); + private Date getDate() { + // Only create a new Date once per second, max. + long systime = System.currentTimeMillis(); + if ((systime - currentMillis) > 1000) { + synchronized (this) { + if ((systime - currentMillis) > 1000) { + currentDate = new Date(systime); + currentMillis = systime; } - sb.append(space); - sb.append(request.getProtocol()); - } else { - sb.append("- - "); - sb.append(request.getProtocol()); } - value = sb.toString(); - } else if (pattern == 'S') { - if (request != null) - if (request.getSession(false) != null) - value = request.getSessionInternal(false).getIdInternal(); - else value = "-"; - else - value = "-"; - } else if (pattern == 's') { - if (response != null) - value = "" + response.getStatus(); - else - value = "-"; - } else if (pattern == 't') { - StringBuffer temp = new StringBuffer("["); - temp.append(dayFormatter.format(date)); // Day - temp.append('/'); - temp.append(lookup(monthFormatter.format(date))); // Month - temp.append('/'); - temp.append(yearFormatter.format(date)); // Year - temp.append(':'); - temp.append(timeFormatter.format(date)); // Time - temp.append(' '); - temp.append(getTimeZone(date)); // Timezone - temp.append(']'); - value = temp.toString(); - } else if (pattern == 'T') { - value = timeTakenFormatter.format(time/1000d); - } else if (pattern == 'u') { - if (request != null) - value = request.getRemoteUser(); - if (value == null) - value = "-"; - } else if (pattern == 'U') { - if (request != null) - value = request.getRequestURI(); - else - value = "-"; - } else if (pattern == 'v') { - value = request.getServerName(); - } else { - value = "???" + pattern + "???"; - } - - if (value == null) - return (""); - else - return (value); - - } - - - /** - * Return the replacement text for the specified "header/parameter". - * - * @param header The header/parameter to get - * @param type Where to get it from i=input,c=cookie,r=ServletRequest,s=Session - * @param request Request being processed - * @param response Response being processed - */ - private String replace(String header, char type, Request request, - Response response) { - - Object value = null; - - switch (type) { - case 'i': - if (null != request) - value = request.getHeader(header); - else - value= "??"; - break; -/* - // Someone please make me work - case 'o': - break; -*/ - case 'c': - Cookie[] c = request.getCookies(); - for (int i=0; c != null && i < c.length; i++){ - if (header.equals(c[i].getName())){ - value = c[i].getValue(); - break; - } - } - break; - case 'r': - if (null != request) - value = request.getAttribute(header); - else - value= "??"; - break; - case 's': - if (null != request) { - HttpSession sess = request.getSession(false); - if (null != sess) - value = sess.getAttribute(header); - } - break; - default: - value = "???"; - } - - /* try catch in case toString() barfs */ - try { - if (value!=null) - if (value instanceof String) - return (String)value; - else - return value.toString(); - else - return "-"; - } catch(Throwable e) { - return "-"; } - } - - - /** - * 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. - * - * @return Date - */ - private Date getDate() { - if(currentDate == null) { - currentDate = new Date(); - } else { - // Only create a new Date once per second, max. - long systime = System.currentTimeMillis(); - if ((systime - currentDate.getTime()) > 1000) { - currentDate = new Date(systime); - } - } - return currentDate; } @@ -1004,21 +675,21 @@ public class AccessLogValve private String calculateTimeZoneOffset(long offset) { StringBuffer tz = new StringBuffer(); - if ((offset<0)) { + if ((offset < 0)) { tz.append("-"); offset = -offset; } else { tz.append("+"); } - long hourOffset = offset/(1000*60*60); - long minuteOffset = (offset/(1000*60)) % 60; + long hourOffset = offset / (1000 * 60 * 60); + long minuteOffset = (offset / (1000 * 60)) % 60; - if (hourOffset<10) + if (hourOffset < 10) tz.append("0"); tz.append(hourOffset); - if (minuteOffset<10) + if (minuteOffset < 10) tz.append("0"); tz.append(minuteOffset); @@ -1035,9 +706,7 @@ public class AccessLogValve * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { - lifecycle.addLifecycleListener(listener); - } @@ -1046,9 +715,7 @@ public class AccessLogValve * Lifecycle has no listeners registered, a zero-length array is returned. */ public LifecycleListener[] findLifecycleListeners() { - return lifecycle.findLifecycleListeners(); - } @@ -1058,9 +725,7 @@ public class AccessLogValve * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { - lifecycle.removeLifecycleListener(listener); - } @@ -1076,8 +741,8 @@ public class AccessLogValve // Validate and update our current component state if (started) - throw new LifecycleException - (sm.getString("accessLogValve.alreadyStarted")); + throw new LifecycleException(sm + .getString("accessLogValve.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; @@ -1086,9 +751,9 @@ public class AccessLogValve timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); Calendar calendar = Calendar.getInstance(timezone); int offset = calendar.get(Calendar.DST_OFFSET); - timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); - - if (fileDateFormat==null || fileDateFormat.length()==0) + timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset() + offset); + + if (fileDateFormat == null || fileDateFormat.length() == 0) fileDateFormat = "yyyy-MM-dd"; dateFormatter = new SimpleDateFormat(fileDateFormat); dateFormatter.setTimeZone(timezone); @@ -1102,10 +767,7 @@ public class AccessLogValve timeFormatter.setTimeZone(timezone); currentDate = new Date(); dateStamp = dateFormatter.format(currentDate); - timeTakenFormatter = new DecimalFormat("0.000"); - open(); - } @@ -1121,12 +783,539 @@ public class AccessLogValve // Validate and update our current component state if (!started) - throw new LifecycleException - (sm.getString("accessLogValve.notStarted")); + throw new LifecycleException(sm + .getString("accessLogValve.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; - close(); + } + + /** + * AccessLogElement writes the partial message into the buffer. + */ + private interface AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time); + + } + + /** + * write local IP address - %A + */ + private class LocalAddrElement implements AccessLogElement { + 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"; + } + buf.append(value); + } + } + + /** + * write remote IP address - %a + */ + private class RemoteAddrElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getRemoteAddr()); + } + } + + /** + * write remote host name - %h + */ + private class HostElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getRemoteHost()); + } + } + + /** + * write remote logical username from identd (always returns '-') - %l + */ + private class LogicalUserNameElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append('-'); + } + } + + /** + * write request protocol - %H + */ + private class ProtocolElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getProtocol()); + } + } + + /** + * write remote user that was authenticated (if any), else '-' - %u + */ + private class UserElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (request != null) { + String value = request.getRemoteUser(); + if (value != null) { + buf.append(value); + } else { + buf.append('-'); + } + } else { + buf.append('-'); + } + } + } + + /** + * write date and time, in Common Log Format - %t + */ + private class DateAndTimeElement implements AccessLogElement { + private Date currentDate = new Date(0); + + private String currentDateString = null; + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (currentDate != date) { + synchronized (this) { + if (currentDate != date) { + StringBuffer current = new StringBuffer(32); + current.append('['); + current.append(dayFormatter.format(date)); // Day + current.append('/'); + current.append(lookup(monthFormatter.format(date))); // Month + current.append('/'); + current.append(yearFormatter.format(date)); // Year + current.append(':'); + current.append(timeFormatter.format(date)); // Time + current.append(' '); + current.append(getTimeZone(date)); // Timezone + current.append(']'); + currentDateString = current.toString(); + currentDate = date; + } + } + } + buf.append(currentDateString); + } + } + + /** + * write first line of the request (method and request URI) - %r + */ + private class RequestElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (request != null) { + buf.append(request.getMethod()); + buf.append(' '); + buf.append(request.getRequestURI()); + if (request.getQueryString() != null) { + buf.append('?'); + buf.append(request.getQueryString()); + } + buf.append(' '); + buf.append(request.getProtocol()); + } else { + buf.append("- - "); + buf.append(request.getProtocol()); + } + } + } + + /** + * write HTTP status code of the response - %s + */ + private class HttpStatusCodeElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (response != null) { + buf.append(response.getStatus()); + } else { + buf.append('-'); + } + } + } + + /** + * write local port on which this request was received - %p + */ + private class LocalPortElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getServerPort()); + } + } + + /** + * write bytes sent, excluding HTTP headers - %b, %B + */ + private class ByteSentElement implements AccessLogElement { + private boolean conversion; + + /** + * if conversion is true, write '-' instead of 0 - %b + */ + public ByteSentElement(boolean conversion) { + this.conversion = conversion; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + int length = response.getContentCount(); + if (length <= 0 && conversion) { + buf.append('-'); + } else { + buf.append(length); + } + } + } + + /** + * write request method (GET, POST, etc.) - %m + */ + private class MethodElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (request != null) { + buf.append(request.getMethod()); + } + } + } + + /** + * write time taken to process the request - %D, %T + */ + private class ElapsedTimeElement implements AccessLogElement { + private boolean millis; + + /** + * if millis is true, write time in millis - %D + * if millis is false, write time in seconds - %T + */ + public ElapsedTimeElement(boolean millis) { + this.millis = millis; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (millis) { + buf.append(time); + } else { + // second + buf.append(time / 1000); + buf.append('.'); + int remains = (int) (time % 1000); + buf.append(remains / 100); + remains = remains % 100; + buf.append(remains / 10); + buf.append(remains % 10); + } + } + } + + /** + * write Query string (prepended with a '?' if it exists) - %q + */ + private class QueryElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + String query = null; + if (request != null) + query = request.getQueryString(); + if (query != null) { + buf.append('?'); + buf.append(query); + } + } + } + + /** + * write user session ID - %S + */ + private class SessionIdElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (request != null) { + if (request.getSession(false) != null) { + buf.append(request.getSessionInternal(false) + .getIdInternal()); + } else { + buf.append('-'); + } + } else { + buf.append('-'); + } + } + } + + /** + * write requested URL path - %U + */ + private class RequestURIElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + if (request != null) { + buf.append(request.getRequestURI()); + } else { + buf.append('-'); + } + } + } + + /** + * write local server name - %v + */ + private class LocalServerNameElement implements AccessLogElement { + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getServerName()); + } + } + + /** + * write any string + */ + private class StringElement implements AccessLogElement { + private String str; + + public StringElement(String str) { + this.str = str; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(str); + } + } + + /** + * write incoming headers - %{xxx}i + */ + private class HeaderElement implements AccessLogElement { + private String header; + + public HeaderElement(String header) { + this.header = header; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + buf.append(request.getHeader(header)); + } + } + + /** + * write a specific cookie - %{xxx}c + */ + private class CookieElement implements AccessLogElement { + private String header; + + public CookieElement(String header) { + this.header = header; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + String value = "-"; + Cookie[] c = request.getCookies(); + if (c != null) { + for (int i = 0; i < c.length; i++) { + if (header.equals(c[i].getName())) { + value = c[i].getValue(); + break; + } + } + } + buf.append(value); + } + } + + /** + * write an attribute in the ServletRequest - %{xxx}r + */ + private class RequestAttributeElement implements AccessLogElement { + private String header; + + public RequestAttributeElement(String header) { + this.header = header; + } + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + Object value = null; + if (request != null) { + value = request.getAttribute(header); + } else { + value = "??"; + } + if (value != null) { + if (value instanceof String) { + buf.append((String) value); + } else { + buf.append(value.toString()); + } + } else { + buf.append('-'); + } + } + } + + /** + * write an attribute in the HttpSession - %{xxx}s + */ + private class SessionAttributeElement implements AccessLogElement { + private String header; + + public SessionAttributeElement(String header) { + this.header = header; + } + + public void addElement(StringBuffer buf, Date date, Request request, + Response response, long time) { + Object value = null; + if (null != request) { + HttpSession sess = request.getSession(false); + if (null != sess) + value = sess.getAttribute(header); + } else { + value = "??"; + } + if (value != null) { + if (value instanceof String) { + buf.append((String) value); + } else { + buf.append(value.toString()); + } + } else { + buf.append('-'); + } + } + } + + + + + /** + * parse pattern string and create the array of AccessLogElement + */ + private AccessLogElement[] createLogElements() { + List list = new ArrayList(); + boolean replace = false; + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < pattern.length(); i++) { + char ch = pattern.charAt(i); + if (replace) { + /* + * For code that processes {, the behavior will be ... if I do + * not enounter a closing } - then I ignore the { + */ + if ('{' == ch) { + StringBuffer name = new StringBuffer(); + int j = i + 1; + for (; j < pattern.length() && '}' != pattern.charAt(j); j++) { + name.append(pattern.charAt(j)); + } + if (j + 1 < pattern.length()) { + /* the +1 was to account for } which we increment now */ + j++; + list.add(createAccessLogElement(name.toString(), + pattern.charAt(j))); + i = j; /* Since we walked more than one character */ + } else { + // D'oh - end of string - pretend we never did this + // and do processing the "old way" + list.add(createAccessLogElement(ch)); + } + } else { + list.add(createAccessLogElement(ch)); + } + replace = false; + } else if (ch == '%') { + replace = true; + list.add(new StringElement(buf.toString())); + buf = new StringBuffer(); + } else { + buf.append(ch); + } + } + if (buf.length() > 0) { + list.add(new StringElement(buf.toString())); + } + return (AccessLogElement[]) list.toArray(new AccessLogElement[0]); + } + + /** + * create an AccessLogElement implementation which needs header string + */ + private AccessLogElement createAccessLogElement(String header, char pattern) { + switch (pattern) { + case 'i': + return new HeaderElement(header); + case 'c': + return new CookieElement(header); + case 'r': + return new RequestAttributeElement(header); + case 's': + return new SessionAttributeElement(header); + default: + return new StringElement("???"); + } + } + + /** + * create an AccessLogElement implementation + */ + private AccessLogElement createAccessLogElement(char pattern) { + switch (pattern) { + case 'a': + return new RemoteAddrElement(); + case 'A': + return new LocalAddrElement(); + case 'b': + return new ByteSentElement(true); + case 'B': + return new ByteSentElement(false); + case 'D': + return new ElapsedTimeElement(true); + case 'h': + return new HostElement(); + case 'H': + return new ProtocolElement(); + case 'l': + return new LogicalUserNameElement(); + case 'm': + return new MethodElement(); + case 'p': + return new LocalPortElement(); + case 'q': + return new QueryElement(); + case 'r': + return new RequestElement(); + case 's': + return new HttpStatusCodeElement(); + case 'S': + return new SessionIdElement(); + case 't': + return new DateAndTimeElement(); + case 'T': + return new ElapsedTimeElement(false); + case 'u': + return new UserElement(); + case 'U': + return new RequestURIElement(); + case 'v': + return new LocalServerNameElement(); + default: + return new StringElement("???" + pattern + "???"); + } } } diff --git a/java/org/apache/catalina/valves/FastAccessLogValve.java b/java/org/apache/catalina/valves/FastAccessLogValve.java deleted file mode 100644 index d5bba8da1..000000000 --- a/java/org/apache/catalina/valves/FastAccessLogValve.java +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -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.StringManager; - - -/** - *

Implementation of the Valve interface that generates a web server - * access log with the detailed line contents matching a configurable pattern. - * The syntax of the available patterns is similar to that supported by the - * Apache mod_log_config module. As an additional feature, - * automatic rollover of log files when the date changes is also supported.

- * - *

Patterns for the logged message may include constant text or any of the - * following replacement strings, for which the corresponding information - * from the specified Response is substituted:

- * - *

In addition, the caller can specify one of the following aliases for - * commonly utilized patterns:

- * - * - *

- * There is also support to write information from the cookie, incoming - * header, the Session or something else in the ServletRequest.
- * It is modeled after the apache syntax: - *

- *

- * - *

- * Conditional logging is also supported. This can be done with the - * condition property. - * If the value returned from ServletRequest.getAttribute(condition) - * yields a non-null value. The logging will be skipped. - *

- * - * @author Craig R. McClanahan - * @author Jason Brittain - * @author Takayuki Kaneko - * @version $Revision: 467222 $ $Date: 2007-01-04 12:17:11 +0900 - */ - -public class FastAccessLogValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default property values. - */ - public FastAccessLogValve() { - super(); - setPattern("common"); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * 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 directory in which log files are created. - */ - private String directory = "logs"; - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.valves.FastAccessLogValve/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The set of month abbreviations for log messages. - */ - protected static final String months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - - /** - * 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 string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = ""; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = 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 Dates into a day string in the format - * "dd". - */ - private SimpleDateFormat dayFormatter = null; - - - /** - * A date formatter to format a Date into a month string in the format - * "MM". - */ - private SimpleDateFormat monthFormatter = null; - - - /** - * A date formatter to format a Date into a year string in the format - * "yyyy". - */ - private SimpleDateFormat yearFormatter = 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; - - - /** - * The system timezone. - */ - private TimeZone timezone = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is not in operation. - */ - private String timeZoneNoDST = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is in operation. - */ - private String timeZoneDST = null; - - - /** - * The system time when we last updated the Date that this valve - * uses for log lines. - */ - private Date currentDate = null; - - private long currentMillis = 0; - - - /** - * Resolve hosts. - */ - private boolean resolveHosts = false; - - - /** - * Instant when the log daily rotation was last checked. - */ - private long rotationLastChecked = 0L; - - - /** - * Are we doing conditional logging. default false. - */ - private String condition = null; - - - /** - * Date format to place in log file name. Use at your own risk! - */ - private String fileDateFormat = null; - - /** - * Array of AccessLogElement, they will be used to make log message. - */ - private AccessLogElement[] logElements = 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 - */ - public void setPattern(String pattern) { - if (pattern == null) - pattern = ""; - if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) - pattern = Constants.AccessLog.COMMON_PATTERN; - if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) - pattern = Constants.AccessLog.COMBINED_PATTERN; - this.pattern = pattern; - logElements = createLogElements(); - } - - - /** - * 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; - } - - - /** - * Should we rotate the logs - */ - 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; - } - - - /** - * Set the resolve hosts flag. - * - * @param resolveHosts The new resolve hosts value - */ - public void setResolveHosts(boolean resolveHosts) { - this.resolveHosts = resolveHosts; - } - - - /** - * Get the value of the resolve hosts flag. - */ - public boolean isResolveHosts() { - return resolveHosts; - } - - - /** - * 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; - } - - /** - * 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; - } - - // --------------------------------------------------------- Public Methods - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - if (writer != null) { - writer.flush(); - } - } - - /** - * Log a message summarizing the specified request and response, according - * to the format specified by the pattern 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 t1 = System.currentTimeMillis(); - - getNext().invoke(request, response); - - long t2 = System.currentTimeMillis(); - long time = t2 - t1; - - if (condition != null - && null != request.getRequest().getAttribute(condition)) { - return; - } - - Date date = getDate(); - StringBuffer result = new StringBuffer(); - - for (int i = 0; i < logElements.length; i++) { - logElements[i].addElement(result, date, request, response, time); - } - - log(result.toString()); - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Close the currently open log file (if any) - */ - private synchronized void close() { - if (writer == null) { - return; - } - writer.flush(); - writer.close(); - writer = null; - dateStamp = ""; - } - - - /** - * 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 - */ - public void log(String message) { - 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 = dateFormatter.format(currentDate); - - // If the date has changed, switch log files - if (!dateStamp.equals(tsDate)) { - synchronized (this) { - if (!dateStamp.equals(tsDate)) { - close(); - dateStamp = tsDate; - open(); - } - } - } - } - } - - // Log this message - if (writer != null) { - writer.println(message); - } - - } - - - /** - * Return the month abbreviation for the specified month, which must - * be a two-digit String. - * - * @param month Month number ("01" .. "12"). - */ - private String lookup(String month) { - int index; - try { - index = Integer.parseInt(month) - 1; - } catch (Throwable t) { - index = 0; // Can not happen, in theory - } - return (months[index]); - } - - - /** - * Open the new log file for the date specified by dateStamp. - */ - 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; - } else { - pathname = dir.getAbsolutePath() + File.separator + prefix - + suffix; - } - writer = new PrintWriter(new BufferedWriter(new FileWriter( - pathname, true), 128000), false); - } catch (IOException e) { - writer = 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. - * - * @return Date - */ - private Date getDate() { - // Only create a new Date once per second, max. - long systime = System.currentTimeMillis(); - if ((systime - currentMillis) > 1000) { - synchronized (this) { - if ((systime - currentMillis) > 1000) { - currentDate = new Date(systime); - currentMillis = systime; - } - } - } - return currentDate; - } - - - private String getTimeZone(Date date) { - if (timezone.inDaylightTime(date)) { - return timeZoneDST; - } else { - return timeZoneNoDST; - } - } - - - private String calculateTimeZoneOffset(long offset) { - StringBuffer tz = new StringBuffer(); - if ((offset < 0)) { - tz.append("-"); - offset = -offset; - } else { - tz.append("+"); - } - - long hourOffset = offset / (1000 * 60 * 60); - long minuteOffset = (offset / (1000 * 60)) % 60; - - if (hourOffset < 10) - tz.append("0"); - tz.append(hourOffset); - - if (minuteOffset < 10) - tz.append("0"); - tz.append(minuteOffset); - - return tz.toString(); - } - - - // ------------------------------------------------------ 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 configure(), - * 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("accessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Initialize the timeZone, Date formatters, and currentDate - timezone = TimeZone.getDefault(); - timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); - Calendar calendar = Calendar.getInstance(timezone); - int offset = calendar.get(Calendar.DST_OFFSET); - timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset() + offset); - - if (fileDateFormat == null || fileDateFormat.length() == 0) - fileDateFormat = "yyyy-MM-dd"; - dateFormatter = new SimpleDateFormat(fileDateFormat); - dateFormatter.setTimeZone(timezone); - dayFormatter = new SimpleDateFormat("dd"); - dayFormatter.setTimeZone(timezone); - monthFormatter = new SimpleDateFormat("MM"); - monthFormatter.setTimeZone(timezone); - yearFormatter = new SimpleDateFormat("yyyy"); - yearFormatter.setTimeZone(timezone); - timeFormatter = new SimpleDateFormat("HH:mm:ss"); - timeFormatter.setTimeZone(timezone); - currentDate = new Date(); - dateStamp = dateFormatter.format(currentDate); - open(); - } - - - /** - * 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("accessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - close(); - } - - /** - * AccessLogElement writes the partial message into the buffer. - */ - private interface AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time); - - } - - /** - * write local IP address - %A - */ - private class LocalAddrElement implements AccessLogElement { - 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"; - } - buf.append(value); - } - } - - /** - * write remote IP address - %a - */ - private class RemoteAddrElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getRemoteAddr()); - } - } - - /** - * write remote host name - %h - */ - private class HostElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getRemoteHost()); - } - } - - /** - * write remote logical username from identd (always returns '-') - %l - */ - private class LogicalUserNameElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append('-'); - } - } - - /** - * write request protocol - %H - */ - private class ProtocolElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getProtocol()); - } - } - - /** - * write remote user that was authenticated (if any), else '-' - %u - */ - private class UserElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (request != null) { - String value = request.getRemoteUser(); - if (value != null) { - buf.append(value); - } else { - buf.append('-'); - } - } else { - buf.append('-'); - } - } - } - - /** - * write date and time, in Common Log Format - %t - */ - private class DateAndTimeElement implements AccessLogElement { - private Date currentDate = new Date(0); - - private String currentDateString = null; - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (currentDate != date) { - synchronized (this) { - if (currentDate != date) { - StringBuffer current = new StringBuffer(32); - current.append('['); - current.append(dayFormatter.format(date)); // Day - current.append('/'); - current.append(lookup(monthFormatter.format(date))); // Month - current.append('/'); - current.append(yearFormatter.format(date)); // Year - current.append(':'); - current.append(timeFormatter.format(date)); // Time - current.append(' '); - current.append(getTimeZone(date)); // Timezone - current.append(']'); - currentDateString = current.toString(); - currentDate = date; - } - } - } - buf.append(currentDateString); - } - } - - /** - * write first line of the request (method and request URI) - %r - */ - private class RequestElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (request != null) { - buf.append(request.getMethod()); - buf.append(' '); - buf.append(request.getRequestURI()); - if (request.getQueryString() != null) { - buf.append('?'); - buf.append(request.getQueryString()); - } - buf.append(' '); - buf.append(request.getProtocol()); - } else { - buf.append("- - "); - buf.append(request.getProtocol()); - } - } - } - - /** - * write HTTP status code of the response - %s - */ - private class HttpStatusCodeElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (response != null) { - buf.append(response.getStatus()); - } else { - buf.append('-'); - } - } - } - - /** - * write local port on which this request was received - %p - */ - private class LocalPortElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getServerPort()); - } - } - - /** - * write bytes sent, excluding HTTP headers - %b, %B - */ - private class ByteSentElement implements AccessLogElement { - private boolean conversion; - - /** - * if conversion is true, write '-' instead of 0 - %b - */ - public ByteSentElement(boolean conversion) { - this.conversion = conversion; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - int length = response.getContentCount(); - if (length <= 0 && conversion) { - buf.append('-'); - } else { - buf.append(length); - } - } - } - - /** - * write request method (GET, POST, etc.) - %m - */ - private class MethodElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (request != null) { - buf.append(request.getMethod()); - } - } - } - - /** - * write time taken to process the request - %D, %T - */ - private class ElapsedTimeElement implements AccessLogElement { - private boolean millis; - - /** - * if millis is true, write time in millis - %D - * if millis is false, write time in seconds - %T - */ - public ElapsedTimeElement(boolean millis) { - this.millis = millis; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (millis) { - buf.append(time); - } else { - // second - buf.append(time / 1000); - buf.append('.'); - int remains = (int) (time % 1000); - buf.append(remains / 100); - remains = remains % 100; - buf.append(remains / 10); - buf.append(remains % 10); - } - } - } - - /** - * write Query string (prepended with a '?' if it exists) - %q - */ - private class QueryElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - String query = null; - if (request != null) - query = request.getQueryString(); - if (query != null) { - buf.append('?'); - buf.append(query); - } - } - } - - /** - * write user session ID - %S - */ - private class SessionIdElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (request != null) { - if (request.getSession(false) != null) { - buf.append(request.getSessionInternal(false) - .getIdInternal()); - } else { - buf.append('-'); - } - } else { - buf.append('-'); - } - } - } - - /** - * write requested URL path - %U - */ - private class RequestURIElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - if (request != null) { - buf.append(request.getRequestURI()); - } else { - buf.append('-'); - } - } - } - - /** - * write local server name - %v - */ - private class LocalServerNameElement implements AccessLogElement { - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getServerName()); - } - } - - /** - * write any string - */ - private class StringElement implements AccessLogElement { - private String str; - - public StringElement(String str) { - this.str = str; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(str); - } - } - - /** - * write incoming headers - %{xxx}i - */ - private class HeaderElement implements AccessLogElement { - private String header; - - public HeaderElement(String header) { - this.header = header; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - buf.append(request.getHeader(header)); - } - } - - /** - * write a specific cookie - %{xxx}c - */ - private class CookieElement implements AccessLogElement { - private String header; - - public CookieElement(String header) { - this.header = header; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - String value = "-"; - Cookie[] c = request.getCookies(); - if (c != null) { - for (int i = 0; i < c.length; i++) { - if (header.equals(c[i].getName())) { - value = c[i].getValue(); - break; - } - } - } - buf.append(value); - } - } - - /** - * write an attribute in the ServletRequest - %{xxx}r - */ - private class RequestAttributeElement implements AccessLogElement { - private String header; - - public RequestAttributeElement(String header) { - this.header = header; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - Object value = null; - if (request != null) { - value = request.getAttribute(header); - } else { - value = "??"; - } - if (value != null) { - if (value instanceof String) { - buf.append((String) value); - } else { - buf.append(value.toString()); - } - } else { - buf.append('-'); - } - } - } - - /** - * write an attribute in the HttpSession - %{xxx}s - */ - private class SessionAttributeElement implements AccessLogElement { - private String header; - - public SessionAttributeElement(String header) { - this.header = header; - } - - public void addElement(StringBuffer buf, Date date, Request request, - Response response, long time) { - Object value = null; - if (null != request) { - HttpSession sess = request.getSession(false); - if (null != sess) - value = sess.getAttribute(header); - } else { - value = "??"; - } - if (value != null) { - if (value instanceof String) { - buf.append((String) value); - } else { - buf.append(value.toString()); - } - } else { - buf.append('-'); - } - } - } - - - - - /** - * parse pattern string and create the array of AccessLogElement - */ - private AccessLogElement[] createLogElements() { - List list = new ArrayList(); - boolean replace = false; - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (replace) { - /* - * For code that processes {, the behavior will be ... if I do - * not enounter a closing } - then I ignore the { - */ - if ('{' == ch) { - StringBuffer name = new StringBuffer(); - int j = i + 1; - for (; j < pattern.length() && '}' != pattern.charAt(j); j++) { - name.append(pattern.charAt(j)); - } - if (j + 1 < pattern.length()) { - /* the +1 was to account for } which we increment now */ - j++; - list.add(createAccessLogElement(name.toString(), - pattern.charAt(j))); - i = j; /* Since we walked more than one character */ - } else { - // D'oh - end of string - pretend we never did this - // and do processing the "old way" - list.add(createAccessLogElement(ch)); - } - } else { - list.add(createAccessLogElement(ch)); - } - replace = false; - } else if (ch == '%') { - replace = true; - list.add(new StringElement(buf.toString())); - buf = new StringBuffer(); - } else { - buf.append(ch); - } - } - if (buf.length() > 0) { - list.add(new StringElement(buf.toString())); - } - return (AccessLogElement[]) list.toArray(new AccessLogElement[0]); - } - - /** - * create an AccessLogElement implementation which needs header string - */ - private AccessLogElement createAccessLogElement(String header, char pattern) { - switch (pattern) { - case 'i': - return new HeaderElement(header); - case 'c': - return new CookieElement(header); - case 'r': - return new RequestAttributeElement(header); - case 's': - return new SessionAttributeElement(header); - default: - return new StringElement("???"); - } - } - - /** - * create an AccessLogElement implementation - */ - private AccessLogElement createAccessLogElement(char pattern) { - switch (pattern) { - case 'a': - return new RemoteAddrElement(); - case 'A': - return new LocalAddrElement(); - case 'b': - return new ByteSentElement(true); - case 'B': - return new ByteSentElement(false); - case 'D': - return new ElapsedTimeElement(true); - case 'h': - return new HostElement(); - case 'H': - return new ProtocolElement(); - case 'l': - return new LogicalUserNameElement(); - case 'm': - return new MethodElement(); - case 'p': - return new LocalPortElement(); - case 'q': - return new QueryElement(); - case 'r': - return new RequestElement(); - case 's': - return new HttpStatusCodeElement(); - case 'S': - return new SessionIdElement(); - case 't': - return new DateAndTimeElement(); - case 'T': - return new ElapsedTimeElement(false); - case 'u': - return new UserElement(); - case 'U': - return new RequestURIElement(); - case 'v': - return new LocalServerNameElement(); - default: - return new StringElement("???" + pattern + "???"); - } - } -} diff --git a/java/org/apache/catalina/valves/FastCommonAccessLogValve.java b/java/org/apache/catalina/valves/FastCommonAccessLogValve.java index 38c6ab317..7636fa0d7 100644 --- a/java/org/apache/catalina/valves/FastCommonAccessLogValve.java +++ b/java/org/apache/catalina/valves/FastCommonAccessLogValve.java @@ -19,838 +19,9 @@ package org.apache.catalina.valves; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -import javax.servlet.ServletException; - -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.StringManager; - - /** - *

Implementation of the Valve interface that generates a web server - * access log with the detailed line contents matching either the common or - * combined patterns. As an additional feature, automatic rollover of log files - * when the date changes is also supported.

- *

- * Conditional logging is also supported. This can be done with the - * condition property. - * If the value returned from ServletRequest.getAttribute(condition) - * yields a non-null value. The logging will be skipped. - *

- * - * @author Craig R. McClanahan - * @author Jason Brittain - * @author Remy Maucherat - * @version $Revision$ $Date$ + * @deprecated */ -public final class FastCommonAccessLogValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default property values. - */ - public FastCommonAccessLogValve() { - - super(); - setPattern("common"); - - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * 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 directory in which log files are created. - */ - private String directory = "logs"; - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.valves.FastCommonAccessLogValve/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The set of month abbreviations for log messages. - */ - protected static final String months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - - /** - * If the current log pattern is the same as the common access log - * format pattern, then we'll set this variable to true and log in - * a more optimal and hard-coded way. - */ - private boolean common = false; - - - /** - * For the combined format (common, plus useragent and referer), we do - * the same - */ - private boolean combined = false; - - - /** - * 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 string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = ""; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = 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 Dates into a day string in the format - * "dd". - */ - private SimpleDateFormat dayFormatter = null; - - - /** - * A date formatter to format a Date into a month string in the format - * "MM". - */ - private SimpleDateFormat monthFormatter = null; - - - /** - * A date formatter to format a Date into a year string in the format - * "yyyy". - */ - private SimpleDateFormat yearFormatter = 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; - - - /** - * The system timezone. - */ - private TimeZone timezone = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is not in operation. - */ - private String timeZoneNoDST = null; - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is in operation. - */ - private String timeZoneDST = null; - - - /** - * The system time when we last updated the Date that this valve - * uses for log lines. - */ - private String currentDateString = null; - - - /** - * The instant where the date string was last updated. - */ - private long currentDate = 0L; - - - /** - * When formatting log lines, we often use strings like this one (" "). - */ - private String space = " "; - - - /** - * Resolve hosts. - */ - private boolean resolveHosts = false; - - - /** - * Instant when the log daily rotation was last checked. - */ - private long rotationLastChecked = 0L; - - - /** - * Are we doing conditional logging. default false. - */ - private String condition = null; - - - /** - * 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 - */ - public void setPattern(String pattern) { - - if (pattern == null) - pattern = ""; - if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) - pattern = Constants.AccessLog.COMMON_PATTERN; - if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) - pattern = Constants.AccessLog.COMBINED_PATTERN; - this.pattern = pattern; - - if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) - combined = true; - else - combined = false; - - } - - - /** - * 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; - - } - - - /** - * Should we rotate the logs - */ - 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; - - } - - - /** - * Set the resolve hosts flag. - * - * @param resolveHosts The new resolve hosts value - */ - public void setResolveHosts(boolean resolveHosts) { - - this.resolveHosts = resolveHosts; - - } - - - /** - * Get the value of the resolve hosts flag. - */ - public boolean isResolveHosts() { - - return resolveHosts; - - } - - - /** - * 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; - - } - - /** - * 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; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - if (writer != null) - writer.flush(); - } - - - /** - * Log a message summarizing the specified request and response, according - * to the format specified by the pattern 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 - getNext().invoke(request, response); - - if (condition!=null && - null!=request.getRequest().getAttribute(condition)) { - return; - } - - StringBuffer result = new StringBuffer(); - - // Check to see if we should log using the "common" access log pattern - String value = null; - - if (isResolveHosts()) - result.append(request.getRemoteHost()); - else - result.append(request.getRemoteAddr()); - - result.append(" - "); - - value = request.getRemoteUser(); - if (value == null) - result.append("- "); - else { - result.append(value); - result.append(space); - } - - result.append(getCurrentDateString()); - - result.append(request.getMethod()); - result.append(space); - result.append(request.getRequestURI()); - if (request.getQueryString() != null) { - result.append('?'); - result.append(request.getQueryString()); - } - result.append(space); - result.append(request.getProtocol()); - result.append("\" "); - - result.append(response.getStatus()); - - result.append(space); - - int length = response.getContentCount(); - - if (length <= 0) - value = "-"; - else - value = "" + length; - result.append(value); - - if (combined) { - result.append(space); - result.append("\""); - String referer = request.getHeader("referer"); - if(referer != null) - result.append(referer); - else - result.append("-"); - result.append("\""); - - result.append(space); - result.append("\""); - String ua = request.getHeader("user-agent"); - if(ua != null) - result.append(ua); - else - result.append("-"); - result.append("\""); - } - - log(result.toString()); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Close the currently open log file (if any) - */ - private synchronized void close() { - - if (writer == null) - return; - writer.flush(); - writer.close(); - writer = null; - dateStamp = ""; - - } - - - /** - * 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 - */ - public void log(String message) { - - // Log this message - if (writer != null) { - writer.println(message); - } - - } - - - /** - * Return the month abbreviation for the specified month, which must - * be a two-digit String. - * - * @param month Month number ("01" .. "12"). - */ - private String lookup(String month) { - - int index; - try { - index = Integer.parseInt(month) - 1; - } catch (Throwable t) { - index = 0; // Can not happen, in theory - } - return (months[index]); - - } - - - /** - * Open the new log file for the date specified by dateStamp. - */ - 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; - } else { - pathname = dir.getAbsolutePath() + File.separator + - prefix + suffix; - } - writer = new PrintWriter(new BufferedWriter - (new FileWriter(pathname, true), 128000), false); - } catch (IOException e) { - writer = 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. - * - * @return Date - */ - private String getCurrentDateString() { - // Only create a new Date once per second, max. - long systime = System.currentTimeMillis(); - if ((systime - currentDate) > 1000) { - synchronized (this) { - // We don't care about being exact here: if an entry does get - // logged as having happened during the previous second - // it will not make any difference - if ((systime - currentDate) > 1000) { - - // Format the new date - Date date = new Date(); - StringBuffer result = new StringBuffer(32); - result.append("["); - // Day - result.append(dayFormatter.format(date)); - result.append('/'); - // Month - result.append(lookup(monthFormatter.format(date))); - result.append('/'); - // Year - result.append(yearFormatter.format(date)); - result.append(':'); - // Time - result.append(timeFormatter.format(date)); - result.append(space); - // Time zone - result.append(getTimeZone(date)); - result.append("] \""); - - // Check for log rotation - if (rotatable) { - // Check for a change of date - String tsDate = dateFormatter.format(date); - // If the date has changed, switch log files - if (!dateStamp.equals(tsDate)) { - synchronized (this) { - if (!dateStamp.equals(tsDate)) { - close(); - dateStamp = tsDate; - open(); - } - } - } - } - - currentDateString = result.toString(); - currentDate = date.getTime(); - } - } - } - return currentDateString; - } - - - private String getTimeZone(Date date) { - if (timezone.inDaylightTime(date)) { - return timeZoneDST; - } else { - return timeZoneNoDST; - } - } - - - private String calculateTimeZoneOffset(long offset) { - StringBuffer tz = new StringBuffer(); - if ((offset<0)) { - tz.append("-"); - offset = -offset; - } else { - tz.append("+"); - } - - long hourOffset = offset/(1000*60*60); - long minuteOffset = (offset/(1000*60)) % 60; - - if (hourOffset<10) - tz.append("0"); - tz.append(hourOffset); - - if (minuteOffset<10) - tz.append("0"); - tz.append(minuteOffset); - - return tz.toString(); - } - - - // ------------------------------------------------------ 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 configure(), - * 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("accessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Initialize the timeZone, Date formatters, and currentDate - timezone = TimeZone.getDefault(); - timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); - Calendar calendar = Calendar.getInstance(timezone); - int offset = calendar.get(Calendar.DST_OFFSET); - timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); - - if (fileDateFormat==null || fileDateFormat.length()==0) - fileDateFormat = "yyyy-MM-dd"; - dateFormatter = new SimpleDateFormat(fileDateFormat); - dateFormatter.setTimeZone(timezone); - dayFormatter = new SimpleDateFormat("dd"); - dayFormatter.setTimeZone(timezone); - monthFormatter = new SimpleDateFormat("MM"); - monthFormatter.setTimeZone(timezone); - yearFormatter = new SimpleDateFormat("yyyy"); - yearFormatter.setTimeZone(timezone); - timeFormatter = new SimpleDateFormat("HH:mm:ss"); - timeFormatter.setTimeZone(timezone); - currentDateString = getCurrentDateString(); - dateStamp = dateFormatter.format(new Date()); - - open(); - - } - - - /** - * 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("accessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - close(); - - } -} +public final class FastCommonAccessLogValve extends AccessLogValve { +} \ No newline at end of file