본문 바로가기
Spring/Spring

[Spring] Logback, log4jdbc를 이용한 시스템로그, DB로그 출력방법

1. 들어가며

이 포스팅에서는 Spring을 이용한 Log를 콘솔과 파일형태로 남기는 방법에 대해서 알아볼려고 합니다. 기존에는 log4j를 이용하여 로그를 출력했다면 최근에는 Logback을 이용한 방식을 많이 사용하고 있습니다. 그 이유는 더 빠르기 때문인데 logback자체가 log4j가 만들어진 이후에 log4j의 단점을 보완하여 만들어진 방식이기에 어찌보면 당연하다고 볼수 있습니다. 앞서 말한 이유로 이 포스팅에서는 Logback을 이용하여 로그를 출력할 예정 이지만 그러기 위해서는 우선 기존에 Spring에서 사용하는 commons-logging 라이브러리를 대체해야하기 때문에 SLF4J도 같이 사용해야만 합니다. SLF4J는 java로 따지면 인터페이스의 역할을 하는데 이를 이용해서 Logback이 기존의 로깅라이브러리를 어떻게 대체하며 나중에 Logback보다 더 좋은 로깅라이브러리가 생긴다면 별다른 어려움 없이 Logback을 대체할 수 있게 될 것이입니다.

 

추가적으로 Logback설정만 하게되면 DB에서 출력되는 쿼리로가 줄바꿈 없이 한줄에 나오기 때문에 가독성이 떨어지는 부분을 보완하기 위하여 Logback에 log4jdbc를 추가하여 사용하는 방법까지 기술하도록 하겠습니다.

 

이 포스팅에서 로그를 남기는 프로젝트의 세팅은 다음과 같습니다.

각자 처한상황에 따라 세팅이 변경될 가능성이 있으니 참고하시길 바랍니다.

 

- Spring Legacy Project

- Maria DB

- Hikari CP (커넥션 풀)

- Logback

- log4jdbc (Logback에서 출력되는 DB로그의 sql문의 줄바꿈을 위해서)

 

 

 

 

 

2. Logback 적용

앞서 말한것처럼 Logback 라이브러리로 대체하기 위해서는 commons-logging(JCL)라이브러리를 제외 시켜야 합니다. commons-logging를 제외시켰기 때문에 기존에  commons-logging를 이용하여 로그를 남기던 코드들은 에러가 발생하는데 이를 막기위해서  jcl-over-sl4j라이브러리를 사용합니다. jcl-over-sl4j 라이브러리를 적용하면 실제로는 slf4를 구현한 logback-classic 라이브러리가 로그를 기록합니다.

 

<exclusions>
  <!-- Exclude Commons Logging in favor of SLF4j -->
  <exclusion>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
  </exclusion>
</exclusions>

위에서 언급한 commons-logging라이브러리입니다. logback을 사용하기 때문에 더이상 필요가 없으며 해당코드가 있다면  Pom.xml에서  코드를 제거해 줍니다.

 

<!-- Logback --> 
<dependency>                                    
  <groupId>ch.qos.logback</groupId>        
  <artifactId>logback-classic</artifactId>     
  <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.30</version>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.30</version>
</dependency>

Pom.xml에 logback에 관련된 라이브러리를 추가해 줍니다.

 

<?xml version="1.0" encoding="UTF-8"?>

<!-- 
[Layout]
%d : 날짜
%n : new line
%t : thread
%p : 로깅레벨
%c : 로깅이 발생한 카테고리
%C : 로깅이 발생한 클래스명
%m : 로깅 메세지
-->



<configuration scan="true" scanPeriod="30 seconds" >

  <property resource="logback.properties"/>
  <property name="SAMPLE" value="" />

  <timestamp key="date" datePattern="yyyyMMdd"/>
  <timestamp key="year" datePattern="YYYY"/>
  <timestamp key="month" datePattern="MM"/>
  <timestamp key="day" datePattern="dd"/>

  <!-- 콘솔로 로그를 남기는 설정 -->
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <charset>UTF-8</charset>
      <Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%p] [%t] [%c]%m%n</Pattern>
    </encoder>
  </appender>



  <!-- 파일로 로그를 남기는 설정 -->
  <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 저장경로/파일명 -->
    <file>${log.url}/${year}/${month}/${date}.log</file>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <Pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%p] [%t] [%c] %m%n</Pattern>
    </encoder>

    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <!-- 파일명을 .zip .tz로 하는경우 자동으로 압축된다 -->
      <fileNamePattern>${log.url}/${year}/${month}/${date}_%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>10</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>30MB</maxFileSize>
    </triggeringPolicy>
  </appender>



  <!-- 출력되는 로그의 양 순서 : ERROR < WARN < INFO < DEBUG < TRACE -->         
  <!-- com.freedy.sample 하위 패키지에서 로그설정 -->
  <!-- additivity가 false인 경우 상위로거의 설정값을 상속받지 않는다. -->
  <logger name="com.freedy.sample" level="debug" additivity="false">
    <appender-ref ref="file" />
    <appender-ref ref="console" />
  </logger>

  <!-- root는 글로벌 로거를 의미하며, 위의 logger에 해당하지 않으면 root 로거가 실행된다. -->
  <root level="warn">
    <appender-ref ref="file" />
    <appender-ref ref="console" />
  </root>

