FileDocCategorySizeDatePackage
ExtendedAccessLogValve.javaAPI DocApache Tomcat 6.0.1431029Fri Jul 20 04:20:34 BST 2007org.apache.catalina.valves

ExtendedAccessLogValve

public class ExtendedAccessLogValve extends AccessLogValve implements org.apache.catalina.Lifecycle
An implementation of the W3c Extended Log File Format. See http://www.w3.org/TR/WD-logfile.html for more information about the format. The following fields are supported:
  • c-dns: Client hostname
  • c-ip: Client ip address
  • bytes: bytes served
  • cs-method: request method
  • cs-uri: The full uri requested
  • cs-uri-query: The query string
  • cs-uri-stem: The uri without query string
  • date: The date in yyyy-mm-dd format for GMT
  • s-dns: The server dns entry
  • s-ip: The server ip address
  • cs(XXX): The value of header XXX from client to server
  • sc(XXX): The value of header XXX from server to client
  • sc-status: The status code
  • time: Time the request was served
  • time-taken: Time (in seconds) taken to serve the request
  • x-A(XXX): Pull XXX attribute from the servlet context
  • x-C(XXX): Pull the first cookie of the name XXX
  • x-R(XXX): Pull XXX attribute from the servlet request
  • x-S(XXX): Pull XXX attribute from the session
  • x-P(...): Call request.getParameter(...) and URLencode it. Helpful to capture certain POST parameters.
  • For any of the x-H(...) the following method will be called from the HttpServletRequestObject
  • x-H(authType): getAuthType
  • x-H(characterEncoding): getCharacterEncoding
  • x-H(contentLength): getContentLength
  • x-H(locale): getLocale
  • x-H(protocol): getProtocol
  • x-H(remoteUser): getRemoteUser
  • x-H(requestedSessionId): getGequestedSessionId
  • x-H(requestedSessionIdFromCookie): isRequestedSessionIdFromCookie
  • x-H(requestedSessionIdValid): isRequestedSessionIdValid
  • x-H(scheme): getScheme
  • x-H(secure): isSecure

Log rotation can be on or off. This is dictated by the rotatable property.

For UvNIX users, another field called checkExistsis 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.

For JMX junkies, a public method called rotate has been made available to allow you to tell this instance to move the existing log file to somewhere else start writing a new log file.

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.

For extended attributes coming from a getAttribute() call, it is you responsibility to ensure there are no newline or control characters.

author
Tim Funk
version
$Revision: 522854 $ $Date: 2007-03-27 12:10:45 +0200 (mar., 27 mars 2007) $

Fields Summary
private static org.apache.juli.logging.Log
log
protected static final String
extendedAccessLogInfo
The descriptive information about this implementation.
Constructors Summary
Methods Summary
protected AccessLogElement[]createLogElements()

        if (log.isDebugEnabled()) {
            log.debug("decodePattern, pattern =" + pattern);
        }
        List<AccessLogElement> list = new ArrayList<AccessLogElement>();

        PatternTokenizer tokenizer = new PatternTokenizer(pattern);
        try {

            // Ignore leading whitespace.
            tokenizer.getWhiteSpaces();

            if (tokenizer.isEnded()) {
                log.info("pattern was just empty or whitespace");
                return null;
            }

            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;
        }
    
protected AccessLogElementgetClientToServerElement(org.apache.catalina.valves.ExtendedAccessLogValve$PatternTokenizer tokenizer)

        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 {
                    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 if (tokenizer.hasParameter()) {
            String parameter = tokenizer.getParameter();
            if (parameter == null) {
                log.error("No closing ) found for in decode");
                return null;
            }
            return new RequestHeaderElement(parameter);
        }
        log.error("The next characters couldn't be decoded: "
                + tokenizer.getRemains());
        return null;
    
public java.lang.StringgetInfo()
Return descriptive information about this implementation.



    // ------------------------------------------------------------- Properties


               
       
        return (extendedAccessLogInfo);
    
protected AccessLogElementgetLogElement(java.lang.String token, org.apache.catalina.valves.ExtendedAccessLogValve$PatternTokenizer tokenizer)

        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 {
                return new TimeElement();
            }
        } 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 AccessLogElementgetProxyElement(org.apache.catalina.valves.ExtendedAccessLogValve$PatternTokenizer tokenizer)

        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 AccessLogElementgetServerToClientElement(org.apache.catalina.valves.ExtendedAccessLogValve$PatternTokenizer tokenizer)

        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 null;
            }
            return new ResponseHeaderElement(parameter);
        }
        log.error("The next characters couldn't be decoded: "
                + tokenizer.getRemains());
        return null;
    
protected AccessLogElementgetServletRequestElement(java.lang.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;
    
protected AccessLogElementgetXParameterElement(org.apache.catalina.valves.ExtendedAccessLogValve$PatternTokenizer tokenizer)

        if (!tokenizer.hasSubToken()) {
            log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
            return null;
        }
        String token = tokenizer.getToken();
        if (!tokenizer.hasParameter()) {
            log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
            return null;
        }
        String parameter = tokenizer.getParameter();
        if (parameter == null) {
            log.error("No closing ) found for in decode");
            return null;
        }
        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 synchronized voidopen()
Open the new log file for the date specified by dateStamp.

        super.open();
        if (currentLogFile.length()==0) {
            writer.println("#Fields: " + pattern);
            writer.println("#Version: 1.0");
            writer.println("#Software: " + ServerInfo.getServerInfo());
        }
    
private java.lang.Stringwrap(java.lang.Object value)
Wrap the incoming value into quotes and escape any inner quotes with double quotes.

param
value - The value to wrap quotes around
return
'-' if empty of null. Otherwise, toString() will be called on the object and the value will be wrapped in quotes and any quotes will be escaped with 2 sets of quotes.

        String svalue;
        // Does the value contain a " ? If so must encode it
        if (value == null || "-".equals(value))
            return "-";

        try {
            svalue = value.toString();
            if ("".equals(svalue))
                return "-";
        } 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) {
                buffer.append(svalue.substring(i));
                i = svalue.length();
            } else {
                buffer.append(svalue.substring(i, j + 1));
                buffer.append('"");
                i = j + 2;
            }
        }

        buffer.append('\'");
        return buffer.toString();