svn commit: r1013 - in logback/trunk: logback-access logback-access/src/main/java/ch/qos/logback/access/db logback-access/src/main/java/ch/qos/logback/access/spi logback-access/src/test/java/ch/qos/logback/access/db logback-classic/src/main/java/ch/qos/logback/classic/db logback-core/src/main/java/ch/qos/logback/core/db

Author: seb Date: Tue Nov 28 16:45:55 2006 New Revision: 1013 Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/ 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/package.html logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/ 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/DBAppenderTestBase.java logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/PackageTest.java Modified: logback/trunk/logback-access/pom.xml logback/trunk/logback-access/src/main/java/ch/qos/logback/access/spi/AccessEvent.java logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/DBAppenderBase.java Log: Added a DBAppender to the access module, and a corresponding test case. One dialect only for now. Modified: logback/trunk/logback-access/pom.xml ============================================================================== --- logback/trunk/logback-access/pom.xml (original) +++ logback/trunk/logback-access/pom.xml Tue Nov 28 16:45:55 2006 @@ -1,9 +1,11 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <groupId>ch.qos.logback</groupId> <artifactId>logback-parent</artifactId> - <version>0.6-SNAPSHOT</version> + <version>0.6-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -25,11 +27,11 @@ </description> <licenses> <license> - <name> GNU Lesser General Public License</name> - <url>http://www.gnu.org/licenses/lgpl.html</url> + <name>GNU Lesser General Public License</name> + <url>http://www.gnu.org/licenses/lgpl.html</url> </license> - </licenses> - + </licenses> + <dependencies> <dependency> <groupId>ch.qos.logback</groupId> @@ -40,10 +42,10 @@ <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> - <classifier>tests</classifier> + <classifier>tests</classifier> <scope>test</scope> </dependency> - + <dependency> <groupId>tomcat</groupId> <artifactId>catalina</artifactId> @@ -61,12 +63,18 @@ <artifactId>servlet-api-2.5</artifactId> <scope>compile</scope> </dependency> - + <dependency> <groupId>janino</groupId> <artifactId>janino</artifactId> <scope>provided</scope> </dependency> + + <dependency> + <groupId>hsqldb</groupId> + <artifactId>hsqldb</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -95,9 +103,9 @@ </excludes> </configuration> </plugin> - + </plugins> - + </build> </project> \ No newline at end of file Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/DBAppender.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/DBAppender.java Tue Nov 28 16:45:55 2006 @@ -0,0 +1,138 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ + +package ch.qos.logback.access.db; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Enumeration; + +import ch.qos.logback.access.spi.AccessEvent; +import ch.qos.logback.core.db.DBAppenderBase; + +/** + * The DBAppender inserts access events into three database tables in a format + * independent of the Java programming language. + * + * For more informations about this appender, please refer to the online manual at + * http://logback.qos.ch/manual/appenders.html#AccessDBAppender + * + * @author Ceki Gülcü + * @author Ray DeCampo + * @author Sébastien Pennec + */ +public class DBAppender extends DBAppenderBase { + protected static final String insertSQL; + protected final String insertHeaderSQL = "INSERT INTO access_event_header (event_id, header_key, header_value) VALUES (?, ?, ?)"; + protected static final Method GET_GENERATED_KEYS_METHOD; + + static { + StringBuffer sql = new StringBuffer(); + sql.append("INSERT INTO access_event ("); + sql.append("timestmp, "); + sql.append("requestURI, "); + sql.append("requestURL, "); + sql.append("remoteHost, "); + sql.append("remoteUser, "); + sql.append("remoteAddr, "); + sql.append("protocol, "); + sql.append("method, "); + sql.append("serverName, "); + sql.append("postContent) "); + sql.append(" VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?, ?)"); + insertSQL = sql.toString(); + + Method getGeneratedKeysMethod; + try { + getGeneratedKeysMethod = PreparedStatement.class.getMethod( + "getGeneratedKeys", (Class[]) null); + } catch (Exception ex) { + getGeneratedKeysMethod = null; + } + GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod; + } + + public DBAppender() { + } + + @Override + protected void subAppend(Object eventObject, Connection connection, + PreparedStatement insertStatement) throws Throwable { + AccessEvent event = (AccessEvent) eventObject; + + addAccessEvent(insertStatement, event); + + int updateCount = insertStatement.executeUpdate(); + if (updateCount != 1) { + addWarn("Failed to insert access event"); + } + + int eventId = getEventId(insertStatement, connection); + addRequestHeaders(event, connection, eventId); + } + + void addAccessEvent(PreparedStatement stmt, AccessEvent event) + throws SQLException { + stmt.setLong(1, event.getTimeStamp()); + stmt.setString(2, event.getRequestURI()); + stmt.setString(3, event.getRequestURL()); + stmt.setString(4, event.getRemoteHost()); + stmt.setString(5, event.getRemoteUser()); + stmt.setString(6, event.getRemoteAddr()); + stmt.setString(7, event.getProtocol()); + stmt.setString(8, event.getMethod()); + stmt.setString(9, event.getServerName()); + stmt.setString(10, event.getPostContent()); + } + + void addRequestHeaders(AccessEvent event, + Connection connection, int eventId) throws SQLException { + Enumeration names = event.getRequestHeaderNames(); + if (names.hasMoreElements()) { + PreparedStatement insertHeaderStatement = connection + .prepareStatement(insertHeaderSQL); + + + while (names.hasMoreElements()) { + String key = (String) names.nextElement(); + String value = (String) event.getRequestHeader(key); + + insertHeaderStatement.setInt(1, eventId); + insertHeaderStatement.setString(2, key); + insertHeaderStatement.setString(3, value); + + if (cnxSupportsBatchUpdates) { + insertHeaderStatement.addBatch(); + } else { + insertHeaderStatement.execute(); + } + } + + if (cnxSupportsBatchUpdates) { + insertHeaderStatement.executeBatch(); + } + + insertHeaderStatement.close(); + insertHeaderStatement = null; + } + } + + @Override + protected Method getGeneratedKeysMethod() { + return GET_GENERATED_KEYS_METHOD; + } + + @Override + protected String getInsertSQL() { + return insertSQL; + } +} Added: logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/package.html ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/main/java/ch/qos/logback/access/db/package.html Tue Nov 28 16:45:55 2006 @@ -0,0 +1,23 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> + +<html> + <head> + <title></title> + </head> + + <body> + +<p>The ch.qos.logback.access.db package provides means to append access events +into various databases. +</p> + +<p>Most popular database systems, such as PostgreSQL, MySQL, Oracle, DB2 and MsSQL +are supported. +</p> + +<p>Just as importantly, the way for obtaining JDBC connections is pluggable. Connections can +be obtained through the tradinal way of DriverManager, or alternatively as a DataSource. +A DataSource can be instantiated directly or it can obtained through JNDI. +</p> + </body> +</html> \ No newline at end of file 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 Tue Nov 28 16:45:55 2006 @@ -206,6 +206,10 @@ return AccessEvent.NA; } } + + public Enumeration getRequestHeaderNames() { + return httpRequest.getHeaderNames(); + } public void buildRequestHeaderMap() { requestHeaderMap = new HashMap<String, Object>(); Added: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTest.java Tue Nov 28 16:45:55 2006 @@ -0,0 +1,117 @@ +package ch.qos.logback.access.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import ch.qos.logback.access.pattern.helpers.DummyRequest; +import ch.qos.logback.access.pattern.helpers.DummyResponse; +import ch.qos.logback.access.pattern.helpers.DummyServerAdapter; +import ch.qos.logback.access.spi.AccessEvent; +import ch.qos.logback.access.spi.BasicContext; +import ch.qos.logback.core.db.DriverManagerConnectionSource; + +public class DBAppenderTest extends DBAppenderTestBase { + + BasicContext context; + DBAppender appender; + DriverManagerConnectionSource connectionSource; + + public DBAppenderTest(String name) { + super(name); + } + + public void setUp() throws SQLException { + super.setUp(); + context = new BasicContext(); + context.setName("default"); + appender = new DBAppender(); + appender.setName("DB"); + appender.setContext(context); + connectionSource = new DriverManagerConnectionSource(); + connectionSource.setContext(context); + connectionSource.setDriverClass(DRIVER_CLASS); + connectionSource.setUrl(url); + connectionSource.setUser(user); + connectionSource.setPassword(password); + connectionSource.start(); + appender.setConnectionSource(connectionSource); + appender.start(); + } + + public void tearDown() throws SQLException { + super.tearDown(); + context = null; + appender = null; + connectionSource = null; + } + + public void testAppendAccessEvent() throws SQLException { + AccessEvent event = createAccessEvent(); + appender.append(event); + + Statement stmt = connectionSource.getConnection().createStatement(); + ResultSet rs = null; + rs = stmt.executeQuery("SELECT * FROM access_event"); + if (rs.next()) { + assertEquals(event.getTimeStamp(), rs.getLong(1)); + assertEquals(event.getRequestURI(), rs.getString(2)); + assertEquals(event.getRequestURL(), rs.getString(3)); + assertEquals(event.getRemoteHost(), rs.getString(4)); + assertEquals(event.getRemoteUser(), rs.getString(5)); + assertEquals(event.getRemoteAddr(), rs.getString(6)); + assertEquals(event.getProtocol(), rs.getString(7)); + assertEquals(event.getMethod(), rs.getString(8)); + assertEquals(event.getServerName(), rs.getString(9)); + assertEquals(event.getPostContent(), rs.getString(10)); + } else { + fail("No row was inserted in the database"); + } + + rs.close(); + stmt.close(); + } + + public void testAppendHeaders() throws SQLException { + AccessEvent event = createAccessEvent(); + appender.append(event); + + Statement stmt = connectionSource.getConnection().createStatement(); + ResultSet rs = null; + rs = stmt.executeQuery("SELECT * FROM access_event_header where event_id = 0"); + while (rs.next()) { + assertEquals(event.getRequestHeader(rs.getString(2)), rs.getString(3)); + } + + rs.close(); + stmt.close(); + } + + public void testAppendMultipleEvents() throws SQLException { + for (int i = 0; i < 10; i++) { + AccessEvent event = createAccessEvent(); + appender.append(event); + } + + Statement stmt = connectionSource.getConnection().createStatement(); + ResultSet rs = null; + rs = stmt.executeQuery("SELECT * FROM access_event"); + int count = 0; + while (rs.next()) { + count++; + } + assertEquals(10, count); + + rs.close(); + stmt.close(); + } + + private AccessEvent createAccessEvent() { + DummyRequest request = new DummyRequest(); + DummyResponse response = new DummyResponse(); + DummyServerAdapter adapter = new DummyServerAdapter(request, response); + + AccessEvent ae = new AccessEvent(request, response, adapter); + return ae; + } +} Added: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTestBase.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/DBAppenderTestBase.java Tue Nov 28 16:45:55 2006 @@ -0,0 +1,123 @@ +package ch.qos.logback.access.db; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; + +import org.hsqldb.Server; + +public abstract class DBAppenderTestBase extends TestCase { + + public static final String DRIVER_CLASS = "org.hsqldb.jdbcDriver"; + String serverProps; + String url; + String user = "sa"; + String password = ""; + Server server; + boolean isNetwork = true; + + public DBAppenderTestBase(String name) { + super(name); + } + + public DBAppenderTestBase(String name, String url, boolean isNetwork) { + super(name); + this.isNetwork = isNetwork; + this.url = url; + } + + protected void setUp() throws SQLException { + if (isNetwork) { + if (url == null) { + url = "jdbc:hsqldb:hsql://localhost/test"; + } + + server = new Server(); + + server.setDatabaseName(0, "test"); + server.setDatabasePath(0, "mem:test;sql.enforce_strict_size=true"); + server.setLogWriter(null); + server.setErrWriter(null); + server.start(); + } else { + if (url == null) { + url = "jdbc:hsqldb:file:test;sql.enforce_strict_size=true"; + } + } + + try { + Class.forName(DRIVER_CLASS); + } catch (Exception e) { + e.printStackTrace(); + System.out.println(this + ".setUp() error: " + e.getMessage()); + } + + createTables(); + } + + protected void tearDown() throws SQLException { + dropTables(); + if (isNetwork) { + server.stop(); + server = null; + } + } + + Connection newConnection() throws SQLException { + return DriverManager.getConnection(url, user, password); + } + + void createTables() throws SQLException { + Connection conn = newConnection(); + StringBuffer buf = new StringBuffer(); + buf.append("CREATE TABLE access_event ("); + buf.append("timestmp BIGINT NOT NULL,"); + buf.append("requestURI VARCHAR(254),"); + buf.append("requestURL VARCHAR(254),"); + buf.append("remoteHost VARCHAR(254),"); + buf.append("remoteUser VARCHAR(254),"); + buf.append("remoteAddr VARCHAR(254),"); + buf.append("protocol VARCHAR(254),"); + buf.append("method VARCHAR(254),"); + buf.append("serverName VARCHAR(254),"); + buf.append("postContent VARCHAR(254),"); + buf.append("event_id INT NOT NULL IDENTITY);"); + query(conn, buf.toString()); + + buf = new StringBuffer(); + buf.append("CREATE TABLE access_event_header ("); + buf.append("event_id INT NOT NULL,"); + buf.append("header_key VARCHAR(254) NOT NULL,"); + buf.append("header_value LONGVARCHAR,"); + buf.append("PRIMARY KEY(event_id, header_key),"); + buf.append("FOREIGN KEY (event_id) REFERENCES access_event(event_id));"); + query(conn, buf.toString()); + } + + void dropTables() throws SQLException { + Connection conn = newConnection(); + + StringBuffer buf = new StringBuffer(); + buf.append("DROP TABLE access_event_header IF EXISTS;"); + query(conn, buf.toString()); + + buf = new StringBuffer(); + buf.append("DROP TABLE access_event IF EXISTS;"); + query(conn, buf.toString()); + } + + void query(Connection conn, String expression) throws SQLException { + Statement st = null; + st = conn.createStatement(); + + int i = st.executeUpdate(expression); + if (i == -1) { + System.out.println("db error : " + expression); + } + + st.close(); + } +} Added: logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/PackageTest.java ============================================================================== --- (empty file) +++ logback/trunk/logback-access/src/test/java/ch/qos/logback/access/db/PackageTest.java Tue Nov 28 16:45:55 2006 @@ -0,0 +1,21 @@ +/** + * Logback: the generic, reliable, fast and flexible logging framework. + * + * Copyright (C) 1999-2006, QOS.ch + * + * This library is free software, you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation. + */ +package ch.qos.logback.access.db; + +import junit.framework.*; + +public class PackageTest extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTestSuite(DBAppenderTest.class); + return suite; + } +} \ No newline at end of file Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java Tue Nov 28 16:45:55 2006 @@ -15,14 +15,16 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.Set; import ch.qos.logback.classic.spi.CallerData; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.db.DBAppenderBase; /** - * The DBAppender inserts loggin events into three database tables in a format + * The DBAppender inserts logging events into three database tables in a format * independent of the Java programming language. * * For more informations about this appender, please refer to the online manual at @@ -33,8 +35,8 @@ * @author Sébastien Pennec */ public class DBAppender extends DBAppenderBase { - protected static final String insertPropertiesSQL = "INSERT INTO logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)"; - protected static final String insertExceptionSQL = "INSERT INTO logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)"; + protected final String insertPropertiesSQL = "INSERT INTO logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)"; + protected final String insertExceptionSQL = "INSERT INTO logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)"; protected static final String insertSQL; protected static final Method GET_GENERATED_KEYS_METHOD; @@ -139,17 +141,62 @@ } @Override - protected String getInsertExceptionSQL() { - return insertExceptionSQL; + protected String getInsertSQL() { + return insertSQL; } + + protected void insertProperties(Map<String, String> mergedMap, + Connection connection, int eventId) throws SQLException { + Set propertiesKeys = mergedMap.keySet(); + if (propertiesKeys.size() > 0) { + PreparedStatement insertPropertiesStatement = connection + .prepareStatement(insertPropertiesSQL); + + for (Iterator i = propertiesKeys.iterator(); i.hasNext();) { + String key = (String) i.next(); + String value = (String) mergedMap.get(key); + + insertPropertiesStatement.setInt(1, eventId); + insertPropertiesStatement.setString(2, key); + insertPropertiesStatement.setString(3, value); + + if (cnxSupportsBatchUpdates) { + insertPropertiesStatement.addBatch(); + } else { + insertPropertiesStatement.execute(); + } + } + + if (cnxSupportsBatchUpdates) { + insertPropertiesStatement.executeBatch(); + } - @Override - protected String getInsertPropertiesSQL() { - return insertPropertiesSQL; + insertPropertiesStatement.close(); + insertPropertiesStatement = null; + } } + + protected void insertThrowable(String[] strRep, Connection connection, + int eventId) throws SQLException { + + PreparedStatement insertExceptionStatement = connection + .prepareStatement(insertExceptionSQL); + + for (short i = 0; i < strRep.length; i++) { + insertExceptionStatement.setInt(1, eventId); + insertExceptionStatement.setShort(2, i); + insertExceptionStatement.setString(3, strRep[i]); + if (cnxSupportsBatchUpdates) { + insertExceptionStatement.addBatch(); + } else { + insertExceptionStatement.execute(); + } + } + if (cnxSupportsBatchUpdates) { + insertExceptionStatement.executeBatch(); + } + insertExceptionStatement.close(); + insertExceptionStatement = null; - @Override - protected String getInsertSQL() { - return insertSQL; } } Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/DBAppenderBase.java ============================================================================== --- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/DBAppenderBase.java (original) +++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/DBAppenderBase.java Tue Nov 28 16:45:55 2006 @@ -17,9 +17,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; import ch.qos.logback.core.AppenderBase; import ch.qos.logback.core.Layout; @@ -40,8 +37,6 @@ protected abstract Method getGeneratedKeysMethod(); protected abstract String getInsertSQL(); - protected abstract String getInsertPropertiesSQL(); - protected abstract String getInsertExceptionSQL(); @Override public void start() { @@ -160,61 +155,6 @@ return eventId; } - protected void insertProperties(Map<String, String> mergedMap, - Connection connection, int eventId) throws SQLException { - Set propertiesKeys = mergedMap.keySet(); - if (propertiesKeys.size() > 0) { - PreparedStatement insertPropertiesStatement = connection - .prepareStatement(getInsertPropertiesSQL()); - - for (Iterator i = propertiesKeys.iterator(); i.hasNext();) { - String key = (String) i.next(); - String value = (String) mergedMap.get(key); - - insertPropertiesStatement.setInt(1, eventId); - insertPropertiesStatement.setString(2, key); - insertPropertiesStatement.setString(3, value); - - if (cnxSupportsBatchUpdates) { - insertPropertiesStatement.addBatch(); - } else { - insertPropertiesStatement.execute(); - } - } - - if (cnxSupportsBatchUpdates) { - insertPropertiesStatement.executeBatch(); - } - - insertPropertiesStatement.close(); - insertPropertiesStatement = null; - } - } - - protected void insertThrowable(String[] strRep, Connection connection, - int eventId) throws SQLException { - - PreparedStatement insertExceptionStatement = connection - .prepareStatement(getInsertExceptionSQL()); - - for (short i = 0; i < strRep.length; i++) { - insertExceptionStatement.setInt(1, eventId); - insertExceptionStatement.setShort(2, i); - insertExceptionStatement.setString(3, strRep[i]); - if (cnxSupportsBatchUpdates) { - insertExceptionStatement.addBatch(); - } else { - insertExceptionStatement.execute(); - } - } - if (cnxSupportsBatchUpdates) { - insertExceptionStatement.executeBatch(); - } - insertExceptionStatement.close(); - insertExceptionStatement = null; - - } - @Override public void stop() { super.stop();
participants (1)
-
noreply.seb@qos.ch