</configuration>

이제는 Logback에 대한 설정파일을 생성해 줘야합니다. xml파일로 작성을 하며 파일의 경로는 /src/main/resources/이며 해당경로에 logback.xml의 이름으로 xml파일을 생성하면 자동으로 logback.xml이라는 이름을 가진 파일을 찾아서 설정값을 적용해 줍니다. 따라서 경로와 이름은 동일하게 지정해 주셔야 합니다. 작성법은 위의 예시 xml파일을 참고하시면 됩니다.

 

추가적으로 ${log.url} 부분은 외부 프로퍼티파일을 통해서 불러온 변수입니다. 만약 프로퍼티파일을 사용하는 방법을 모르신다면 직접 타이핑하여 입력하시면 됩니다.

 

추가적인 기능의 확인이 필요하신분들은 공식사이트의 메뉴얼을 확인하시면 됩니다.

http://logback.qos.ch/manual/

 

Logback Manual

The logback manual 和訳 (Japanese translation) The complete logback manual documents the latest version of logback framework. In over 150 pages and dozens of concrete examples, it covers both basic and advanced logback features, including: the overall logbac

logback.qos.ch

 

 

 

 

 

3. log4jdbc 적용

위의 설정대로 했다면 정상적으로 로그가 찍히는 것을 확인할 수 있습니다. 하지만 sql문의 경우 줄바꿈이 없이 한줄로 나오기 때문에 보기가 불편합니다. 그래서 logback에 log4jdbc를 추가하여 sql쿼리를 정렬된 상태로 볼 수 있도록 해보겠습니다. 물론 로그에 나오는 쿼리의 줄바꿈 기능이 필요없다면 더이상 진행할 필요는 없습니다.

 

<!-- log4jdbc-log4j2 -->
<dependency>
    <groupId>org.bgee.log4jdbc-log4j2</groupId>
    <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
    <version>1.16</version>
</dependency>

우선 pom.xml에 log4jdbc를 추가합니다.

 

log4jdbc.drivers = org.mariadb.jdbc.Driver
log4jdbc.spylogdelegator.name = net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength = 0

/src/main/resources/ 경로에 log4jdbc.log4j2.properties이름으로 properties파일을 생성하며 내용은 위의 코드와 동일하게 작성을 합니다. 만약 사용하는 DB가 Maria DB가 아니라면 그에 맞는 적절한 값을 입력해 주셔야 하며 해당설정 파일의 이름과 경로는 동일하게 지정해 주셔야 합니다.

 

<!-- DB연결 설정 -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
  <!-- <property name="driverClassName" value="org.mariadb.jdbc.Driver" /> -->
  <!-- <property name="jdbcUrl" value="jdbc:mariadb://128.251.171.170:3306/test" /> -->
  <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" />
  <property name="jdbcUrl" value="jdbc:log4jdbc:mariadb://128.251.171.170:3306/test" />
  <property name="username" value="ID" />
  <property name="password" value="PW" />
</bean>

다음은 root-context.xml에서 db연결 설정을 변경합니다. 주석부분이 기존의 코드이고 그 아래코드가 새롭게 수정된 코드입니다.

 

<!-- mybatis query log setting -->
<logger name="jdbc" level="OFF" />
<logger name="jdbc.sqlonly" level="OFF" />
<logger name="jdbc.sqltiming" level="DEBUG" />
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.resultsettable" level="OFF" />
<logger name="jdbc.connection" level="OFF" />

<!-- root는 글로벌 로거를 의미하며, 위의 logger에 해당하지 않으면 root 로거가 실행된다. -->
<root level="warn">
  <appender-ref ref="file" />
  <appender-ref ref="console" />
</root>

마지막으로 위에서 만들었던 logback.xml파일에 새로운 코드를 추가하면 이제 쿼리문이 보기좋게 정렬되어 로그로 남겨지게 됩니다.

 

 

 

 

 

4. JAVA에서 로그 찍기

시스템과 DB로그를 찍었다면 이번에는 자바단에서 개발자가 직접출력하는 로그를 사용해 보도록 하겠습니다.

 

private Logger logger = LoggerFactory.getLogger(this.getClass());

@RequestMapping(value = "test.do", method = RequestMethod.GET)
public String home() {

  System.out.println("sysout log");
  logger.debug("logback log");
  logger.debug("logback log {} {}", "1번", "2번");

  return "test/test.tiles";
}

특별히 어려운부분이 없어 코드만 보고 사용법을 알 수 있습니다.

참고로 {}부분은 뒤쪽에 기입한 파라메타가 출력되는 부분입니다.

댓글