You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2010/06/03 17:00:11 UTC

svn commit: r951018 - in /tomcat/trunk: java/org/apache/catalina/ java/org/apache/catalina/connector/ java/org/apache/catalina/core/ webapps/docs/config/

Author: markt
Date: Thu Jun  3 15:00:11 2010
New Revision: 951018

URL: http://svn.apache.org/viewvc?rev=951018&view=rev
Log:
Refactor the hooks from the CoyoteAdapter to the access logs
- cleaner interface
- handles AccessLogs at multiple levels (but not multiple AccessLogs per container)

Modified:
    tomcat/trunk/java/org/apache/catalina/AccessLog.java
    tomcat/trunk/java/org/apache/catalina/Container.java
    tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
    tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java
    tomcat/trunk/java/org/apache/catalina/core/StandardEngine.java
    tomcat/trunk/webapps/docs/config/valve.xml

Modified: tomcat/trunk/java/org/apache/catalina/AccessLog.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/AccessLog.java?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/AccessLog.java (original)
+++ tomcat/trunk/java/org/apache/catalina/AccessLog.java Thu Jun  3 15:00:11 2010
@@ -23,9 +23,8 @@ import org.apache.catalina.connector.Res
 
 /**
  * Intended for use by a {@link Valve} to indicate that the {@link Valve}
- * provides access logging. It is used by the Tomcat internals (the
- * {@link org.apache.catalina.connector.CoyoteAdapter} at the time of writing)
- * to identify a Valve that logs access requests so requests that are rejected
+ * provides access logging. It is used by the Tomcat internals to identify a
+ * Valve that logs access requests so requests that are rejected
  * earlier in the processing chain can still be added to the access log.
  * Implementations of this interface should be robust against the provided
  * {@link Request} and {@link Response} objects being null, having null

Modified: tomcat/trunk/java/org/apache/catalina/Container.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Container.java?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Container.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Container.java Thu Jun  3 15:00:11 2010
@@ -450,4 +450,27 @@ public interface Container extends Lifec
      * @param data Event data
      */
     public void fireContainerEvent(String type, Object data);
+    
+    
+    /**
+     * Log a request/response that was destined for this container but has been
+     * handled earlier in the processing chain so that the request/response
+     * still appears in the correct access logs.
+     * @param request       Request (associated with the response) to log
+     * @param response      Response (associated with the request) to log
+     * @param time          Time taken to process the request/response in
+     *                      milliseconds (use 0 if not known) 
+     * @param   useDefault  Flag that indicates that the request/response should
+     *                      be logged in the engine's default access log
+     */
+    public void logAccess(Request request, Response response, long time,
+            boolean useDefault);
+    
+    
+    /**
+     * Identify the AccessLog to use to log a request/response that was destined
+     * for this container but was handled earlier in the processing chain so
+     * that the request/response still appears in the correct access logs.
+     */
+    public AccessLog getAccessLog();
 }

Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Thu Jun  3 15:00:11 2010
@@ -24,13 +24,8 @@ import java.util.EnumSet;
 
 import javax.servlet.SessionTrackingMode;
 
-import org.apache.catalina.AccessLog;
-import org.apache.catalina.Container;
 import org.apache.catalina.Context;
-import org.apache.catalina.Engine;
 import org.apache.catalina.Globals;
-import org.apache.catalina.Host;
-import org.apache.catalina.Valve;
 import org.apache.catalina.Wrapper;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.catalina.comet.CometEvent;
@@ -120,11 +115,6 @@ public class CoyoteAdapter implements Ad
     protected static URLEncoder urlEncoder;
 
 
-    /**
-     * Access log to use for rejected requests
-     */
-    private volatile AccessLog accessLog = null;
-    
     // ----------------------------------------------------- Static Initializer
 
 
@@ -522,14 +512,16 @@ public class CoyoteAdapter implements Ad
         } catch (IOException ioe) {
             res.setStatus(400);
             res.setMessage("Invalid URI: " + ioe.getMessage());
-            getAccessLog().log(request, response, 0);
+            connector.getService().getContainer().logAccess(
+                    request, response, 0, true);
             return false;
         }
         // Normalization
         if (!normalize(req.decodedURI())) {
             res.setStatus(400);
             res.setMessage("Invalid URI");
-            getAccessLog().log(request, response, 0);
+            connector.getService().getContainer().logAccess(
+                    request, response, 0, true);
             return false;
         }
         // Character decoding
