You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-cvs@jakarta.apache.org by ce...@apache.org on 2001/06/18 14:41:22 UTC
cvs commit: jakarta-log4j/contribs/KevinSteppe JDBCAppender.java
ceki 01/06/18 05:41:22
Modified: contribs/KevinSteppe JDBCAppender.java
Log:
Updated version of Kevin Steppe's JDBCAppender.
Revision Changes Path
1.2 +237 -56 jakarta-log4j/contribs/KevinSteppe/JDBCAppender.java
Index: JDBCAppender.java
===================================================================
RCS file: /home/cvs/jakarta-log4j/contribs/KevinSteppe/JDBCAppender.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JDBCAppender.java 2001/02/14 17:47:00 1.1
+++ JDBCAppender.java 2001/06/18 12:41:22 1.2
@@ -1,8 +1,12 @@
package org.apache.log4j.varia;
+
import org.apache.log4j.*;
import org.apache.log4j.spi.*;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.helpers.OptionConverter;
+
import java.util.List;
@@ -10,34 +14,71 @@
import java.util.Iterator;
+
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
+
/**
- * Contribution from MD Data Direct.
+ * This JDBCAppender is intended to provide a convinent base clas or
+ * default class for sending log messages to a database.
+ *
+ * Each append call adds to an ArrayList buffer. When the buffer is filled
+ * (set by the BUFFER_OPTION or setBufferSize(int buffer), default is 1) each
+ * log event is placed in a sql statement (configurable) and executed.
+ *
+ * BufferSize, db URL, User, & Password are configurable options in
+ * the standard Log4J methods.
+ *
+ * DB driver is also configurable -- setting the DRIVER_OPTION
+ * automaticaly loads the driver The SQL_OPTION sets the SQL statement
+ * to be used for logging -- by default all the conversion patterns in
+ * PatternLayout can be used inside of the statement. (see the test
+ * cases for examples) if a layout is explicitely attached it's output
+ * will replace the first instance of "%m" in the SQL statement.
+ * Overriding the getSQL method allows more explicit control of the
+ * statement used for logging.
*
- * Implements an ArrayList buffer before storing messages to the DB.
- * Override getSQL to fit your database schema (or implement spLog msg
- * on your DB) Override executeSQL to modify how DB connection and SQL
- * execution is made.
*
- * @author: Kevin Steppe */
+ * For use as a base class:
+ *
+ * Override executeSQL(String sql) to modify connection/statement
+ * behavior The default implementation creates a new connection
+ * from the Driver for every statement.
+ *
+ * Override getSQL(LoggingEvent event) to produce specialized or
+ * dynamic statements The default uses the sql option value
+ *
+ *
+ * @author: Kevin Steppe (ksteppe@pacbell.net)
+*/
+
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
implements org.apache.log4j.Appender {
-
- protected String databaseURL = "jdbc:odbc:myDB";
- protected String databaseUser = "me";
- protected String databasePassword = "mypassword";
public static final String URL_OPTION = "URL";
public static final String USER_OPTION = "User";
public static final String PASSWORD_OPTION = "Password";
public static final String BUFFER_OPTION = "Buffer";
+ public static final String DRIVER_OPTION = "Driver";
+ public static final String SQL_OPTION = "Sql";
+
+
+ protected String databaseURL = "jdbc:odbc:myDB";
+ protected String databaseUser = "me";
+ protected String databasePassword = "mypassword";
+ protected String databaseDriver = "sun.jdbc.odbc.JdbcOdbcDriver";
+
+
+ protected PatternLayout sqlLayout = null;
+ protected String sqlStatement = "";
+
+
protected int bufferSize = 1;
protected List buffer;
@@ -48,6 +89,9 @@
}
+ /**
+ * Adds the event to the buffer. When full the buffer is flushed.
+ */
public void append(LoggingEvent event) {
buffer.add(event);
@@ -57,69 +101,119 @@
}
- public void close() {
- flushBuffer();
- this.closed = true;
- }
-
+ /**
+ * Sets options as per the 1.0 version of Log4J option setting.
+ * all cases are forwarded to the appropriate JavaBeans Introspection set
+method.
+ * @deprecated
+ */
public void setOption(String key, String value) {
super.setOption(key, value);
+ key = key.trim();
+ value = value.trim();
+
+
+ if(key == null || value == null)
+ return;
+
+
if (key.equalsIgnoreCase(URL_OPTION))
- databaseURL = value;
+ setURL(value);
else if (key.equalsIgnoreCase(USER_OPTION))
- databaseUser = value;
+ setUser(value);
else if (key.equalsIgnoreCase(PASSWORD_OPTION))
- databasePassword = value;
+ setPassword(value);
else if (key.equalsIgnoreCase(BUFFER_OPTION))
- bufferSize = Integer.parseInt(value);
+ setBufferSize(Integer.parseInt(value));
+ else if (key.equalsIgnoreCase(DRIVER_OPTION))
+ setDriver(value);
+ else if (key.equalsIgnoreCase(SQL_OPTION))
+ setSql(value);
}
+ /** @deprecated */
+ public String[] getOptionStrings() {
+ return OptionConverter.concatanateArrays(super.getOptionStrings(),
+ new String[] {URL_OPTION, USER_OPTION, PASSWORD_OPTION, BUFFER_OPTION,
+DRIVER_OPTION});
+ }
+
+
/**
- * Override this to create the SQL needed for your DB schema
+ * By default getSQL formats the event into the provided statement using
+ * PatternLayout style conversion characters. In fact, it uses an internal
+ * PatternLayout object to do this.
+ *
+ * If a separate layout has been attached to the appender then the first
+ * instance of "%m" in the sql statement will be replaced with the output
+ * from that layout's format(LoggingEvent) method.
+ *
+ *
+ * Overriding this provides direct access to the LoggingEvent
+ * when constructing the logging statement.
+ *
+ * In hind-sight I should have given this a more different name from the
+setSql, getSql
+ * property methods.
*/
protected String getSQL(LoggingEvent event) {
- String msg = this.layout.format(event);
- String sql = "spLog '" + msg + "'";
- return sql;
- }
+ if (getLayout() != null) {
+ String msg = this.layout.format(event);
+ String _sql = getSql();
+ return _sql.substring(0, _sql.indexOf("%m")) + msg +
+_sql.substring(_sql.indexOf("%m") + 2, _sql.length());
+ } else
+ return sqlLayout.format(event);
- /**
- * Override this to provide an alertnate method of getting
- * connections (such as caching) This implementation creates a new
- * connection and statement for every execution which is very
- * wastefull. One method to fix this is to open connections at
- * the start of flushBuffer() and close them at the end. MD Data
- * uses a connection pool outside of JDBCAppender which is
- * accessed in the override of this method.
-
-
- */
- protected void executeSQL(String sql) throws SQLException {
- Connection con = null;
- Statement stmt = null;
+ }
- try {
- con = DriverManager.getConnection(databaseURL, databaseUser,
- databasePassword);
- stmt = con.createStatement();
- stmt.executeUpdate(sql);
- } catch (SQLException e) {
- if (con != null)
- con.close();
- if (stmt != null)
- stmt.close();
- throw e;
- }
- stmt.close();
- con.close();
+
+ /**
+ * By default this method creates a new connection for each
+ * statement executed.
+ *
+ * Override this to provide an alertnate method of getting
+ * connections (such as caching). One method to fix this is to open
+ * connections at the start of flushBuffer() and close them at the
+ * end. I use a connection pool outside of JDBCAppender which is
+ * accessed in an override of this method.
+ * */
+ protected void executeSQL(String sql) throws SQLException {
+ Connection con = null;
+ Statement stmt = null;
+
+
+ try {
+ if (!DriverManager.getDrivers().hasMoreElements())
+ setDriver(databaseDriver);
+
+
+ con = DriverManager.getConnection(databaseURL, databaseUser,
+ databasePassword);
+ stmt = con.createStatement();
+ stmt.executeUpdate(sql);
+ } catch (SQLException e) {
+ if (con != null)
+ con.close();
+ if (stmt != null)
+ stmt.close();
+ throw e;
}
+ stmt.close();
+ con.close();
+ }
+ /**
+ * loops through the buffer of LoggingEvents, gets a
+ * sql string from getSQL() and sends it to
+ * executeSQL()
+ */
public void flushBuffer() {
//Do the actual logging
for (Iterator i = buffer.iterator(); i.hasNext();) {
@@ -134,17 +228,104 @@
}
buffer.clear();
}
-
-
+
+
+ /** closes the appender, flushing the buffer first */
+ public void close() {
+ flushBuffer();
+ this.closed = true;
+ }
+
+
+ /** closes the appender before disposal */
public void finalize() {
close();
}
+
+
+ /**
+ * JDBCAppender has a built in layout.
+ * a separate layout can be attached if needed.
+ */
+ public boolean requiresLayout() {
+ return false;
+ }
- public boolean requiresLayout() {
- return true;
+ public void setSql(String s) {
+ sqlStatement = s;
+ if (getLayout() == null) {
+ if (sqlLayout == null)
+ sqlLayout = new PatternLayout(s);
+ else
+ sqlLayout.setConversionPattern(s);
+ }
+ }
+
+
+ public String getSql() {
+ return sqlStatement;
+ }
+
+
+ public void setUser(String user) {
+ databaseUser = user;
+ }
+
+
+ public void setURL(String url) {
+ databaseURL = url;
}
+ public void setPassword(String password) {
+ databasePassword = password;
+ }
+
+
+ public void setBufferSize(int buffer) {
+ bufferSize = buffer;
+ }
+
+
+ public String getUser() {
+ return databaseUser;
+ }
+
+
+ public String getURL() {
+ return databaseURL;
+ }
+
+
+ public String getPassword() {
+ return databasePassword;
+ }
+
+
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+
+ public void setDriver(String driverClass) {
+ databaseDriver = driverClass;
+ try {
+ Class.forName(databaseDriver);
+ } catch (Exception e) {
+ errorHandler.error("Failed to load driver", e,
+ ErrorCode.GENERIC_FAILURE);
+ }
+ }
+
+
+ /**
+ * Returns whatever driver JDBCAppender was last told to load.
+ * If a driver was loaded elsewhere in the program this may not
+ * be meaningful.
+ */
+ public String getDriver() {
+ return databaseDriver;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-cvs-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-cvs-help@jakarta.apache.org