Author: markt
Date: Tue Aug 18 11:49:26 2009
New Revision: 805375
URL: http://svn.apache.org/viewvc?rev=805375&view=rev
Log:
Replace the RequestDumperValve with a RequestDumperFilter. Merge the
RequestDumperFilter from the examples with this new filter.
Adds:
- thread name to start of output line to make analysing output easier
- request timings
GSOC 2009
Based on a patch by Xie Xiaodong
Added:
tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java
(with props)
Removed:
tomcat/trunk/java/org/apache/catalina/valves/RequestDumperValve.java
tomcat/trunk/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.java
Modified:
tomcat/trunk/conf/server.xml
tomcat/trunk/java/org/apache/catalina/mbeans/MBeanFactory.java
tomcat/trunk/webapps/docs/config/filter.xml
tomcat/trunk/webapps/docs/config/valve.xml
tomcat/trunk/webapps/examples/WEB-INF/web.xml
Modified: tomcat/trunk/conf/server.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/conf/server.xml?rev=805375&r1=805374&r2=805375&view=diff
==============================================================================
--- tomcat/trunk/conf/server.xml (original)
+++ tomcat/trunk/conf/server.xml Tue Aug 18 11:49:26 2009
@@ -106,13 +106,6 @@
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
- <!-- The request dumper valve dumps useful debugging information about
- the request and response data received and sent by Tomcat.
- Documentation at: /docs/config/valve.html -->
- <!--
- <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
- -->
-
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
Added: tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java?rev=805375&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java
(added)
+++ tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java Tue
Aug 18 11:49:26 2009
@@ -0,0 +1,283 @@
+/*
+ * 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.filters;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+
+/**
+ * <p>Implementation of a Filter that logs interesting contents from the
+ * specified Request (before processing) and the corresponding Response
+ * (after processing). It is especially useful in debugging problems
+ * related to headers and cookies.</p>
+ *
+ * <p>When using this Filter, it is strongly recommended that the
+ * <code>org.apache.catalina.filter.RequestDumperFilter</code> logger is
+ * directed to a dedicated file and that the
+ * <code>org.apache.juli.VerbatimFormmater</code> is used.</p>
+ *
+ * @author Craig R. McClanahan
+ */
+
+public class RequestDumperFilter implements Filter {
+
+ private static final String NON_HTTP_REQ_MSG =
+ "Not available. Non-http request.";
+ private static final String NON_HTTP_RES_MSG =
+ "Not available. Non-http response.";
+
+ private static final ThreadLocal<Timestamp> timestamp =
+ new ThreadLocal<Timestamp>() {
+ protected Timestamp initialValue() {
+ return new Timestamp();
+ }
+ };
+
+ /**
+ * The logger for this class.
+ */
+ private static Log log = LogFactory.getLog(RequestDumperFilter.class);
+
+
+ /**
+ * Log the interesting request parameters, invoke the next Filter in the
+ * sequence, and log the interesting response parameters.
+ *
+ * @param request The servlet request to be processed
+ * @param response The servlet response to be created
+ * @param chain The filter chain being processed
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet error occurs
+ */
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest hRequest = null;
+ HttpServletResponse hResponse = null;
+
+ if (request instanceof HttpServletRequest) {
+ hRequest = (HttpServletRequest) request;
+ }
+ if (response instanceof HttpServletResponse) {
+ hResponse = (HttpServletResponse) response;
+ }
+
+ // Log pre-service information
+ doLog("START TIME ", getTimestamp());
+
+ if (hRequest == null) {
+ doLog(" requestURI", NON_HTTP_REQ_MSG);
+ doLog(" authType", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" requestURI", hRequest.getRequestURI());
+ doLog(" authType", hRequest.getAuthType());
+ }
+
+ doLog(" characterEncoding", request.getCharacterEncoding());
+ doLog(" contentLength",
+ Integer.valueOf(request.getContentLength()).toString());
+ doLog(" contentType", request.getContentType());
+
+ if (hRequest == null) {
+ doLog(" contextPath", NON_HTTP_REQ_MSG);
+ doLog(" cookie", NON_HTTP_REQ_MSG);
+ doLog(" header", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" contextPath", hRequest.getContextPath());
+ Cookie cookies[] = hRequest.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++)
+ doLog(" cookie", cookies[i].getName() +
+ "=" + cookies[i].getValue());
+ }
+ Enumeration<String> hnames = hRequest.getHeaderNames();
+ while (hnames.hasMoreElements()) {
+ String hname = hnames.nextElement();
+ Enumeration<String> hvalues = hRequest.getHeaders(hname);
+ while (hvalues.hasMoreElements()) {
+ String hvalue = hvalues.nextElement();
+ doLog(" header", hname + "=" + hvalue);
+ }
+ }
+ }
+
+ doLog(" locale", request.getLocale().toString());
+
+ if (hRequest == null) {
+ doLog(" method", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" method", hRequest.getMethod());
+ }
+
+ Enumeration<String> pnames = request.getParameterNames();
+ while (pnames.hasMoreElements()) {
+ String pname = pnames.nextElement();
+ String pvalues[] = request.getParameterValues(pname);
+ StringBuffer result = new StringBuffer(pname);
+ result.append('=');
+ for (int i = 0; i < pvalues.length; i++) {
+ if (i > 0)
+ result.append(", ");
+ result.append(pvalues[i]);
+ }
+ doLog(" parameter", result.toString());
+ }
+
+ if (hRequest == null) {
+ doLog(" pathInfo", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" pathInfo", hRequest.getPathInfo());
+ }
+
+ doLog(" protocol", request.getProtocol());
+
+ if (hRequest == null) {
+ doLog(" queryString", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" queryString", hRequest.getQueryString());
+ }
+
+ doLog(" remoteAddr", request.getRemoteAddr());
+ doLog(" remoteHost", request.getRemoteHost());
+
+ if (hRequest == null) {
+ doLog(" remoteUser", NON_HTTP_REQ_MSG);
+ doLog("requestedSessionId", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" remoteUser", hRequest.getRemoteUser());
+ doLog("requestedSessionId", hRequest.getRequestedSessionId());
+ }
+
+ doLog(" scheme", request.getScheme());
+ doLog(" serverName", request.getServerName());
+ doLog(" serverPort",
+ Integer.valueOf(request.getServerPort()).toString());
+
+ if (hRequest == null) {
+ doLog(" servletPath", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" servletPath", hRequest.getServletPath());
+ }
+
+ doLog(" isSecure",
+ Boolean.valueOf(request.isSecure()).toString());
+ doLog("------------------",
+ "--------------------------------------------");
+
+ // Perform the request
+ chain.doFilter(request, response);
+
+ // Log post-service information
+ doLog("------------------",
+ "--------------------------------------------");
+ if (hRequest == null) {
+ doLog(" authType", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" authType", hRequest.getAuthType());
+ }
+
+ doLog(" contentType", response.getContentType());
+
+ if (hResponse == null) {
+ doLog(" header", NON_HTTP_RES_MSG);
+ } else {
+ Iterable<String> rhnames = hResponse.getHeaderNames();
+ for (String rhname : rhnames) {
+ Iterable<String> rhvalues = hResponse.getHeaders(rhname);
+ for (String rhvalue : rhvalues)
+ doLog(" header", rhname + "=" + rhvalue);
+ }
+ }
+
+ if (hRequest == null) {
+ doLog(" remoteUser", NON_HTTP_REQ_MSG);
+ } else {
+ doLog(" remoteUser", hRequest.getRemoteUser());
+ }
+
+ if (hResponse == null) {
+ doLog(" remoteUser", NON_HTTP_RES_MSG);
+ } else {
+ doLog(" status",
+ Integer.valueOf(hResponse.getStatus()).toString());
+ }
+
+ doLog("END TIME ", getTimestamp());
+ doLog("==================",
+ "============================================");
+ }
+
+ private void doLog(String attribute, String value) {
+ StringBuilder sb = new StringBuilder(80);
+ sb.append(Thread.currentThread().getName());
+ sb.append(' ');
+ sb.append(attribute);
+ sb.append('=');
+ sb.append(value);
+ log.info(sb.toString());
+ }
+
+ private String getTimestamp() {
+ Timestamp ts = timestamp.get();
+ long currentTime = System.currentTimeMillis();
+
+ if ((ts.date.getTime() + 999) < currentTime) {
+ ts.date.setTime(currentTime - (currentTime % 1000));
+ ts.update();
+ }
+ return ts.dateString;
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // NOOP
+ }
+
+ @Override
+ public void destroy() {
+ // NOOP
+ }
+
+ private static final class Timestamp {
+ private Date date = new Date(0);
+ private SimpleDateFormat format =
+ new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
+ private String dateString = format.format(date);
+ private void update() {
+ dateString = format.format(date);
+ }
+ }
+}
Propchange:
tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
tomcat/trunk/java/org/apache/catalina/filters/RequestDumperFilter.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision
Modified: tomcat/trunk/java/org/apache/catalina/mbeans/MBeanFactory.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/mbeans/MBeanFactory.java?rev=805375&r1=805374&r2=805375&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/mbeans/MBeanFactory.java (original)
+++ tomcat/trunk/java/org/apache/catalina/mbeans/MBeanFactory.java Tue Aug 18
11:49:26 2009
@@ -49,7 +49,6 @@
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.RemoteAddrValve;
import org.apache.catalina.valves.RemoteHostValve;
-import org.apache.catalina.valves.RequestDumperValve;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.modeler.BaseModelMBean;
@@ -513,29 +512,6 @@
/**
- * Create a new Request Dumper Valve.
- *
- * @param parent MBean Name of the associated parent component
- *
- * @exception Exception if an MBean cannot be created or registered
- */
- public String createRequestDumperValve(String parent)
- throws Exception {
-
- // Create a new RequestDumperValve instance
- RequestDumperValve valve = new RequestDumperValve();
-
- // Add the new instance to its parent component
- ObjectName pname = new ObjectName(parent);
- ContainerBase containerBase = getParentContainerFromParent(pname);
- containerBase.addValve(valve);
- ObjectName oname = valve.getObjectName();
- return (oname.toString());
-
- }
-
-
- /**
* Create a new Single Sign On Valve.
*
* @param parent MBean Name of the associated parent component
Modified: tomcat/trunk/webapps/docs/config/filter.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/filter.xml?rev=805375&r1=805374&r2=805375&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/filter.xml (original)
+++ tomcat/trunk/webapps/docs/config/filter.xml Tue Aug 18 11:49:26 2009
@@ -194,6 +194,75 @@
</section>
+<section name="Request Dumper Filter">
+
+ <subsection name="Introduction">
+
+ <p>The Request Dumper Filter logs information from the request and response
+ objects and is intended to be used for debugging purposes. When using this
+ Filter, it is recommended that the
+ <code>org.apache.catalina.filter.RequestDumperFilter</code> logger is
+ directed to a dedicated file and that the
+ <code>org.apache.juli.VerbatimFormmater</code> is used.</p>
+
+ <p><strong>WARNING: Using this filter has side-effects.</strong> The
+ output from this filter includes any parameters included with the request.
+ The parameters will be decoded using the default platform encoding. Any
+ subsequent calls to <code>request.setCharacterEncoding()</code> within
+ the web application will have no effect.</p>
+
+ </subsection>
+
+ <subsection name="Filter Class Name">
+
+ <p>The filter class name for the Request Dumper Filter is
+ <strong><code>org.apache.catalina.filters.RequestDumperFilter</code>
+ </strong>.</p>
+
+ </subsection>
+
+ <subsection name="Initialisation parameters">
+
+ <p>The Request Dumper Filter does not support any initialization
+ parameters.</p>
+
+ </subsection>
+
+ <subsection name="Sample Configuration">
+
+ <p>The following entries in a web application's web.xml would enable the
+ Request Dumper filter for all requests for that web application. If the
+ entries were added to <code>CATALINA_BASE/conf/web.xml</code>, the Request
+ Dumper Filter would be enabled for all web applications.</p>
+ <source>
+<filter>
+ <filter-name>requestdumper</filter-name>
+ <filter-class>
+ org.apache.catalina.filters.RequestDumperFilter
+ </filter-class>
+</filter>
+<filter-mapping>
+ <filter-name>requestdumper</filter-name>
+ <url-pattern>*</url-pattern>
+</filter-mapping>
+ </source>
+
+ <p>The following entries in CATALINA_BASE/conf/logging.properties would
+ create a separate log file for the Request Dumper Filter output.</p>
+ <source>
+# To this configuration below, 1request-dumper.org.apache.juli.FileHandler
+# also needs to be added to the handlers property near the top of the file
+1request-dumper.org.apache.juli.FileHandler.level = INFO
+1request-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+1request-dumper.org.apache.juli.FileHandler.prefix = request-dumper.
+1request-dumper.org.apache.juli.FileHandler.formatter =
org.apache.juli.VerbatimFormatter
+org.apache.catalina.filters.RequestDumperFilter.level = INFO
+org.apache.catalina.filters.RequestDumperFilter.handlers =
1request-dumper.org.apache.juli.FileHandler
+ </source>
+ </subsection>
+</section>
+
+
<section name="WebDAV Fix Filter">
<subsection name="Introduction">
Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=805375&r1=805374&r2=805375&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Tue Aug 18 11:49:26 2009
@@ -320,47 +320,6 @@
</section>
-<section name="Request Dumper Valve">
-
-
- <subsection name="Introduction">
-
- <p>The <em>Request Dumper Valve</em> is a useful tool in debugging
- interactions with a client application (or browser) that is sending
- HTTP requests to your Tomcat-based server. When configured, it causes
- details about each request processed by its associated
<code>Engine</code>,
- <code>Host</code>, or <code>Context</code> to be logged according to
- the logging configuration for that container.</p>
-
- <p><strong>WARNING: Using this valve has side-effects.</strong> The
- output from this valve includes any parameters included with the request.
- The parameters will be decoded using the default platform encoding. Any
- subsequent calls to <code>request.setCharacterEncoding()</code> within
- the web application will have no effect.</p>
-
- </subsection>
-
-
- <subsection name="Attributes">
-
- <p>The <strong>Request Dumper Valve</strong> supports the following
- configuration attributes:</p>
-
- <attributes>
-
- <attribute name="className" required="true">
- <p>Java class name of the implementation to use. This MUST be set to
- <strong>org.apache.catalina.valves.RequestDumperValve</strong>.</p>
- </attribute>
-
- </attributes>
-
- </subsection>
-
-
-</section>
-
-
<section name="Single Sign On Valve">
<subsection name="Introduction">
Modified: tomcat/trunk/webapps/examples/WEB-INF/web.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/web.xml?rev=805375&r1=805374&r2=805375&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/web.xml (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/web.xml Tue Aug 18 11:49:26 2009
@@ -39,7 +39,7 @@
<filter>
<filter-name>Request Dumper Filter</filter-name>
- <filter-class>filters.RequestDumperFilter</filter-class>
+
<filter-class>org.apache.catalina.filters.RequestDumperFilter</filter-class>
</filter>
<!-- Example filter to set character encoding on each request -->
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]