package egovframework.rte.fdl.logging;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.MDC;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;
import org.springframework.transaction.annotation.Transactional;
import egovframework.rte.fdl.logging.util.LogFileUtil;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:META-INF/spring/context-common.xml",
"classpath*:META-INF/spring/context-datasource.xml",
"classpath*:META-INF/spring/context-transaction.xml",
"classpath*:META-INF/spring/context-jndi-jeus.xml" })
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = false)
@Transactional
public class AdvancedLogTargetTest {
@Resource(name = "dataSource")
DataSource dataSource;
@Resource(name = "jdbcProperties")
Properties jdbcProperties;
boolean isHsql = true;
boolean isOracle = false;
boolean isMysql = false;
// @SuppressWarnings("unchecked")
// @AfterClass
// public static void deleteAllLogFiles() throws InterruptedException {
//
// // 테스트 케이스가 종료할 때 생성한 모든 로그 파일을 삭제함.
// // log4j 에서 로그 파일에 대한 lock 을 잡고 있기 때문에 모든 appender 의 close() 를 실행하여
// resource 해제 필요
// Enumeration<Logger> loggers = LogManager.getCurrentLoggers();
// while (loggers.hasMoreElements()) {
// Logger logger = loggers.nextElement();
// Enumeration<Appender> appenders = logger.getAllAppenders();
// while (appenders.hasMoreElements()) {
// Appender appender = appenders.nextElement();
// appender.close();
// }
// }
//
// // 모든 로그 파일 삭제
// File logDir = new File("./logs");
// for (File tempDir : logDir.listFiles()) {
// for (File tempFile : tempDir.listFiles()) {
// //assertTrue(tempFile.delete());
// tempFile.delete();
// }
// }
// }
@Before
public void onSetUp() throws Exception {
isHsql = "hsql".equals(jdbcProperties.getProperty("usingDBMS"));
isMysql = "mysql".equals(jdbcProperties.getProperty("usingDBMS"));
isOracle = "oracle".equals(jdbcProperties.getProperty("usingDBMS"));
if (isHsql) {
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(
dataSource), new ClassPathResource(
"META-INF/testdata/dialect/hsqldb.sql"), true);
} else if (isMysql) {
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(
dataSource), new ClassPathResource(
"META-INF/testdata/dialect/mysql.sql"), true);
} else if (isOracle) {
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(
dataSource), new ClassPathResource(
"META-INF/testdata/dialect/oracle.sql"), true);
SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);
StringBuffer callableStmt = new StringBuffer();
callableStmt
.append(" CREATE OR REPLACE TRIGGER logging_event_id_seq_trig \n");
callableStmt.append(" BEFORE INSERT ON logging_event \n");
callableStmt.append(" FOR EACH ROW \n");
callableStmt.append(" BEGIN \n");
callableStmt.append(" SELECT logging_event_id_seq.NEXTVAL \n");
callableStmt.append(" INTO :NEW.event_id \n");
callableStmt.append(" FROM DUAL; \n");
callableStmt.append(" END logging_event_id_seq_trig; \n");
jdbcTemplate.getJdbcOperations().execute(callableStmt.toString());
} else {
// TODO
LogFactory.getLog("sysoutLogger").debug(
jdbcProperties.getProperty("usingDBMS")
+ " currently not supported!");
}
}
@Test
public void testDBAppender() throws Exception {
// db 로 설정되어 있는 로거
Log log = null;
if (isOracle) {
// Oracle 인 경우 getGeneratedKeys 를 사용하지 않는 형태로 확장한
// DBAppender(EgovDBAppender) 사용
log = LogFactory.getLog("egovDBLogger");
} else {
log = LogFactory.getLog("dbLogger");
}
// 로그 기록
log.debug("DBAppender test");
// DB 확인
String sql = "select * from logging_event order by event_id desc ";
Map<String, Object> logMap = new SimpleJdbcTemplate(dataSource)
.queryForList(sql).get(0);
assertEquals(isOracle ? "egovDBLogger" : "dbLogger", logMap
.get("LOGGER_NAME"));
assertEquals("DEBUG", logMap.get("LEVEL_STRING"));
assertEquals("DBAppender test", logMap.get("RENDERED_MESSAGE"));
assertTrue(((String) logMap.get("THREAD_NAME")).contains("main"));
assertEquals("AdvancedLogTargetTest.java", logMap
.get("CALLER_FILENAME"));
assertEquals("egovframework.rte.fdl.logging.AdvancedLogTargetTest",
logMap.get("CALLER_CLASS"));
assertEquals("testDBAppender", logMap.get("CALLER_METHOD"));
// CALLER_LINE 은 CHAR(4) 로 정의되 있음 - blank 에 주의 (Oracle/Hsql 의 trim 처리가
// 다름)
String patternStr = "^[0-9]{1,4}$";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(((String) logMap.get("CALLER_LINE"))
.trim());
assertTrue(matcher.matches());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm",
java.util.Locale.getDefault());
// oracle 인 경우 Number 필드에 대한 맵핑 타입인 BigDecimal 로 돌아옴
if (isOracle) {
assertTrue(1 <= ((BigDecimal) logMap.get("EVENT_ID")).intValue());
// timestamp 필드가 NUMBER(20) 로 선언되어 있음.
// 현재 분까지만 Date 변환하여 비교
// cf.) 로그 테이블에 들어있는 timestamp 는 DB 서버의 값이 아닌 log 를 실행한 (여기서는 local
// testcase) jvm 의 시간임에 유의!
assertEquals(sdf.format(new Date()), sdf.format(new Timestamp(
((BigDecimal) logMap.get("TIMESTAMP")).longValue())));
} else {
// hsql 인 경우는 0 부터 시작됨을 확인
assertTrue((isHsql ? 0 : 1) <= (Integer) logMap.get("EVENT_ID"));
// timestamp 필드가 BIGINT 로 선언되어 있음 -> Long
assertEquals(sdf.format(new Date()), sdf.format(new Timestamp(
(Long) logMap.get("TIMESTAMP"))));
}
}
// EgovJDBCAppender 는 내부에 SingletonDataSourceProvider 의 singleton 인스턴스를 가지고
// 있으며
// SingletonDataSourceProvider 의 dataSource 를 Spring 의 Annotation 형태의
// EgovJDBCAppender bean 생성 시
// injection 해 주도록 하였음. (log4j 에서 생성하는 EgovJDBCAppender 와 Spring 에서 생성하는
// EgovJDBCAppender bean 은
// 서로 다르나 내부의 SingletonDataSourceProvider 는 같음!
// EgovJDBCAppender 에서 DB 접속/해제 와 관련한 로직은 SingletonDataSourceProvider 의
// dataSource 를 사용하게 함.
@Test
public void testEgovJDBCAppender() throws Exception {
// pooledDB 로 설정되어 있는 로거
Log log = LogFactory.getLog("pooledDBLogger");
// 로그 기록
log.debug("EgovJDBCAppender test");
// DB 확인
String sql = "select * from logging_event order by event_id desc ";
Map<String, Object> logMap = new SimpleJdbcTemplate(dataSource)
.queryForList(sql).get(0);
assertEquals("pooledDBLogger", logMap.get("LOGGER_NAME"));
assertEquals("DEBUG", logMap.get("LEVEL_STRING"));
assertEquals("EgovJDBCAppender test", logMap.get("RENDERED_MESSAGE"));
assertTrue(((String) logMap.get("THREAD_NAME")).contains("main"));
assertEquals("AdvancedLogTargetTest.java", logMap
.get("CALLER_FILENAME"));
assertEquals("egovframework.rte.fdl.logging.AdvancedLogTargetTest",
logMap.get("CALLER_CLASS"));
assertEquals("testEgovJDBCAppender", logMap.get("CALLER_METHOD"));
// CALLER_LINE 은 CHAR(4) 로 정의되 있음 - blank 에 주의 (Oracle/Hsql 의 trim 처리가
// 다름)
String patternStr = "^[0-9]{1,4}$";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(((String) logMap.get("CALLER_LINE"))
.trim());
assertTrue(matcher.matches());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm",
java.util.Locale.getDefault());
// oracle 인 경우 Number 필드에 대한 맵핑 타입인 BigDecimal 로 돌아옴
if (isOracle) {
assertTrue(1 <= ((BigDecimal) logMap.get("EVENT_ID")).intValue());
// timestamp 필드가 NUMBER(20) 로 선언되어 있음.
// 현재 분까지만 Date 변환하여 비교
// cf.) 로그 테이블에 들어있는 timestamp 는 DB 서버의 값이 아닌 log 를 실행한 (여기서는 local
// testcase) jvm 의 시간임에 유의!
assertEquals(sdf.format(new Date()), sdf.format(new Timestamp(
((BigDecimal) logMap.get("TIMESTAMP")).longValue())));
} else {
// hsql 인 경우는 0 부터 시작됨을 확인
assertTrue((isHsql ? 0 : 1) <= (Integer) logMap.get("EVENT_ID"));
// timestamp 필드가 BIGINT 로 선언되어 있음 -> Long
assertEquals(sdf.format(new Date()), sdf.format(new Timestamp(
(Long) logMap.get("TIMESTAMP"))));
}
}
@Test
public void testJMSAppender() throws Exception {
// console 로 설정되어 있는 로거
Log log = LogFactory.getLog("jmsLogger");
// jms 메시지에 담을 추가 정보 - 보통 로그인 사용자 관련 정보, 시스템 정보 등을 포함함
MDC.put("class", this.getClass().getSimpleName());
MDC.put("method", "testJMSAppender");
MDC.put("testKey", "test value");
// 로그 기록
log.debug("JMSAppender test");
// JMS 메시지 consumer (보통 remote 에 있는 system 이 될 수 있음. 여기서는 테스트로 같은
// container 에 LoggerMDP)가
// 해당 메시지를 처리하는 동안 (여기서는 ./logs/jmsconsume/jmsSample.log 에 기록) 잠시 sleep
Thread.sleep(1000);
// JMS 확인
File jmsFile = new File("./logs/jmsconsume/jmsSample.log");
String lastLine = LogFileUtil.getLastLine(jmsFile);
LogFactory.getLog("sysoutLogger").debug(lastLine);
// %d %5p [%c] [%X{class} %X{method} %X{testKey}] %m%n
String patternStr = "^(.*\\]) \\[([a-zA-Z]+) ([a-zA-Z]+) ([a-zA-Z| ]+)\\] (.*)$";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(lastLine);
boolean isMatch = matcher.matches();
assertTrue(isMatch);
LogFactory.getLog("sysoutLogger").debug(lastLine);
LogFactory.getLog("sysoutLogger").debug(
"%d %5p [%c] : " + matcher.group(1));
LogFactory.getLog("sysoutLogger").debug(
"%X{class} : " + matcher.group(2));
LogFactory.getLog("sysoutLogger").debug(
"%X{method} : " + matcher.group(3));
LogFactory.getLog("sysoutLogger").debug(
"%X{testKey} : " + matcher.group(4));
LogFactory.getLog("sysoutLogger").debug("%m%n : " + matcher.group(5));
}
}