/* * 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.IOException; import java.io.StringReader; import java.net.InetAddress; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import org.apache.catalina.Lifecycle; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.ServerInfo; import org.jboss.logging.Logger; import org.jboss.logging.Logger; /** * 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 hostnamec-ip
: Client ip addressbytes
: bytes servedcs-method
: request methodcs-uri
: The full uri requestedcs-uri-query
: The query stringcs-uri-stem
: The uri without query stringdate
: The date in yyyy-mm-dd format for GMTs-dns
: The server dns entry s-ip
: The server ip addresscs(XXX)
: The value of header XXX from client to serversc(XXX)
: The value of header XXX from server to client sc-status
: The status codetime
: Time the request was servedtime-taken
: Time (in seconds) taken to serve the requestx-A(XXX)
: Pull XXX attribute from the servlet context x-C(XXX)
: Pull the first cookie of the name XXX x-O(XXX)
: Pull the all response header values 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.
* x-H(authType)
: getAuthType x-H(characterEncoding)
: getCharacterEncoding x-H(contentLength)
: getContentLength x-H(locale)
: getLocalex-H(protocol)
: getProtocol x-H(remoteUser)
: getRemoteUserx-H(requestedSessionId)
: getGequestedSessionIdx-H(requestedSessionIdFromCookie)
:
* isRequestedSessionIdFromCookie x-H(requestedSessionIdValid)
:
* isRequestedSessionIdValidx-H(scheme)
: getSchemex-H(secure)
: isSecure* Log rotation can be on or off. This is dictated by the rotatable * property. *
* *
* For UvNIX users, another field called checkExists
is also
* available. If set to true, the log file's existence will be checked before
* each logging. This way an external log rotator can move the file
* somewhere and tomcat will start with a new file.
*
* 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 * @author Peter Rossbach * * @version $Revision: 1.1 $ $Date: 2012/08/17 14:41:45 $ */ public class ExtendedAccessLogValve extends AccessLogValve implements Lifecycle { private static Logger log = Logger.getLogger(ExtendedAccessLogValve.class); // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String extendedAccessLogInfo = "org.apache.catalina.valves.ExtendedAccessLogValve/2.1"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this implementation. */ public String getInfo() { return (extendedAccessLogInfo); } // --------------------------------------------------------- Public Methods // -------------------------------------------------------- Private Methods /** * 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. */ private String wrap(Object value) { 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(); } /** * Open the new log file for the date specified bydateStamp
.
*/
protected synchronized void open() {
super.open();
if (currentLogFile.length()==0) {
writer.println("#Fields: " + pattern);
writer.println("#Version: 2.0");
writer.println("#Software: " + ServerInfo.getServerInfo());
}
}
// ------------------------------------------------------ Lifecycle Methods
protected class DateElement implements AccessLogElement {
private Date currentDate = new Date(0);
private String currentDateString = null;
/**
* A date formatter to format a Date into a date in the format
* "yyyy-MM-dd".
*/
private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
public DateElement() {
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (currentDate != date) {
synchronized (this) {
if (currentDate != date) {
currentDateString = dateFormatter.format(date);
currentDate = date;
}
}
}
buf.append(currentDateString);
}
}
protected class TimeElement implements AccessLogElement {
private Date currentDate = new Date(0);
private String currentTimeString = null;
/**
* A date formatter to format a Date into a time in the format
* "kk:mm:ss" (kk is a 24-hour representation of the hour).
*/
private SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
public TimeElement() {
timeFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (currentDate != date) {
synchronized (this) {
if (currentDate != date) {
currentTimeString = timeFormatter.format(date);
currentDate = date;
}
}
}
buf.append(currentTimeString);
}
}
protected class RequestHeaderElement implements AccessLogElement {
private String header;
public RequestHeaderElement(String header) {
this.header = header;
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(wrap(request.getHeader(header)));
}
}
protected class ResponseHeaderElement implements AccessLogElement {
private String header;
public ResponseHeaderElement(String header) {
this.header = header;
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(wrap(response.getHeader(header)));
}
}
protected class ServletContextElement implements AccessLogElement {
private String attribute;
public ServletContextElement(String attribute) {
this.attribute = attribute;
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
buf.append(wrap(request.getContext().getServletContext()
.getAttribute(attribute)));
}
}
protected class CookieElement implements AccessLogElement {
private String name;
public CookieElement(String name) {
this.name = name;
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
Cookie[] c = request.getCookies();
for (int i = 0; c != null && i < c.length; i++) {
if (name.equals(c[i].getName())) {
buf.append(wrap(c[i].getValue()));
}
}
}
}
/**
* write a specific response header - x-O(xxx)
*/
protected class ResponseAllHeaderElement implements AccessLogElement {
private String header;
public ResponseAllHeaderElement(String header) {
this.header = header;
}
public void addElement(StringBuffer buf, Date date, Request request,
Response response, long time) {
if (null != response) {
String[] values = response.getHeaderValues(header);
if(values.length > 0) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < values.length; i++) {
String string = values[i];
buffer.append(string) ;
if(i+1