
Author: seb Date: Wed Sep 27 16:17:35 2006 New Revision: 608 Added: 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/spi/Util.java logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyTestSetup.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/jetty/JettyServerAdapter.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java Log: Work in progress: - added a PostContentConverter - created a test case and test setup to create and launch a Jetty server - added a getPostContent method to AccessEvent - added the corresponding pattern to PatternLayout - added javadoc to RequestLogImpl 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 Sep 27 16:17:35 2006 @@ -17,6 +17,7 @@ import ch.qos.logback.access.pattern.LineSeparatorConverter; import ch.qos.logback.access.pattern.LocalIPAddressConverter; 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; @@ -49,8 +50,6 @@ defaultConverterMap.put("b", ContentLengthConverter.class.getName()); defaultConverterMap.put("B", ContentLengthConverter.class.getName()); defaultConverterMap.put("bytesSent", ContentLengthConverter.class.getName()); - - defaultConverterMap.put("h", RemoteHostConverter.class.getName()); defaultConverterMap.put("clientHost", RemoteHostConverter.class.getName()); @@ -85,6 +84,9 @@ defaultConverterMap.put("v", ServerNameConverter.class.getName()); defaultConverterMap.put("server", ServerNameConverter.class.getName()); + defaultConverterMap.put("p", PostContentConverter.class.getName()); + defaultConverterMap.put("post", PostContentConverter.class.getName()); + } public PatternLayout() { 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 Wed Sep 27 16:17:35 2006 @@ -31,5 +31,4 @@ public String getResponseHeader(String key) { return response.getHeader(key); } - } Modified: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java ============================================================================== --- logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java (original) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/jetty/RequestLogImpl.java Wed Sep 27 16:17:35 2006 @@ -16,7 +16,51 @@ import ch.qos.logback.core.status.ErrorStatus; import ch.qos.logback.core.util.StatusPrinter; - +/** + * This class is logback's implementation of jetty's RequestLog interface. + * <p> + * It can be seen as logback classic's LoggerContext. Appenders can be attached + * directly to RequestLogImpl and RequestLogImpl uses the same StatusManager as + * LoggerContext does. It also provides containers for properties. + * <p> + * To configure jetty in order to use RequestLogImpl, the following lines must + * be added to the jetty configuration file: + * <pre> + * <Ref id="requestLog"> + * <Set name="requestLog"> + * <New id="requestLogImpl" class="ch.qos.logback.access.jetty.RequestLogImpl"></New> + * </Set> + * </Ref> + * </pre> + * By default, RequestLogImpl looks for a logback configuration file called + * logback.xml, in the same folder where jetty.xml is located, that is + * /etc/logback.xml. The logback.xml file is slightly different than the usual + * logback classic configuration file. Most of it is the same: Appenders and + * Layouts are declared the exact same way. However, loggers elements are not + * allowed. + * <p> + * Here is a sample logback.xml file that can be used right away: + * <pre> + * <configuration> + * <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + * <layout class="ch.qos.logback.access.PatternLayout"> + * <param name="Pattern" value="%date %server %remoteIP %clientHost %user %requestURL %post" /> + * </layout> + * </appender> + * + * <appender-ref ref="STDOUT" /> + * </configuration> + * </pre> + * A special, module-specific implementation of PatternLayout was implemented to allow + * http-specific patterns to be used. The {@link ch.qos.logback.access.PatternLayout} provides + * a way to format the logging output that is just as easy and flexible as the usual + * PatternLayout. + * For more information about the general use of a PatternLayout, please refer to logback + * classic's {@link ch.qos.logback.classic.PatternLayout}. For information about logback + * access' specific PatternLayout, please refer to it's javadoc. + * + * @author Ceki Gülcü + */ public class RequestLogImpl extends ContextBase implements RequestLog, AppenderAttachable { @@ -27,8 +71,10 @@ String filename; public void log(Request jettyRequest, Response jettyResponse) { - JettyServerAdapter adapter = new JettyServerAdapter(jettyRequest, jettyResponse); - AccessEvent accessEvent = new AccessEvent(jettyRequest, jettyResponse, adapter); + JettyServerAdapter adapter = new JettyServerAdapter(jettyRequest, + jettyResponse); + AccessEvent accessEvent = new AccessEvent(jettyRequest, jettyResponse, + adapter); // TODO better exception handling aai.appendLoopOnAppenders(accessEvent); } @@ -51,18 +97,18 @@ StatusPrinter.print(getStatusManager()); } else { getStatusManager().add( - new ErrorStatus("["+filename+"] does not exist", this)); + new ErrorStatus("[" + filename + "] does not exist", this)); } } public void stop() throws Exception { - System.out.println("RequestLogImpl-stop called"); + // System.out.println("RequestLogImpl-stop called"); aai.detachAndStopAllAppenders(); } public boolean isRunning() { - System.out.println("RequestLogImpl-isRunning called"); + // System.out.println("RequestLogImpl-isRunning called"); return false; } @@ -71,22 +117,22 @@ } public boolean isStarted() { - System.out.println("RequestLogImpl-isStarted called"); + // System.out.println("RequestLogImpl-isStarted called"); return true; } public boolean isStarting() { - System.out.println("RequestLogImpl-isStarting called"); + // System.out.println("RequestLogImpl-isStarting called"); return false; } public boolean isStopping() { - System.out.println("RequestLogImpl-isStopping called"); + // System.out.println("RequestLogImpl-isStopping called"); return false; } public boolean isFailed() { - System.out.println("RequestLogImpl-isFailed called"); + // System.out.println("RequestLogImpl-isFailed called"); return false; } Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/pattern/PostContentConverter.java Wed Sep 27 16:17:35 2006 @@ -0,0 +1,12 @@ +package ch.qos.logback.access.pattern; + +import ch.qos.logback.access.spi.AccessEvent; + +public class PostContentConverter extends AccessConverter { + + @Override + protected String convert(AccessEvent accessEvent) { + return accessEvent.getPostContent(); + } + +} 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 Sep 27 16:17:35 2006 @@ -279,6 +279,20 @@ return statusCode; } + public String getPostContent() { + String content = null; + try { + content = Util.readToString(httpRequest.getInputStream()); + } catch (Exception ex) { + // do nothing + } + if (content != null && content.length() > 0) { + return content; + } else { + return NA; + } + } + public int getLocalPort() { if (localPort == SENTINEL) { if (httpRequest != null) { Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/Util.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/Util.java Wed Sep 27 16:17:35 2006 @@ -0,0 +1,20 @@ +package ch.qos.logback.access.spi; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class Util { + + public static String readToString(InputStream in) throws IOException { + StringBuffer sb = new StringBuffer(); + BufferedReader inbr = new BufferedReader(new InputStreamReader(in)); + String line; + while ((line = inbr.readLine()) != null) { + sb.append(line); + } + + return sb.toString(); + } +} Added: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyBasicTest.java Wed Sep 27 16:17:35 2006 @@ -0,0 +1,71 @@ +package ch.qos.logback.access.jetty; + + +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import ch.qos.logback.access.spi.AccessEvent; +import ch.qos.logback.access.spi.Util; +import ch.qos.logback.core.appender.ListAppender; + +public class JettyBasicTest extends TestCase { + + static RequestLogImpl requestLogImpl; + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTestSuite(JettyBasicTest.class); + requestLogImpl = new RequestLogImpl(); + return new JettyTestSetup(suite, requestLogImpl); + } + +// public void testGetRequest() throws Exception { +// URL url = new URL("http://localhost:8080/"); +// HttpURLConnection connection = (HttpURLConnection)url.openConnection(); +// connection.setDoInput(true); +// +// String result = Util.readToString(connection.getInputStream()); +// +// assertEquals("hello world", result); +// +// ListAppender appender = (ListAppender)requestLogImpl.getAppender("list"); +// appender.list.clear(); +// } + + public void testPostContentConverter() throws Exception { + System.out.println("into test"); + URL url = new URL("http://localhost:8080/"); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + ((HttpURLConnection)connection).setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setRequestProperty("Content-Type", "text/plain"); + + String msg = "test message"; + PrintWriter output = new PrintWriter(new OutputStreamWriter(connection.getOutputStream())); + output.print(msg); + output.flush(); + output.close(); + + String result = Util.readToString(connection.getInputStream()); + + ListAppender appender = (ListAppender)requestLogImpl.getAppender("list"); + //assertEquals(1, appender.list.size()); + Iterator it = appender.list.iterator(); + int i = 0; + while(it.hasNext()) { + AccessEvent event = (AccessEvent)it.next(); + System.out.println(i++ + ": " + event.getPostContent()); + } + //System.out.println("0: " + event.getPostContent()); + + } + +} Added: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyTestSetup.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/jetty/JettyTestSetup.java Wed Sep 27 16:17:35 2006 @@ -0,0 +1,119 @@ +package ch.qos.logback.access.jetty; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.extensions.TestSetup; +import junit.framework.Test; + +import org.mortbay.jetty.Connector; +import org.mortbay.jetty.Handler; +import org.mortbay.jetty.HttpConnection; +import org.mortbay.jetty.Request; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.AbstractHandler; +import org.mortbay.jetty.handler.ContextHandler; +import org.mortbay.jetty.handler.RequestLogHandler; +import org.mortbay.jetty.nio.SelectChannelConnector; +import org.mortbay.util.ByteArrayISO8859Writer; + +import ch.qos.logback.access.PatternLayout; +import ch.qos.logback.core.ConsoleAppender; +import ch.qos.logback.core.appender.ListAppender; + +public class JettyTestSetup extends TestSetup { + + ListAppender appender; + RequestLogImpl requestLogImpl; + + public JettyTestSetup(Test suite, RequestLogImpl impl) { + super(suite); + requestLogImpl = impl; + } + + Server server; + String url = "http://localhost:8080/"; + + public void setUp() throws Exception { + System.out.println("into setUp"); + super.setUp(); + + server = new Server(); + Connector connector = new SelectChannelConnector(); + connector.setPort(8080); + server.setConnectors(new Connector[] { connector }); + + ContextHandler context = new ContextHandler(); + context.setContextPath("/"); + context.setResourceBase("."); + context.setClassLoader(Thread.currentThread().getContextClassLoader()); + server.addHandler(context); + + RequestLogHandler requestLogHandler = new RequestLogHandler(); + buildContext(); + requestLogHandler.setRequestLog(requestLogImpl); + server.addHandler(requestLogHandler); + + Handler handler = new BasicHandler(); + context.addHandler(handler); + + server.start(); + } + + public void tearDown() throws Exception { + System.out.println("into tearDown"); + super.tearDown(); + server.stop(); +// Thread.sleep(1000); +// server = null; +// appender = null; +// requestLogImpl = null; + } + + private void buildContext() { + + appender = new ListAppender(); + appender.setContext(requestLogImpl); + appender.setName("list"); + appender.start(); + +// ConsoleAppender console = new ConsoleAppender(); +// console.setContext(requestLogImpl); +// console.setName("console"); +// PatternLayout layout = new PatternLayout(); +// layout.setContext(requestLogImpl); +// layout +// .setPattern("%date %server %remoteIP %clientHost %user %requestURL %post"); +// console.setLayout(layout); +// layout.start(); +// console.start(); + + //requestLogImpl.addAppender(console); + requestLogImpl.addAppender(appender); + } + +} + +class BasicHandler extends AbstractHandler { + public void handle(String target, HttpServletRequest request, + HttpServletResponse response, int dispatch) throws IOException, + ServletException { + + OutputStream out = response.getOutputStream(); + ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(); + writer.write("hello world"); + writer.flush(); + response.setContentLength(writer.size()); + writer.writeTo(out); + out.flush(); + + Request base_request = (request instanceof Request) ? (Request) request + : HttpConnection.getCurrentConnection().getRequest(); + base_request.setHandled(true); + + } +} \ No newline at end of file