728x90

log4j, 파일, 디비 DB, JDBCAppender, 중복, 로그, MDC, NDC


보안사고가 잦은 요즘 고객사에서 파일로 남기는 로그가 있었는데

모든 액션에 대해서 6하원칙 원인 분석이 가능하도록 DB에 남겨달라는 요청이 있다.

 

확인을 해보니 log4j 에서 파일만 지원하는 줄 알았는데 콘솔, DB 에 저장 가능하다고 한다.

 

JDBCAppender 를 검색해보면 여러가지 나오는데 

MDC까지 활용을 하면 log4j에서 지원하는 기본기능에 더해서 내가 원하는 변수들도 저장이 가능하다.

 

MDC는 hashtable 타입같은거고 NDC는 stack 형식이며

NDC는 메모리 부하가 있다고 하니 꼭 remove를 해야 한다.

웬만하면 MDC 쓰는 편이 명확하고 좋은 것 같음. (org.apache.log4j.MDC)

 

 

1. 스프링의 인터셉터를 생성 혹은 추가 

    <bean id="beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="interceptors">
         <list>
             <ref bean="LogInterceptor"/>
            </list>
        </property>
        <property name="order"><value>1</value></property>
    </bean> 

2. LogInterceptor 라는 bean 설정 

<bean id="LogInterceptor" class="원하는 패키지 경로.LogInterceptor" />

 

3. LogInterceptor 클래스에서 HandlerInterceptorAdapter 를 extends 받아서 구현 

아래 내용은 preHandle 메소드안에서 구현한다.

 

     String url = request.getServletPath();
     String ip = request.getRemoteAddr();

 

     Enumeration param = request.getParameterNames();
     while(param.hasMoreElements())
     {
      String name = (String)param.nextElement();
      String value = request.getParameter(name);
      if(null != value && !"".equals(value))
      {
       params += ("["+name+":"+value+"]");
      }
     }
     
     MDC.put("ACCOUNT_ID", accountId);
     MDC.put("ACCOUNT_IP", ip);
     MDC.put("PAGE_URL", url);
     MDC.put("PARAMS", params);
     
     return true;

 

 

4. log4j.properties 에서 아래 내용 추가 (아래내용은 파일과 DB를 동시에 남기는 설정)

 

 

#================================================================================
# ibatis shkim.add.IBATIS_DB_LOG
#================================================================================
log4j.logger.com.ibatis=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.java.sql.Connection=DEBUG, IBATIS_LOG, IBATIS_DB_LOG
log4j.logger.java.sql.Statement=DEBUG, IBATIS_LOG
log4j.logger.java.sql.PreparedStatement=DEBUG, IBATIS_LOG
#log4j.logger.java.sql.ResultSet=DEBUG, IBATIS_LOG
log4j.logger.spectra.base.sql.ibatis=DEBUG, IBATIS_LOG, IBATIS_DB_LOG

log4j.appender.IBATIS_LOG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.IBATIS_LOG.Threshold=DEBUG
log4j.appender.IBATIS_LOG.File=원하는파일저장경로/ibatis.log
log4j.appender.IBATIS_LOG.DatePattern='.'yyyy-MM-dd
log4j.appender.IBATIS_LOG.layout=org.apache.log4j.PatternLayout
log4j.appender.IBATIS_LOG.layout.ConversionPattern=%d{MM-dd HH:mm:ss} %-10t %-10x %-5p %-24.24C{2} %-30.30M %m%n
log4j.appender.IBATIS_LOG.ImmediateFlush=True

 

#DB LOG SETTING s
log4j.appender.IBATIS_DB_LOG=org.apache.log4j.jdbcplus.JDBCAppender
log4j.appender.IBATIS_DB_LOG.url=jdbc:oracle:thin:@디비아이피혹은호스트:1521:orcl
log4j.appender.IBATIS_DB_LOG.dbclass=oracle.jdbc.driver.OracleDriver
log4j.appender.IBATIS_DB_LOG.username=디비접속계정
log4j.appender.IBATIS_DB_LOG.password=디비접속비밀번호
log4j.appender.IBATIS_DB_LOG.sql=INSERT INTO T_ACCOUNT_ACTION_LOG( LOG_DATE,ACCOUNT_ID,ACCOUNT_IP,PAGE_URL,QUERY_NAME,PARAMS  ) values (to_char(SYSDATE, 'YYYYMMDDhh24miss'),'@MDC:ACCOUNT_ID@','@MDC:ACCOUNT_IP@','@MDC:PAGE_URL@','@MSG@','@MDC:PARAMS@')
log4j.appender.IBATIS_DB_LOG.layout=org.apache.log4j.PatternLayout
log4j.appender.IBATIS_DB_LOG.layout.ConversionPattern=%m%n
log4j.appender.IBATIS_DB_LOG.buffer=1
log4j.appender.IBATIS_DB_LOG.commit=true
log4j.appender.IBATIS_DB_LOG.quoteReplace=true
log4j.appender.IBATIS_DB_LOG.throwableMaxChars=3000
#DB LOG SETTING e 

 

5. 테이블 생성 쿼리

--------------------------------------------------------------------------------
-- 상담사 로그 저장 테이블 생성 스크립트
-- 작성자 : shkim,
-- 작성일 : 2014.01.23
--------------------------------------------------------------------------------
-- Table 테이블명

CREATE TABLE 테이블명
(
  LOG_DATE    CHAR(14)  DEFAULT to_char(sysdate, 'YYYYMMDDhh24miss'), 
  ACCOUNT_ID  VARCHAR2(128 BYTE) ,
  ACCOUNT_IP  VARCHAR2(128 BYTE) ,
  PAGE_URL    VARCHAR2(128 BYTE) ,
  QUERY_NAME  VARCHAR2(500 BYTE) ,
  PARAMS      VARCHAR2(4000 BYTE) 
);

CREATE INDEX IDX_LOG_DATE_ID_ASC ON 테이블명(LOG_DATE, ACCOUNT_ID);
CREATE INDEX IDX_LOG_DATE_ID_DESC ON 테이블명(LOG_DATE DESC, ACCOUNT_ID);

COMMENT ON TABLE 테이블명 IS 'enomix사용자액션저장테이블';
COMMENT ON COLUMN 테이블명.LOG_DATE IS '액션시간';
COMMENT ON COLUMN 테이블명.ACCOUNT_ID IS '사용자ID null일 경우 시스템호출 혹은 로그인 전 발생한 액션';
COMMENT ON COLUMN 테이블명.ACCOUNT_IP IS '사용자IP null일 경우 시스템호출';
COMMENT ON COLUMN 테이블명.PAGE_URL IS '호출URL null일 경우 시스템호출';
COMMENT ON COLUMN 테이블명.QUERY_NAME IS '호출쿼리명';
COMMENT ON COLUMN 테이블명.PARAMS IS '파라미터로 검색조건이나 검색기간 기타 request 정보등이 담겨있다'; 

 

 

 

출처 : 김상현 블로그 <https://m.blog.naver.com/PostView.nhn?blogId=0131v&logNo=110183988915&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F>



반응형

+ Recent posts