[logback-dev] svn commit: r1251 - in logback/trunk/logback-access/src: main/java/ch/qos/logback/access main/java/ch/qos/logback/access/jetty main/java/ch/qos/logback/access/pattern main/java/ch/qos/logback/access/servlet main/java/ch/qos/logback/access/spi main/java/ch/qos/logback/access/tomcat test/java/ch/qos/logback/access/pattern/helpers

noreply.ceki at qos.ch noreply.ceki at qos.ch
Thu Jan 18 17:05:40 CET 2007


Author: ceki
Date: Thu Jan 18 17:05:40 2007
New Revision: 1251

Added:
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullResponseConverter.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/ResponseContentConverter.java
Modified:
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/PatternLayout.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletResponse.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletOutputStream.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java
   logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java
   logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyServerAdapter.java
   logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyValuesAdapter.java

Log:
Added support for the http response, including contents.

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java	Thu Jan 18 17:05:40 2007
@@ -1,7 +1,6 @@
 package ch.qos.logback.access;
 
 public class Constants {
-
   public static final String LB_INPUT_BUFFER = "LB_INPUT_BUFFER";
-  
+  public static final String LB_OUTPUT_BUFFER = "LB_OUTPUT_BUFFER";
 }

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/PatternLayout.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/PatternLayout.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/PatternLayout.java	Thu Jan 18 17:05:40 2007
@@ -15,6 +15,7 @@
 import ch.qos.logback.access.pattern.ContentLengthConverter;
 import ch.qos.logback.access.pattern.DateConverter;
 import ch.qos.logback.access.pattern.FullRequestConverter;
+import ch.qos.logback.access.pattern.FullResponseConverter;
 import ch.qos.logback.access.pattern.LineSeparatorConverter;
 import ch.qos.logback.access.pattern.LocalIPAddressConverter;
 import ch.qos.logback.access.pattern.LocalPortConverter;
@@ -31,6 +32,7 @@
 import ch.qos.logback.access.pattern.RequestProtocolConverter;
 import ch.qos.logback.access.pattern.RequestURIConverter;
 import ch.qos.logback.access.pattern.RequestURLConverter;
+import ch.qos.logback.access.pattern.ResponseContentConverter;
 import ch.qos.logback.access.pattern.ResponseHeaderConverter;
 import ch.qos.logback.access.pattern.ServerNameConverter;
 import ch.qos.logback.access.pattern.StatusCodeConverter;
@@ -135,7 +137,10 @@
 
     defaultConverterMap.put("requestContent", RequestContentConverter.class.getName());
 
+    defaultConverterMap.put("responseContent", ResponseContentConverter.class.getName());
+
     defaultConverterMap.put("fullRequest", FullRequestConverter.class.getName());
+    defaultConverterMap.put("fullResponse", FullResponseConverter.class.getName());
 
     
     defaultConverterMap.put("n", LineSeparatorConverter.class.getName());

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/JettyServerAdapter.java	Thu Jan 18 17:05:40 2007
@@ -1,5 +1,10 @@
 package ch.qos.logback.access.jetty;
 
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.mortbay.jetty.HttpFields;
 import org.mortbay.jetty.Request;
 import org.mortbay.jetty.Response;
 
@@ -7,11 +12,11 @@
 
 /**
  * A jetty specific implementation of the {@link ServerAdapter} interface.
- *
+ * 
  * @author Sébastien Pennec
  */
 public class JettyServerAdapter implements ServerAdapter {
-  
+
   Request request;
   Response response;
 
@@ -19,7 +24,7 @@
     this.request = jettyRequest;
     this.response = jettyResponse;
   }
-  
+
   public long getContentLength() {
     return response.getContentCount();
   }
@@ -27,8 +32,18 @@
   public int getStatusCode() {
     return response.getStatus();
   }
-  
+
   public String getResponseHeader(String key) {
     return response.getHeader(key);
   }