@@ -538,7 +530,8 @@ public class CoyoteAdapter implements Ad
         if (!checkNormalize(req.decodedURI())) {
             res.setStatus(400);
             res.setMessage("Invalid URI character encoding");
-            getAccessLog().log(request, response, 0);
+            connector.getService().getContainer().logAccess(
+                    request, response, 0, true);
             return false;
         }
 
@@ -598,7 +591,7 @@ public class CoyoteAdapter implements Ad
             res.setStatus(405);
             res.addHeader("Allow", header);
             res.setMessage("TRACE method is not allowed");
-            getAccessLog().log(request, response, 0);
+            request.getContext().logAccess(request, response, 0, true);
             return false;
         }
 
@@ -637,7 +630,7 @@ public class CoyoteAdapter implements Ad
                 redirectPath = redirectPath + "?" + query;
             }
             response.sendRedirect(redirectPath);
-            getAccessLog().log(request, response, 0);
+            request.getContext().logAccess(request, response, 0, true);
             return false;
         }
 
@@ -1088,63 +1081,4 @@ public class CoyoteAdapter implements Ad
             b[pos + dest] = b[pos + src];
         }
     }
-
-
-    /**
-     * Obtain a reference to the access log to use to log rejected requests.
-     * 
-     * @return
-     */
-    protected AccessLog getAccessLog() {
-        if (accessLog != null) {
-            return accessLog;
-        }
-        
-        // First look in Engine for associated service
-        Engine engine = (Engine) connector.getService().getContainer();
-        accessLog = findAccessLog(engine);
-        if (accessLog != null) {
-            return accessLog;
-        }
-        
-        // Then look in default host
-        Host defaultHost = (Host) engine.findChild(engine.getDefaultHost());
-        accessLog = findAccessLog(defaultHost);
-        if (accessLog != null) {
-            return accessLog;
-        }
-            
-        // Then look in ROOT context of default host
-        Context defaultContext = (Context) defaultHost.findChild("");
-        accessLog = findAccessLog(defaultContext);
-        if (accessLog != null) {
-            return accessLog;
-        }
-
-        accessLog = new NoopAccessLog(); 
-        return accessLog;
-    }
-    
-    private AccessLog findAccessLog(Container container) {
-        if (container == null) {
-            return new NoopAccessLog();
-        }
-
-        Valve valves[] = container.getPipeline().getValves();
-        for (Valve valve : valves) {
-            if (valve instanceof AccessLog) {
-                return (AccessLog) valve;
-            }
-        }
-        return null;
-    }
-    
-    private static final class NoopAccessLog implements AccessLog {
-
-        @Override
-        public void log(Request request, Response response, long time) {
-            // NOOP
-        }
-        
-    }
 }

Modified: tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java Thu Jun  3 15:00:11 2010
@@ -31,6 +31,7 @@ import javax.management.ObjectName;
 import javax.naming.directory.DirContext;
 import javax.servlet.ServletException;
 
+import org.apache.catalina.AccessLog;
 import org.apache.catalina.CatalinaFactory;
 import org.apache.catalina.Cluster;
 import org.apache.catalina.Container;
@@ -265,6 +266,13 @@ public abstract class ContainerBase exte
     private volatile boolean threadDone = false;
 
 
+    /**
+     * The access log to use for requests normally handled by this container
+     * that have been handled earlier in the processing chain.
+     */
+    protected volatile AccessLog accessLog = null;
+    private volatile boolean accessLogScanComplete = false;
+
     // ------------------------------------------------------------- Properties
 
 
@@ -1062,6 +1070,46 @@ public abstract class ContainerBase exte
         super.destroyInternal();
     }
 
+    
+    /**
+     * Check this container for an access log and if none is found, look to the
+     * parent. If there is no parent and still none is found, use the NoOp
+     * access log.
+     */
+    public void logAccess(Request request, Response response, long time,
+            boolean useDefault) {
+        
+        boolean logged = false;
+        
+        if (getAccessLog() != null) {
+            getAccessLog().log(request, response, time);
+            logged = true;
+        }
+        
+        if (getParent() != null) {
+            // No need to use default logger once request/response has been logged
+            // once
+            getParent().logAccess(request, response, time, (useDefault && !logged));
+        }
+    }
+
+    public AccessLog getAccessLog() {
+        
+        if (accessLogScanComplete) {
+            return accessLog;
+        }
+        
+        Valve valves[] = getPipeline().getValves();
+        for (Valve valve : valves) {
+            if (valve instanceof AccessLog) {
+                accessLog = (AccessLog) valve;
+                break;
+            }
+        }
+        accessLogScanComplete = true;
+        return accessLog;
+    }
+
     // ------------------------------------------------------- Pipeline Methods
 
 
