o
增加配置:
增加java类:
public class AccessLogFactory {
private static final String ACCESSLOG_CATEGORY = "accesslog_category";
static {
DOMConfigurator.configure("./resource/log4j.xml");
}
public static Log getLog() {
Log logger = null;
try {
logger = LogFactory.getLog(ACCESSLOG_CATEGORY);
} catch (LogConfigurationException e) {
e.printStackTrace();
}
return logger;
}
}
增加java类:
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton {
/**
* URL of the DB for default connection handling
*/
protected String databaseURL = "jdbc:odbc:myDB";
/**
* User to connect as for default connection handling
*/
protected String databaseUser = "me";
/**
* User to use for default connection handling
*/
protected String databasePassword = "mypassword";
/**
* Connection used by default. The connection is opened the first time it is
* needed and then held open until the appender is closed (usually at
* garbage collection). This behavior is best modified by creating a
* sub-class and overriding the getConnection
and
* closeConnection
methods.
*/
protected Connection connection = null;
/**
* Stores the string given to the pattern layout for conversion into a SQL
* statement, eg: insert into LogTable (Thread, Class, Message) values
* ("%t", "%c", "%m").
*
* Be careful of quotes in your messages!
*
* Also see PatternLayout.
*/
protected String sqlStatement = "";
/**
* size of LoggingEvent buffer before writting to the database. Default is
* 1.
*/
protected int bufferSize = 1;
/**
* ArrayList holding the buffer of Logging Events.
*/
protected ArrayList buffer;
/**
* Helper object for clearing out the buffer
*/
protected ArrayList removes;
private boolean locationInfo = false;
public JDBCAppender() {
super();
buffer = new ArrayList(bufferSize);
removes = new ArrayList(bufferSize);
}
/**
* Gets whether the location of the logging request call should be captured.
*
* @since 1.2.16
* @return the current value of the LocationInfo option.
*/
public boolean getLocationInfo() {
return locationInfo;
}
/**
* The LocationInfo option takes a boolean value. By default, it is
* set to false which means there will be no effort to extract the location
* information related to the event. As a result, the event that will be
* ultimately logged will likely to contain the wrong location information
* (if present in the log format).
*
*
* Location information extraction is comparatively very slow and should be
* avoided unless performance is not a concern.
*
*
* @since 1.2.16
* @param flag
* true if location information should be extracted.
*/
public void setLocationInfo(final boolean flag) {
locationInfo = flag;
}
/**
* Adds the event to the buffer. When full the buffer is flushed.
*/
public void append(LoggingEvent event) {
event.getNDC();
event.getThreadName();
// Get a copy of this thread's MDC.
event.getMDCCopy();
if (locationInfo) {
event.getLocationInformation();
}
event.getRenderedMessage();
event.getThrowableStrRep();
buffer.add(event);
if (buffer.size() >= bufferSize) {
flushBuffer();
}
}
/**
* By default getLogStatement sends the event to the required Layout object.
* The layout will format the given pattern into a workable SQL string.
*
* Overriding this provides direct access to the LoggingEvent when
* constructing the logging statement.
*
*/
protected String getLogStatement(LoggingEvent event) {
return getLayout().format(event);
}
/**
*
* 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 execute(String sql) throws SQLException {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
stmt.executeUpdate(sql);
} finally {
if (stmt != null) {
stmt.close();
}
closeConnection(con);
}
// System.out.println("Execute: " + sql);
}
/**
* Override this to return the connection to a pool, or to clean up the
* resource.
*
* The default behavior holds a single connection open until the appender is
* closed (typically when garbage collected).
*/
protected void closeConnection(Connection con) {
}
/**
* Override this to link with your connection pooling system.
*
* By default this creates a single connection which is held open until the
* object is garbage collected.
*/
protected Connection getConnection() throws SQLException {
if (!DriverManager.getDrivers().hasMoreElements()) {
setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
}
if (connection == null) {
connection = DriverManager.getConnection(databaseURL, databaseUser, databasePassword);
}
return connection;
}
/**
* Closes the appender, flushing the buffer first then closing the default
* connection if it is open.
*/
public void close() {
flushBuffer();
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
}
this.closed = true;
}
/**
* loops through the buffer of LoggingEvents, gets a sql string from
* getLogStatement() and sends it to execute(). Errors are sent to the
* errorHandler.
*
* If a statement fails the LoggingEvent stays in the buffer!
*/
public void flushBuffer() {
// Do the actual logging
removes.ensureCapacity(buffer.size());
for (Iterator i = buffer.iterator(); i.hasNext();) {
LoggingEvent logEvent = (LoggingEvent) i.next();
try {
Connection con = getConnection();
PreparedStatement stmt = con.prepareStatement(getSql());
stmt.setString(1, DateUtil.formatCurDate().concat(DateUtil.formatCurTime()));
stmt.setString(2, logEvent.getThreadName());
stmt.setString(3, logEvent.getLevel().toString());
stmt.setString(4, logEvent.getLoggerName());
stmt.setString(5, logEvent.getMessage().toString());
stmt.executeUpdate();
} catch (SQLException e) {
errorHandler.error("Failed to excute sql", e, ErrorCode.FLUSH_FAILURE);
} finally {
removes.add(logEvent);
}
}
// remove from the buffer any events that were reported
buffer.removeAll(removes);
// clear the buffer of reported events
removes.clear();
}
/** closes the appender before disposal */
public void finalize() {
close();
}
/**
* JDBCAppender requires a layout.
*/
public boolean requiresLayout() {
return true;
}
/**
*
*/
public void setSql(String sql) {
sqlStatement = sql;
if (getLayout() == null) {
this.setLayout(new PatternLayout(sql));
} else {
((PatternLayout) getLayout()).setConversionPattern(sql);
}
}
/**
* Returns pre-formated statement eg: insert into LogTable (msg) values
* ("%m")
*/
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 newBufferSize) {
bufferSize = newBufferSize;
buffer.ensureCapacity(bufferSize);
removes.ensureCapacity(bufferSize);
}
public String getUser() {
return databaseUser;
}
public String getURL() {
return databaseURL;
}
public String getPassword() {
return databasePassword;
}
public int getBufferSize() {
return bufferSize;
}
/**
* Ensures that the given driver class has been loaded for sql connection
* creation.
*/
public void setDriver(String driverClass) {
try {
Class.forName(driverClass);
} catch (Exception e) {
errorHandler.error("Failed to load driver", e, ErrorCode.GENERIC_FAILURE);
}
}
}
增加表:
create table T_LOG
(
currtime VARCHAR2(20) not null,
currthread CHAR(100),
currlevel CHAR(10),
currcode CHAR(20),
currmsg CHAR(200)
)
调用:
Log logger = AccessLogFactory.getLog();
logger.debug("XXXX")