Tip. SQL문을 로그로 남기기

Query 서비스를 통해 수행되는 SQL을 로그로 남기기 위해서는 log4jdbc(http://log4jdbc.sourceforge.net/)라는 오픈소스를 활용할 수 있다. log4jdbc는 JDBC 호출이나 SQL문에 대해 로그를 남길 수 있는 JDBC Driver로, log4jdbc에서 Driver에 대한 Wrapper는 제공하나, DataSource에 대한 Wrapper를 제공하지 않으므로 첨부 AnyFrameDataSourceSpy.java 와 같이 별도 Wrapper를 사용해야 한다. 다음에서는 DataSurceSpy.java를 사용하여 SQL을 로그로 남기기 위한 절차이다. 보다 자세한 내용은 log4jdbc 사이트(http://log4jdbc.sourceforge.net/)를 참조한다.

SQL문을 로그로 남기기

Step 1 : Log4jdbc 라이브러리 다운로드

다음을 참고하여, 필요한 log4jdbcX-1.1alpha2.jar 파일을 다운로드한 후, [Anyframe Core 설치 폴더]내에 복사한다.
파일명
설명
다운로드
log4jdbc3-1.1alpha2.jar If you are using JDK 1.4 or 1.5, you should use the JDBC 3 version of log4jdbc.
Download
log4jdbc4-1.1alpha2.jar If you are using JDK 1.6 or 1.7, you should use the JDBC 4 version of log4jdbc
(even if the actual underlying JDBC driver you are using is a JDBC 3 or older driver).
Download

Step 2 : Simple Logging Facade for Java 라이브러리 다운로드

log4jdbc는 Simple Logging Facade for Java (SLF4J)를 이용하여 어플리케이션에서 사용하는 Logging 서비스와 유연하게 연동할 수 있도록 하고 있다. 따라서 다음 파일들을 다운로드한 후, [Anyframe Core 설치 폴더] 내에 복사한다.
파일명
설명
다운로드
slf4j-api-1.4.3.jar log4jdbc와 logging 서비스 연동을 위한 API 제공
Download
slf4j-log4j12-1.4.3.jar log4jdbc와 Log4j 기반의 Logging 서비스 연동을 위한 구현 라이브러리 제공
Download

Step 3 : AnyFrameDataSourceSpy.java 생성 및 컴파일

다음과 같이 패키지 net.sf.log4jdbc에 속한 클래스 AnyFrameDataSourceSpy.java를 다운로드하고 컴파일한 후, [Anyframe Core 설치 폴더]classes 내에 저장한다. 컴파일시 log4jdbcX-1.1alpha2.jar 파일이 클래스패스 내에 존재해야 함에 유의하도록 한다. 다음은 AnyFrameDataSourceSpy.java의 코드 일부이다.
package net.sf.log4jdbc;

// 중략
public class AnyFrameDataSourceSpy implements DataSource {

	// 중략

	public Connection getConnection() throws SQLException {
		return getWrappedConnection(dataSource.getConnection());
	}

	public Connection getConnection(String username, String password) throws SQLException {
		return getWrappedConnection(dataSource.getConnection(username, password));
	}

	public PrintWriter getLogWriter() throws SQLException {
		return dataSource.getLogWriter();
	}

	public int getLoginTimeout() throws SQLException {
		return dataSource.getLoginTimeout();
	}

	public void setLogWriter(PrintWriter out) throws SQLException {
		dataSource.setLogWriter(out);
	}

	public void setLoginTimeout(int seconds) throws SQLException {
		dataSource.setLoginTimeout(seconds);
	}

	private Connection getWrappedConnection(Connection con) {
		if (log.isJdbcLoggingEnabled()) {
			ConnectionSpy cspy = new ConnectionSpy(con);
			cspy.setRdbmsSpecifics(defaultRdbmsSpecifics);
			return cspy;
		} else {
			return con;
		}
	}
}

Step 4 : DataSource 서비스 속성 정의 파일 정의

앞서 정의한 AnyFrameDataSourceSpy를 통해 DataSource 서비스가 실행될 수 있도록 다음을 참조하여 applicationContext-datasource.xml 파일을 정의한다.
<bean id="common_datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
	<property name="url" value="jdbc:hsqldb:file:/./DATABASE/db/sampledb"/>
	<property name="username" value="sa"/>
</bean> 

<bean id="dataSource" class="net.sf.log4jdbc.AnyFrameDataSourceSpy">
	<property name="dataSource" ref="common_datasource"/>
</bean>

Step 5 : Query 서비스 속성 정의 파일 정의

Query 서비스에서 참조하는 DataSource 서비스를 앞서 정의한 AnyFrameDataSourceSpy 클래스의 Bean Id로 정의한다. 다음은 Query 서비스 속성을 정의한 샘플 applicationContext-query.xml 파일의 일부 내용이다.
<bean name="queryService" class="anyframe.core.query.impl.QueryServiceImpl">
	<property name="jdbcTemplate">
		<ref bean="jdbcTemplate"/>
	</property>		
	<config:configuration>
		<filename>classpath:mappings/emp-user-userservice-mapping.xml</filename>
		<nullcheck type="VARCHAR" default-value=""/>
		<sqlload dynamic="false" frequency="5"/>
		<skiperror>true</skiperror>
	</config:configuration>					
</bean>

<bean id="jdbcTemplate" class="anyframe.core.query.impl.util.PagingJdbcTemplate">
	<property name="dataSource" ref="dataSource" />
</bean>

Step 6 : Logger 정의

lo4jdbc를 사용하여 로그를 남기기 위해서는 log4j.xml 파일 내에 다음을 참고하여, 필요한 Logger를 정의하도록 한다.
  • jdbc.sqlonly :
  • SQL문만을 로그로 남기며, PreparedStatement일 경우 관련된 argument 값으로 대체된 SQL문이 보여진다.
  • jdbc.sqltiming :
  • SQL문과 해당 SQL을 실행시키는데 수행된 시간 정보(milliseconds)를 포함한다.
  • jdbc.audit :
  • ResultSet을 제외한 모든 JDBC 호출 정보를 로그로 남긴다. 많은 양의 로그가 생성되므로 특별히 JDBC 문제를 추적해야 할 필요가 있는 경우를 제외하고는 사용을 권장하지 않는다.
  • jdbc.resultset :
  • ResultSet을 포함한 모든 JDBC 호출 정보를 로그로 남기므로 매우 방대한 양의 로그가 생성된다.

또한, 각 Logger에 대한 로그 레벨은 DEBUG, INFO, ERROR 중 하나를 선택할 수 있다.
  • DEBUG - SQL이 실행된 클래스명과 Line 번호를 로그로 남긴다.
  • INFO - SQL문을 로그로 남긴다.
  • ERROR - SQL 실행 에러가 발생한 경우 stack trace 정보를 로그로 남긴다.

Resources