+
+  public List<String> getResponseHeaderNameList() {
+    HttpFields httpFields = response.getHttpFields();
+    List<String> hnList = new ArrayList<String>();
+    Enumeration e = httpFields.getFieldNames();
+    while (e.hasMoreElements()) {
+      hnList.add((String) e.nextElement());
+    }
+    return hnList;
+  }
 }

Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullResponseConverter.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullResponseConverter.java	Thu Jan 18 17:05:40 2007
@@ -0,0 +1,32 @@
+package ch.qos.logback.access.pattern;
+
+import java.util.List;
+
+import ch.qos.logback.access.spi.AccessEvent;
+import ch.qos.logback.core.Layout;
+
+public class FullResponseConverter extends AccessConverter {
+
+  @Override
+  public String convert(AccessEvent ae) {
+    StringBuffer buf = new StringBuffer();
+    
+    buf.append("HTTP/1.1 ");
+    buf.append(ae.getStatusCode());
+    buf.append(" NA");
+    buf.append(Layout.LINE_SEP);
+    
+    List<String> hnList = ae.getResponseHeaderNameList();
+    for(String headerName: hnList) {
+      buf.append(headerName);
+      buf.append(": ");
+      buf.append(ae.getResponseHeader(headerName));
+      buf.append(Layout.LINE_SEP);
+    }
+    buf.append(Layout.LINE_SEP);
+    buf.append(ae.getResponseContent());
+    buf.append(Layout.LINE_SEP);
+    return buf.toString();
+  }
+
+}

Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/ResponseContentConverter.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/ResponseContentConverter.java	Thu Jan 18 17:05:40 2007
@@ -0,0 +1,21 @@
+package ch.qos.logback.access.pattern;
+
+import ch.qos.logback.access.spi.AccessEvent;
+
+/**
+ * This class is tied to the <code>requestContent</code> conversion word.
+ * <p>
+ * It has been removed from the {@link ch.qos.logback.access.PatternLayout} since
+ * it needs further testing before wide use.
+ * <p>
+ * @author Ceki G&uuml;lc&uuml;
+ * @author S&eacute;bastien Pennec
+ */
+public class ResponseContentConverter extends AccessConverter {
+
+  @Override
+  public String convert(AccessEvent accessEvent) {
+    return accessEvent.getResponseContent();
+  }
+
+}

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java	Thu Jan 18 17:05:40 2007
@@ -11,6 +11,8 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import ch.qos.logback.access.Constants;
+
 public class TeeFilter implements Filter {
 
   public void destroy() {
@@ -19,17 +21,33 @@
 
   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain filterChain) throws IOException, ServletException {
-    
-    if(request instanceof HttpServletRequest) {
-      HttpServletRequest httpRequest = (HttpServletRequest) request;
-      request =  new TeeHttpServletRequest(httpRequest);
-    }
-    if(response instanceof HttpServletResponse) {
-      HttpServletResponse httpResponse = (HttpServletResponse) response;
-      response =  new TeeHttpServletResponse(httpResponse);
+
+    if (request instanceof HttpServletRequest) {
+      try {
+        TeeHttpServletRequest teeRequest = new TeeHttpServletRequest(
+            (HttpServletRequest) request);
+        TeeHttpServletResponse teeResponse = new TeeHttpServletResponse(
+            (HttpServletResponse) response);
+        
+        //System.out.println("BEFORE TeeFilter. filterChain.doFilter()");
+        filterChain.doFilter(teeRequest, teeResponse);
+        //System.out.println("AFTER TeeFilter. filterChain.doFilter()");
+
+        teeResponse.finish();
+        // let the output contents be available for later use by
+        // logback-access-logging
+        teeRequest.setAttribute(Constants.LB_OUTPUT_BUFFER, teeResponse
+            .getOutputBuffer());
+      } catch (IOException e) {
+        e.printStackTrace();
+        throw e;
+      } catch (ServletException e) {
+        e.printStackTrace();
+        throw e;
+      }
+    } else {
+      filterChain.doFilter(request, response);
     }
-    
-    filterChain.doFilter(request, response);
 
   }
 

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletResponse.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletResponse.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletResponse.java	Thu Jan 18 17:05:40 2007
@@ -1,6 +1,7 @@
 package ch.qos.logback.access.servlet;
 
 import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 
 import javax.servlet.ServletOutputStream;
@@ -9,27 +10,46 @@
 
 public class TeeHttpServletResponse extends HttpServletResponseWrapper {
 
-  final TeeServletOutputStream teeServletOutputStream;
+  TeeServletOutputStream teeServletOutputStream;
   PrintWriter writer;
 
-  public TeeHttpServletResponse(HttpServletResponse httpServletResponse)
-      throws IOException {
+  public TeeHttpServletResponse(HttpServletResponse httpServletResponse) {
     super(httpServletResponse);
-    ServletOutputStream underlyingStream = httpServletResponse
-        .getOutputStream();
-    teeServletOutputStream = new TeeServletOutputStream(underlyingStream);
+    //System.out.println("TeeHttpServletResponse.constructor called");
   }
 
   @Override
   public ServletOutputStream getOutputStream() throws IOException {
+    //System.out.println("TeeHttpServletResponse.getOutputStream() called");
+    if(teeServletOutputStream == null) {
+      teeServletOutputStream = new TeeServletOutputStream(
+          this.getResponse());
+    }
     return teeServletOutputStream;
   }
 
   @Override
   public PrintWriter getWriter() throws IOException {
-    if (writer == null)
-      writer = new PrintWriter(getOutputStream());
-    return writer;
+    //System.out.println("TeeHttpServletResponse.getWriter() called");
+    if (this.writer == null) {
+      this.writer = new PrintWriter(new OutputStreamWriter(getOutputStream()), true);
+    }
+    return this.writer;
   }
 
+  @Override
+  public void flushBuffer() {
+    //System.out.println("TeeHttpServletResponse.flushBuffer() called");
+    this.writer.flush();
+  }
+  
+  byte[] getOutputBuffer() {
+    return teeServletOutputStream.getOutputBuffer();
+  }
+  
+  
+  void  finish() throws IOException {
+    this.writer.close();
+    teeServletOutputStream.close();
+  }
 }

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletOutputStream.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletOutputStream.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletOutputStream.java	Thu Jan 18 17:05:40 2007
@@ -4,44 +4,67 @@
 import java.io.IOException;
 
 import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
 
 public class TeeServletOutputStream extends ServletOutputStream {
 
   final ServletOutputStream underlyingStream;
   final ByteArrayOutputStream baos;
 
-  TeeServletOutputStream(ServletOutputStream underlyingStream) {
-    this.underlyingStream = underlyingStream;
+
+  TeeServletOutputStream(ServletResponse httpServletResponse) throws IOException {
+    //System.out.println("TeeServletOutputStream.constructor() called");
+    this.underlyingStream = httpServletResponse.getOutputStream();
     baos = new ByteArrayOutputStream();
   }
 
+  byte[] getOutputBuffer() {
+    return baos.toByteArray();
+  }
+  
   @Override
   public void write(int val) throws IOException {
+    //System.out.println("XXXXXXXXXXXWRITE TeeServletOutputStream.write(int) called");
     underlyingStream.write(val);
     baos.write(val);
   }
 
   @Override
   public void write(byte[] byteArray) throws IOException {
-    underlyingStream.write(byteArray);
-    baos.write(byteArray);
+    //System.out.println("WRITE TeeServletOutputStream.write(byte[]) called");
+    write(byteArray, 0, byteArray.length);
   }
 
   @Override
   public void write(byte byteArray[], int offset, int length)
       throws IOException {
+    //System.out.println("WRITE TeeServletOutputStream.write(byte[], int, int) called");
+    //System.out.println(new String(byteArray, offset, length));
     underlyingStream.write(byteArray, offset, length);
     baos.write(byteArray, offset, length);
   }
 
   public void close() throws IOException {
+   // System.out.println("CLOSE TeeServletOutputStream.close() called");
+    
+    // If the servlet accessing the stream is using a writer instead of 
+    // an OutputStream, it will probably call os.close() begore calling
+    // writer.close. Thus, the undelying output stream will be called
+    // before the data sent to the writer could be flushed.
+  }
+
+  public void finish() throws IOException {
+    //System.out.println("FINISH TeeServletOutputStream.close() called");
+    flush();
     underlyingStream.close();
     baos.close();
   }
 
   public void flush() throws IOException {
+    //System.out.println("FLUSH TeeServletOutputStream.flush() called");
     underlyingStream.flush();
     baos.flush();
   }
 
+
 }

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java	Thu Jan 18 17:05:40 2007
@@ -3,6 +3,7 @@
 import java.io.Serializable;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.servlet.http.Cookie;
@@ -41,7 +42,8 @@
   String method;
   String serverName;
   String requestContent;
-
+  String responseContent;
+  
   Map<String, String> requestHeaderMap;
   Map<String, Object> requestParameterMap;
 
@@ -247,6 +249,10 @@
     return serverAdapter.getResponseHeader(key);
   }
 
+  public List<String> getResponseHeaderNameList() {
+    return serverAdapter.getResponseHeaderNameList();
+  }
+  
   /**
    * Attributes are not serialized
    * 
@@ -333,6 +339,23 @@
     return requestContent;
   }
 
+  public String getResponseContent() {
+    if (responseContent != null) {
+      return responseContent;
+    }
+    // retreive the byte array previously placed by TeeFilter
+    byte[] outputBuffer = (byte[]) httpRequest.getAttribute(Constants.LB_OUTPUT_BUFFER);
+
+    if (outputBuffer != null) {
+      responseContent = new String(outputBuffer);
+    }
+
+    if (responseContent == null || responseContent.length() == 0) {
+      responseContent = EMPTY;
+    }
+
+    return responseContent;
+  }
   public int getLocalPort() {
     if (localPort == SENTINEL) {
       if (httpRequest != null) {

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/ServerAdapter.java	Thu Jan 18 17:05:40 2007
@@ -1,5 +1,7 @@
 package ch.qos.logback.access.spi;
 
+import java.util.List;
+
 /**
  * An interface to access server-specific methods from
  * the server-independent AccessEvent.
@@ -12,4 +14,6 @@
   long getContentLength();
   int getStatusCode();
   String getResponseHeader(String key);
+  List<String> getResponseHeaderNameList();
+
 }

Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java
==============================================================================
--- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java	(original)
+++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/tomcat/TomcatServerAdapter.java	Thu Jan 18 17:05:40 2007
@@ -1,5 +1,8 @@
 package ch.qos.logback.access.tomcat;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
 
@@ -7,11 +10,11 @@
 
 /**
  * A tomcat specific implementation of the {@link ServerAdapter} interface.
- *
+ * 
  * @author S&eacute;bastien Pennec
  */
 public class TomcatServerAdapter implements ServerAdapter {
-  
+
   Request request;
   Response response;
 
@@ -19,7 +22,7 @@
     this.request = tomcatRequest;
     this.response = tomcatResponse;
   }
-  
+
   public long getContentLength() {
     return response.getContentLength();
   }
@@ -27,8 +30,16 @@
   public int getStatusCode() {
     return response.getStatus();
   }
-  
+
   public String getResponseHeader(String key) {
     return response.getHeader(key);
   }
+
+  public List<String> getResponseHeaderNameList() {
+    List<String> hnList = new ArrayList<String>();
+    for (String name : response.getHeaderNames()) {
+      hnList.add(name);
+    }
+    return hnList;
+  }
 }

Modified: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyServerAdapter.java
==============================================================================
--- logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyServerAdapter.java	(original)
+++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyServerAdapter.java	Thu Jan 18 17:05:40 2007
@@ -1,5 +1,7 @@
 package ch.qos.logback.access.pattern.helpers;
 
+import java.util.List;
+
 import ch.qos.logback.access.spi.ServerAdapter;
 
 public class DummyServerAdapter implements ServerAdapter {
@@ -24,4 +26,8 @@
     return response.getHeader(key);
   }
 
+  public List<String> getResponseHeaderNameList() {
+    return null;
+  }
+
 }

Modified: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyValuesAdapter.java
==============================================================================
--- logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyValuesAdapter.java	(original)
+++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/pattern/helpers/DummyValuesAdapter.java	Thu Jan 18 17:05:40 2007
@@ -1,5 +1,7 @@
 package ch.qos.logback.access.pattern.helpers;
 
+import java.util.List;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -32,4 +34,8 @@
     return 1;
   }
 
+  public List<String> getResponseHeaderNameList() {
+    return null;
+  }
+
 }



More information about the logback-dev mailing list