You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by ce...@apache.org on 2004/05/04 11:36:03 UTC
cvs commit: logging-log4j/src/java/org/apache/log4j/db/dialect postgresql.sql MySQLDialect.java mysql.sql oracle.sql SQLDialect.java PostgreSQLDialect.java
ceki 2004/05/04 02:36:03
Added: src/java/org/apache/log4j/db UrlConnectionSource.java
ConnectionSource.java DBAppender.java
JNDIConnectionSource.java
ConnectionSourceSkeleton.java
src/java/org/apache/log4j/db/dialect postgresql.sql
MySQLDialect.java mysql.sql oracle.sql
SQLDialect.java PostgreSQLDialect.java
Log:
An initial draft of DBAppender. It seems to work on MySQL and PostgreSQL using the URLConnectionSource
Revision Changes Path
1.1 logging-log4j/src/java/org/apache/log4j/db/UrlConnectionSource.java
Index: UrlConnectionSource.java
===================================================================
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.log4j.spi.ErrorCode;
/**
* The UrlConnectionSource is an implementation of {@link ConnectionSource}
* that obtains the Connection in the traditional JDBC manner based on the
* connection URL.
* <p>
* Note that this class will establish a new Connection for each call to
* {@link #getConnection()}. It is recommended that you either use a JDBC
* driver that natively supported Connection pooling or that you create
* your own implementation of {@link ConnectionSource} that taps into whatever
* pooling mechanism you are already using. (If you have access to a JNDI
* implementation that supports {@link javax.sql.DataSource}s, e.g. within
* a J2EE application server, see {@link JNDIConnectionSource}). See
* <a href="#dbcp">below</a> for a configuration example that uses the
* <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
* package from Apache.
* <p>
* Sample configuration:<br>
* <pre>
* <connectionSource class="org.apache.log4j.jdbc.UrlConnectionSource">
* <param name="driver" value="com.mysql.jdbc.Driver" />
* <param name="url" value="jdbc:mysql://localhost:3306/mydb" />
* <param name="username" value="myUser" />
* <param name="password" value="myPassword" />
* </connectionSource>
* </pre>
* <p>
* <a name="dbcp">If</a> you do not have another connection pooling mechanism
* built into your application, you can use the
* <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
* package from Apache:<br>
* <pre>
* <connectionSource class="org.apache.log4j.jdbc.UrlConnectionSource">
* <param name="driver" value="org.apache.commons.dbcp.PoolingDriver" />
* <param name="url" value="jdbc:apache:commons:dbcp:/myPoolingDriver" />
* </connectionSource>
* </pre>
* Then the configuration information for the commons-dbcp package goes into
* the file myPoolingDriver.jocl and is placed in the classpath. See the
* <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
* documentation for details.
*
* @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
*/
public class UrlConnectionSource
extends ConnectionSourceSkeleton {
static private final String POSTGRES_PART = "postgresql";
static private final String MYSQL_PART = "mysql";
private String driverClass = null;
protected String url = null;
public void activateOptions() {
try {
if (driverClass != null) {
Class.forName(driverClass);
} else if (errorHandler != null) {
errorHandler.error("WARNING: No JDBC driver specified for log4j " + "UrlConnectionSource.");
}
} catch (final ClassNotFoundException cnfe) {
if (errorHandler != null) {
errorHandler.error("Could not load JDBC driver class: " + driverClass, cnfe, ErrorCode.GENERIC_FAILURE);
} else {
cnfe.printStackTrace();
}
}
}
/**
* @see org.apache.log4j.db.ConnectionSource#getConnection()
*/
public Connection getConnection()
throws SQLException {
if (user == null) {
return DriverManager.getConnection(url);
} else {
return DriverManager.getConnection(url, user, password);
}
}
/**
* Returns the url.
* @return String
*/
public String getUrl() {
return url;
}
/**
* Sets the url.
* @param url The url to set
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Returns the name of the driver class.
* @return String
*/
public String getDriverClass() {
return driverClass;
}
/**
* Sets the driver class.
* @param driver The driver to set
*/
public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
}
public int getSQLDialect() {
int dialectCode = 0;
if (url == null) {
return ConnectionSource.UNKNOWN_DIALECT;
}
if (url.indexOf(POSTGRES_PART) != -1) {
return ConnectionSource.POSTGRES_DIALECT;
} else if (url.indexOf(MYSQL_PART) != -1) {
return ConnectionSource.MYSQL_DIALECT;
} else {
return ConnectionSource.UNKNOWN_DIALECT;
}
}
}
1.1 logging-log4j/src/java/org/apache/log4j/db/ConnectionSource.java
Index: ConnectionSource.java
===================================================================
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.db;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.OptionHandler;
import java.sql.Connection;
import java.sql.SQLException;
/**
* The <id>ConnectionSource</id> interface provides a pluggable means of
* transparently obtaining JDBC {@link java.sql.Connection}s for log4j classes
* that require the use of a {@link java.sql.Connection}.
*
* @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
*/
public interface ConnectionSource extends OptionHandler {
final int UNKNOWN_DIALECT = 0;
final int POSTGRES_DIALECT = 1;
final int MYSQL_DIALECT = 2;
/**
* Obtain a {@link java.sql.Connection} for use. The client is
* responsible for closing the {@link java.sql.Connection} when it is no
* longer required.
*
* @throws SQLException if a {@link java.sql.Connection} could not be
* obtained
*/
Connection getConnection() throws SQLException;
/**
* Set the error handler.
*
* @param errorHandler the new error handler
*/
void setErrorHandler(ErrorHandler errorHandler);
/**
*
* Get the SQL dialect that should be used for this connection.
*
*/
int getSQLDialect();
}
1.1 logging-log4j/src/java/org/apache/log4j/db/DBAppender.java
Index: DBAppender.java
===================================================================
package org.apache.log4j.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
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 org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.db.dialect.MySQLDialect;
import org.apache.log4j.db.dialect.PostgreSQLDialect;
import org.apache.log4j.db.dialect.SQLDialect;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
/**
*
* @author Ceki Gülcü
*
*/
public class DBAppender
extends AppenderSkeleton {
ConnectionSource connectionSource;
SQLDialect sqlDialect;
public void activateOptions() {
if (connectionSource != null) {
connectionSource.activateOptions();
} else {
throw new IllegalStateException("DBAppender cannot function without a connection source");
}
switch (connectionSource.getSQLDialect()) {
case ConnectionSource.POSTGRES_DIALECT :
sqlDialect = new PostgreSQLDialect();
break;
case ConnectionSource.MYSQL_DIALECT :
sqlDialect = new MySQLDialect();
break;
}
}
/**
* @return Returns the connectionSource.
*/
public ConnectionSource getConnectionSource() {
return connectionSource;
}
/**
* @param connectionSource The connectionSource to set.
*/
public void setConnectionSource(ConnectionSource connectionSource) {
this.connectionSource = connectionSource;
}
protected void append(LoggingEvent event) {
try {
Connection connection = connectionSource.getConnection();
connection.setAutoCommit(false);
// sequence_number BIGINT NOT NULL,
// timestamp BIGINT NOT NULL,
// rendered_message TEXT NOT NULL,
// logger_name VARCHAR(254) NOT NULL,
// ndc TEXT,
// thread_name VARCHAR(254),
// id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
StringBuffer sql = new StringBuffer();
sql.append("INSERT INTO logging_event (");
sql.append("sequence_number, timestamp, rendered_message, ");
sql.append("logger_name, ndc, thread_name) ");
sql.append(" VALUES (?, ?, ? ,?, ?, ?)");
PreparedStatement insertStatement = connection.prepareStatement(sql.toString());
insertStatement.setLong(1, event.getSequenceNumber());
insertStatement.setLong(2, event.getTimeStamp());
insertStatement.setString(3, event.getRenderedMessage());
insertStatement.setString(4, event.getLoggerName());
insertStatement.setString(5, event.getNDC());
insertStatement.setString(6, event.getThreadName());
int updateCount = insertStatement.executeUpdate();
if (updateCount != 1) {
LogLog.warn("Failed to insert loggingEvent");
}
Statement idStatement = connection.createStatement();
idStatement.setMaxRows(1);
ResultSet rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
rs.first();
int eventId = rs.getInt(1);
LogLog.info("inserted id is " + eventId);
// event_id INT NOT NULL,
// mapped_key VARCHAR(254) NOT NULL,
// mapped_value VARCHAR(254),
Set mdcKeys = event.getMDCKeySet();
if (mdcKeys.size() > 0) {
String insertMDCSQL = "INSERT INTO mdc (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)";
PreparedStatement insertMDCStatement = connection.prepareStatement(insertMDCSQL);
for (Iterator i = mdcKeys.iterator(); i.hasNext();) {
String key = (String)i.next();
String value = (String)event.getMDC(key);
LogLog.debug("id " + eventId + ", key " + key + ", value " + value);
insertMDCStatement.setInt(1, eventId);
insertMDCStatement.setString(2, key);
insertMDCStatement.setString(3, value);
insertMDCStatement.addBatch();
}
insertMDCStatement.executeBatch();
}
connection.commit();
} catch (SQLException sqle) {
LogLog.error("problem appending event", sqle);
}
}
public void close() {
// TODO Auto-generated method st
}
/*
* The DBAppender does not require a layout.
*/
public boolean requiresLayout() {
return false;
}
}
1.1 logging-log4j/src/java/org/apache/log4j/db/JNDIConnectionSource.java
Index: JNDIConnectionSource.java
===================================================================
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.db;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.sql.DataSource;
/**
* The <id>JNDIConnectionSource</id> is an implementation of
* {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a
* JNDI provider and uses it to obtain a {@link java.sql.Connection}. It is
* primarily designed to be used inside of J2EE application servers or
* application server clients, assuming the application server supports remote
* access of {@link javax.sql.DataSource}s. In this way one can take
* advantage of connection pooling and whatever other goodies the application
* server provides.
* <p>
* Sample configuration:<br>
* <pre>
* <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
* <param name="jndiLocation" value="jdbc/MySQLDS" />
* </connectionSource>
* </pre>
* <p>
* Sample configuration (with username and password):<br>
* <pre>
* <connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource">
* <param name="jndiLocation" value="jdbc/MySQLDS" />
* <param name="username" value="myUser" />
* <param name="password" value="myPassword" />
* </connectionSource>
* </pre>
* <p>
* Note that this class will obtain an {@link javax.naming.InitialContext}
* using the no-argument constructor. This will usually work when executing
* within a J2EE environment. When outside the J2EE environment, make sure
* that you provide a jndi.properties file as described by your JNDI
* provider's documentation.
*
* @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
*/
public class JNDIConnectionSource
extends ConnectionSourceSkeleton {
private String jndiLocation = null;
private DataSource dataSource = null;
/**
* @see org.apache.log4j.db.ConnectionSource#getConnection()
*/
public Connection getConnection()
throws SQLException {
Connection conn = null;
try {
if(dataSource == null) {
dataSource = lookupDataSource();
}
if (user == null) {
conn = dataSource.getConnection();
} else {
conn = dataSource.getConnection(user, password);
}
} catch (final NamingException ne) {
if (errorHandler != null) {
errorHandler.error(ne.getMessage(), ne, 0);
}
throw new SQLException("NamingException while looking up DataSource: " + ne.getMessage());
} catch (final ClassCastException cce) {
if (errorHandler != null) {
errorHandler.error(cce.getMessage(), cce, 0);
}
throw new SQLException("ClassCastException while looking up DataSource: " + cce.getMessage());
}
return conn;
}
/**
* @see org.apache.log4j.spi.OptionHandler#activateOptions()
*/
public void activateOptions() {
if (jndiLocation == null && errorHandler != null) {
errorHandler.error("No JNDI location specified for JNDIConnectionSource.");
}
}
/**
* Returns the jndiLocation.
* @return String
*/
public String getJndiLocation() {
return jndiLocation;
}
/**
* Sets the jndiLocation.
* @param jndiLocation The jndiLocation to set
*/
public void setJndiLocation(String jndiLocation) {
this.jndiLocation = jndiLocation;
}
/**
* Sets the password.
* @param password The password to set
*/
public void setPassword(String password) {
this.password = password;
}
public int getSQLDialect() {
return 0;
}
private DataSource lookupDataSource()
throws NamingException, SQLException {
DataSource ds;
Context ctx = new InitialContext();
Object obj = ctx.lookup(jndiLocation);
ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class);
if (ds == null) {
throw new SQLException("Failed to obtain data source from JNDI location " + jndiLocation);
} else {
return ds;
}
}
}
1.1 logging-log4j/src/java/org/apache/log4j/db/ConnectionSourceSkeleton.java
Index: ConnectionSourceSkeleton.java
===================================================================
package org.apache.log4j.db;
import org.apache.log4j.spi.ErrorHandler;
/**
* @author Ceki Gülcü
*/
abstract public class ConnectionSourceSkeleton
implements ConnectionSource {
protected String user = null;
protected String password = null;
protected ErrorHandler errorHandler = null;
/**
* Get teh errorHandler for this connection source
*/
public ErrorHandler getErrorHandler() {
return errorHandler;
}
/**
* Sets the error handler.
* @param errorHandler the error handler to set
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
/**
* Get the password for this connection source.
*/
public String getPassword() {
return password;
}
/**
* Sets the password.
* @param password The password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Get the user for this connection source.
*/
public String getUser() {
return user;
}
/**
* Sets the username.
* @param username The username to set
*/
public void setUser(String username) {
this.user = username;
}
}
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/postgresql.sql
Index: postgresql.sql
===================================================================
DROP TABLE mdc;
DROP TABLE logging_event;
DROP SEQUENCE logging_event_id_seq;
CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1;
CREATE TABLE logging_event
(
sequence_number BIGINT NOT NULL,
timestamp BIGINT NOT NULL,
rendered_message TEXT NOT NULL,
logger_name VARCHAR(254) NOT NULL,
ndc TEXT,
thread_name VARCHAR(254),
id INT DEFAULT nextval('logging_event_id_seq') PRIMARY KEY
);
CREATE TABLE mdc
(
event_id INT NOT NULL,
mapped_key VARCHAR(254) NOT NULL,
mapped_value VARCHAR(254),
PRIMARY KEY(event_id, mapped_key),
FOREIGN KEY (event_id) REFERENCES logging_event(id)
);
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/MySQLDialect.java
Index: MySQLDialect.java
===================================================================
package org.apache.log4j.db.dialect;
/**
*
*
* @author Ceki
*
*/
public class MySQLDialect implements SQLDialect {
public static final String SELECT_LAST_INSERT_ID = "SELECT LAST_INSERT_ID()";
public String getSelectInsertId() {
return SELECT_LAST_INSERT_ID;
}
}
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/mysql.sql
Index: mysql.sql
===================================================================
BEGIN;
DROP TABLE IF EXISTS loggging_event;
DROP TABLE IF EXISTS mdc;
COMMIT;
BEGIN;
CREATE TABLE logging_event
(
sequence_number BIGINT NOT NULL,
timestamp BIGINT NOT NULL,
rendered_message TEXT NOT NULL,
logger_name VARCHAR(254) NOT NULL,
ndc TEXT,
thread_name VARCHAR(254),
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
COMMIT;
BEGIN;
CREATE TABLE mdc
(
event_id INT NOT NULL,
mapped_key VARCHAR(254) NOT NULL,
mapped_value VARCHAR(254),
PRIMARY KEY(event_id, mapped_key),
FOREIGN KEY (event_id) REFERENCES logging_event(id)
);
COMMIT;
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/oracle.sql
Index: oracle.sql
===================================================================
CREATE SEQUENCE event_id_seq;
CREATE OR REPLACE TRIGGER event_id_seq_trig
BEFORE INSERT ON logging_event
FOR EACH ROW
BEGIN
SELECT logging_event_seq.NEXTVAL
INTO :NEW.id
FROM DUAL;
END event_id_seq_trig;
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/SQLDialect.java
Index: SQLDialect.java
===================================================================
package org.apache.log4j.db.dialect;
/**
* @author ceki
*
*/
public interface SQLDialect {
public String getSelectInsertId();
}
1.1 logging-log4j/src/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java
Index: PostgreSQLDialect.java
===================================================================
/*
* Created on May 4, 2004
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.apache.log4j.db.dialect;
/**
* @author ceki
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class PostgreSQLDialect
implements SQLDialect {
public static final String SELECT_CURRVAL = "SELECT currval('logging_event_id_seq')";
public String getSelectInsertId() {
return SELECT_CURRVAL;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org