
Author: ceki Date: Wed Jan 17 15:59:12 2007 New Revision: 1242 Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullRequestConverter.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/RequestContentConverter.java - copied, changed from r1238, /logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java Removed: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/InputStreamDuplicatingFilter.java 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/db/DBAppender.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletInputStream.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java Log: - Getting the contents of a post now works (tested in Jetty) This requires adding a special filter (TeeFilter.java) - Added FullRequestConverter.java which outputs the full contents of the request including request payload - Minor changes to PatternLayout (DOC NEEDS TO BE UPDATED) - Renaming changes in AccessEvent.java Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/Constants.java Wed Jan 17 15:59:12 2007 @@ -0,0 +1,7 @@ +package ch.qos.logback.access; + +public class Constants { + + public static final String LB_INPUT_BUFFER = "LB_INPUT_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 Wed Jan 17 15:59:12 2007 @@ -14,15 +14,16 @@ 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.LineSeparatorConverter; import ch.qos.logback.access.pattern.LocalIPAddressConverter; import ch.qos.logback.access.pattern.LocalPortConverter; import ch.qos.logback.access.pattern.NAConverter; -import ch.qos.logback.access.pattern.PostContentConverter; import ch.qos.logback.access.pattern.RemoteHostConverter; import ch.qos.logback.access.pattern.RemoteIPAddressConverter; import ch.qos.logback.access.pattern.RemoteUserConverter; import ch.qos.logback.access.pattern.RequestAttributeConverter; +import ch.qos.logback.access.pattern.RequestContentConverter; import ch.qos.logback.access.pattern.RequestCookieConverter; import ch.qos.logback.access.pattern.RequestHeaderConverter; import ch.qos.logback.access.pattern.RequestMethodConverter; @@ -111,16 +112,30 @@ defaultConverterMap.put("server", ServerNameConverter.class.getName()); defaultConverterMap.put("localPort", LocalPortConverter.class.getName()); + + defaultConverterMap.put("requestAttribute", RequestAttributeConverter.class + .getName()); defaultConverterMap.put("reqAttribute", RequestAttributeConverter.class .getName()); + defaultConverterMap .put("reqCookie", RequestCookieConverter.class.getName()); + defaultConverterMap + .put("requestCookie", RequestCookieConverter.class.getName()); + + defaultConverterMap.put("responseHeader", ResponseHeaderConverter.class .getName()); + + + defaultConverterMap.put("requestParameter", RequestParameterConverter.class + .getName()); defaultConverterMap.put("reqParameter", RequestParameterConverter.class .getName()); - defaultConverterMap.put("post", PostContentConverter.class.getName()); + defaultConverterMap.put("requestContent", RequestContentConverter.class.getName()); + + defaultConverterMap.put("fullRequest", FullRequestConverter.class.getName()); defaultConverterMap.put("n", LineSeparatorConverter.class.getName()); Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/DBAppender.java ============================================================================== --- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/DBAppender.java (original) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/DBAppender.java Wed Jan 17 15:59:12 2007 @@ -95,7 +95,7 @@ stmt.setString(7, event.getProtocol()); stmt.setString(8, event.getMethod()); stmt.setString(9, event.getServerName()); - stmt.setString(10, event.getPostContent()); + stmt.setString(10, event.getRequestContent()); } void addRequestHeaders(AccessEvent event, Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullRequestConverter.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/FullRequestConverter.java Wed Jan 17 15:59:12 2007 @@ -0,0 +1,38 @@ +package ch.qos.logback.access.pattern; + +import java.util.Enumeration; + +import ch.qos.logback.access.spi.AccessEvent; +import ch.qos.logback.core.Layout; + +/** + * 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ülcü + * @author Sébastien Pennec + */ +public class FullRequestConverter extends AccessConverter { + + @Override + public String convert(AccessEvent ae) { + StringBuffer buf = new StringBuffer(); + buf.append(ae.getRequestURL()); + buf.append(Layout.LINE_SEP); + + Enumeration headerNames = ae.getRequestHeaderNames(); + while(headerNames.hasMoreElements()) { + String name = (String) headerNames.nextElement(); + buf.append(name); + buf.append(": "); + buf.append(ae.getRequestHeader(name)); + buf.append(Layout.LINE_SEP); + } + buf.append(Layout.LINE_SEP); + buf.append(ae.getRequestContent()); + return buf.toString(); + } + +} Copied: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/RequestContentConverter.java (from r1238, /logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java) ============================================================================== --- /logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java (original) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/RequestContentConverter.java Wed Jan 17 15:59:12 2007 @@ -3,21 +3,19 @@ import ch.qos.logback.access.spi.AccessEvent; /** - * This class is tied to the <code>postContent</code> conversion pattern. + * 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 being used widely. + * it needs further testing before wide use. * <p> - * <strong>Please handle this class with caution if you wish to use it anyway!</strong> - * * @author Ceki Gülcü * @author Sébastien Pennec */ -public class PostContentConverter extends AccessConverter { +public class RequestContentConverter extends AccessConverter { @Override public String convert(AccessEvent accessEvent) { - return accessEvent.getPostContent(); + return accessEvent.getRequestContent(); } } Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeFilter.java Wed Jan 17 15:59:12 2007 @@ -0,0 +1,35 @@ +package ch.qos.logback.access.servlet; + +import java.io.IOException; + +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.HttpServletRequest; + +public class TeeFilter implements Filter { + + public void destroy() { + // NOP + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain filterChain) throws IOException, ServletException { + + if(request instanceof HttpServletRequest) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + request = new TeeHttpServletRequest(httpRequest); + } + + filterChain.doFilter(request, response); + + } + + public void init(FilterConfig arg0) throws ServletException { + // NOP + } + +} Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java ============================================================================== --- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java (original) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeHttpServletRequest.java Wed Jan 17 15:59:12 2007 @@ -8,30 +8,38 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import ch.qos.logback.access.Constants; + /** * As the "tee" program on Unix, duplicate the request's input stream. * * @author Ceki Gülcü */ -public class TeeHttpServletRequest extends HttpServletRequestWrapper { - - static final int BUF_SIZE = 512; +class TeeHttpServletRequest extends HttpServletRequestWrapper { - private ServletInputStream inStream; + private TeeServletInputStream inStream; private BufferedReader reader; - public TeeHttpServletRequest(HttpServletRequest request) { + TeeHttpServletRequest(HttpServletRequest request) { super(request); inStream = new TeeServletInputStream(request); + // add the contents of the input buffer as an attribute of the request in byte[] format + request.setAttribute(Constants.LB_INPUT_BUFFER, inStream.getInputBuffer()); reader = new BufferedReader(new InputStreamReader(inStream)); } + + byte[] getInputBuffer() { + return inStream.getInputBuffer(); + } + @Override public ServletInputStream getInputStream() throws IOException { return inStream; } + @Override public BufferedReader getReader() throws IOException { return reader; } - + } Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletInputStream.java ============================================================================== --- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletInputStream.java (original) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/servlet/TeeServletInputStream.java Wed Jan 17 15:59:12 2007 @@ -8,15 +8,15 @@ import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; -public class TeeServletInputStream extends ServletInputStream { +class TeeServletInputStream extends ServletInputStream { InputStream in; byte[] inputBuffer; - + TeeServletInputStream(HttpServletRequest request) { duplicateInputStream(request); } - + @Override public int read() throws IOException { return in.read(); @@ -26,20 +26,24 @@ try { int len = request.getContentLength(); ServletInputStream originalSIS = request.getInputStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - inputBuffer = new byte[len]; - int n = 0; - while ((n = originalSIS.read(inputBuffer, 0, len)) != -1) { - baos.write(inputBuffer, 0, n); + if (len < 0) { + in = originalSIS; + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + inputBuffer = new byte[len]; + int n = 0; + while ((n = originalSIS.read(inputBuffer, 0, len)) != -1) { + baos.write(inputBuffer, 0, n); + } + this.in = new ByteArrayInputStream(inputBuffer); + originalSIS.close(); } - this.in = new ByteArrayInputStream(inputBuffer); - originalSIS.close(); } catch (IOException e) { e.printStackTrace(); } } - - public byte[] getInputBuffer() { + + byte[] getInputBuffer() { return inputBuffer; } } 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 Wed Jan 17 15:59:12 2007 @@ -1,6 +1,5 @@ package ch.qos.logback.access.spi; -import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.HashMap; @@ -10,14 +9,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import ch.qos.logback.access.Constants; import ch.qos.logback.access.pattern.AccessConverter; /** * The Access module's internal representation of logging events. When the - * logging component instance is called in the container to log then a - * <code>AccessEvent</code> - * instance is created. This instance is passed around to the different logback - * components. + * logging component instance is called in the container to log then a + * <code>AccessEvent</code> instance is created. This instance is passed + * around to the different logback components. * * @author Ceki Gülcü * @author Sébastien Pennec @@ -27,6 +26,7 @@ private static final long serialVersionUID = -3118194368414470960L; public final static String NA = "-"; + public final static String EMPTY = ""; public static final int SENTINEL = -1; private transient final HttpServletRequest httpRequest; @@ -40,7 +40,7 @@ String protocol; String method; String serverName; - String postContent; + String requestContent; Map<String, String> requestHeaderMap; Map<String, Object> requestParameterMap; @@ -64,11 +64,11 @@ this.timeStamp = System.currentTimeMillis(); this.serverAdapter = adapter; } - + public HttpServletRequest getRequest() { return httpRequest; } - + public HttpServletResponse getResponse() { return httpResponse; } @@ -207,18 +207,18 @@ return AccessEvent.NA; } } - + public Enumeration getRequestHeaderNames() { return httpRequest.getHeaderNames(); } public Map<String, String> getRequestHeaderMap() { - if(requestHeaderMap == null) { + if (requestHeaderMap == null) { buildRequestHeaderMap(); } return requestHeaderMap; } - + public void buildRequestHeaderMap() { requestHeaderMap = new HashMap<String, String>(); Enumeration e = httpRequest.getHeaderNames(); @@ -230,7 +230,7 @@ requestHeaderMap.put(key, httpRequest.getHeader(key)); } } - + public void buildRequestParameterMap() { requestParameterMap = new HashMap<String, Object>(); Enumeration e = httpRequest.getParameterNames(); @@ -242,7 +242,7 @@ requestParameterMap.put(key, httpRequest.getParameter(key)); } } - + public String getResponseHeader(String key) { return serverAdapter.getResponseHeader(key); } @@ -315,22 +315,22 @@ return statusCode; } - public String getPostContent() { - if (postContent != null) { - return postContent; + public String getRequestContent() { + if (requestContent != null) { + return requestContent; } + // retreive the byte array placed by TeeFilter + byte[] inputBuffer = (byte[]) httpRequest.getAttribute(Constants.LB_INPUT_BUFFER); - try { - InputStream in = httpRequest.getInputStream(); - postContent = Util.readToString(in); - } catch (Exception ex) { - ex.printStackTrace(); + if (inputBuffer != null) { + requestContent = new String(inputBuffer); } - if (postContent == null || postContent.length() == 0) { - postContent = NA; + + if (requestContent == null || requestContent.length() == 0) { + requestContent = EMPTY; } - return postContent; + return requestContent; } public int getLocalPort() { @@ -346,7 +346,7 @@ public ServerAdapter getServerAdapter() { return serverAdapter; } - + public void prepareForDeferredProcessing() { buildRequestHeaderMap(); buildRequestParameterMap(); @@ -360,9 +360,9 @@ getRequestURL(); getServerName(); getTimeStamp(); - + getStatusCode(); getContentLength(); - //getPostContent(); + // getPostContent(); } } \ No newline at end of file Modified: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java ============================================================================== --- logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java (original) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java Wed Jan 17 15:59:12 2007 @@ -70,7 +70,7 @@ assertEquals(event.getProtocol(), rs.getString(7)); assertEquals(event.getMethod(), rs.getString(8)); assertEquals(event.getServerName(), rs.getString(9)); - assertEquals(event.getPostContent(), rs.getString(10)); + assertEquals(event.getRequestContent(), rs.getString(10)); } else { fail("No row was inserted in the database"); }