@@ -1305,4 +1353,11 @@ public abstract class ContainerBase exte
 
     }
 
+    protected static final class NoopAccessLog implements AccessLog {
+
+        @Override
+        public void log(Request request, Response response, long time) {
+            // NOOP
+        }
+    }
 }

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardEngine.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardEngine.java?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardEngine.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardEngine.java Thu Jun  3 15:00:11 2010
@@ -18,12 +18,16 @@ package org.apache.catalina.core;
 
 import java.util.Locale;
 
+import org.apache.catalina.AccessLog;
 import org.apache.catalina.Container;
+import org.apache.catalina.Context;
 import org.apache.catalina.Engine;
 import org.apache.catalina.Host;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.Realm;
 import org.apache.catalina.Service;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
 import org.apache.catalina.realm.JAASRealm;
 import org.apache.catalina.util.LifecycleBase;
 import org.apache.catalina.util.ServerInfo;
@@ -99,6 +103,11 @@ public class StandardEngine extends Cont
      */
     private String jvmRouteId;
 
+    /**
+     * Default access log to use for request/response pairs where we can't ID
+     * the intended host and context.
+     */
+    private volatile AccessLog defaultAccessLog;
 
     // ------------------------------------------------------------- Properties
 
@@ -280,6 +289,51 @@ public class StandardEngine extends Cont
 
     }
 
+    /**
+     * Override the default implementation. If no access log is defined for the
+     * Engine, look for one in the Engine's default host and then the default
+     * host's ROOT context. If still none is found, return the default NoOp
+     * access log.
+     */
+    @Override
+    /**
+     * Check this container for an access log and if none is found, look to the
+     * parent. If there is no parent and still none is found, use the NoOp
+     * access log.
+     */
+    public void logAccess(Request request, Response response, long time,
+            boolean useDefault) {
+
+        boolean logged = false;
+        
+        if (accessLog != null) {
+            accessLog.log(request, response, time);
+            logged = true;
+        }
+
+        if (!logged && useDefault) {
+            Host host = null;
+            if (defaultAccessLog == null) {
+                // If we reached this point, this Engine can't have an AccessLog
+                // Look in the defaultHost
+                host = (Host) findChild(getDefaultHost());
+                defaultAccessLog = host.getAccessLog();
+
+                if (defaultAccessLog == null) {
+                    // Try the ROOT context of default host
+                    Context context = (Context) host.findChild("");
+                    defaultAccessLog = context.getAccessLog();
+
+                    if (defaultAccessLog == null) {
+                        defaultAccessLog = new NoopAccessLog();
+                    }
+                }
+            }
+            
+            defaultAccessLog.log(request, response, time);
+        }
+    }
+
 
     // -------------------- JMX registration  --------------------
 

Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=951018&r1=951017&r2=951018&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Thu Jun  3 15:00:11 2010
@@ -66,12 +66,17 @@
     <code>Host</code>, or <code>Engine</code>), and
     will record ALL requests processed by that container.</p>
 
-    <p>Some requests (e.g. those with mal-formed URLs) may be rejected by Tomcat
-    before they are passed to a container. In these cases Tomcat will look in
-    the <code>Engine</code>, then the default <code>Host</code> for the
-    <code>Engine</code> and finally the ROOT (or default) <code>Context</code>
-    for the default <code>Host</code> for an <code>AccessLogValve</code> or
-    other <code>AccessLog</code> implementation. Tomcat will use the first
+    <p>Some requests may be handled by Tomcat before they are passed to a
+    container. These include redirects from /foo to /foo/ and the rejection of
+    invalid requests. Where Tomcat can identify the <code>Context</code> that
+    would have handled the request, the request/response will be logged in the 
+    <code>AccessLog</code>(s) associated <code>Context</code>, <code>Host</code>
+    and <code>Engine</code>. Where Tomcat cannot identify the
+    <code>Context</code> that would have handled the request, e.g. in cases
+    where the URL is invalid, Tomcat will look first in the <code>Engine</code>,
+    then the default <code>Host</code> for the <code>Engine</code> and finally
+    the ROOT (or default) <code>Context</code> for the default <code>Host</code>
+    for an <code>AccessLog</code> implementation. Tomcat will use the first
     <code>AccessLog</code> implementation found to log those requests that are
     rejected before they are passed to a container.</p>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org