ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] Kotlin으로 REST API 만들기(4) - Log4jdbc 설정
    Spring Boot/Kotlin으로 REST API 만들기 2022. 10. 27. 10:45
    반응형

    Kotlin으로 REST API 만들기(4) - Log4jdbc 설정

    기본적으로 스프링 부트는 Java Util Logging, Log4J2 and Logback 기능을 지원하여 실행된 SQL문을 확인할 수 있지만, 파라미터가 바인드되지 않고 물음표로 출력되거나, 탭이나 개행문자가 적용되지 않아 가독성이 떨어지기 때문에 log4jdbc 설정이 필요합니다.

     

    1. 의존성 추가

    Log4Jdbc를 사용하여 DB 관련 로그를 추가하기 위해 log4jdbc-log4j2-jdbc4를 추가하세요.

    import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
    
    plugins {
      id("org.springframework.boot") version "2.7.4"
      id("io.spring.dependency-management") version "1.0.14.RELEASE"
      kotlin("jvm") version "1.6.21"
      kotlin("plugin.spring") version "1.6.21"
    }
    
    group = "com.example"
    version = "0.0.1-SNAPSHOT"
    java.sourceCompatibility = JavaVersion.VERSION_11
    
    repositories {
      mavenCentral()
    }
    
    dependencies {
      implementation("org.springframework.boot:spring-boot-starter-web")
      implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
      implementation("org.jetbrains.kotlin:kotlin-reflect")
      implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
      testImplementation("org.springframework.boot:spring-boot-starter-test")
    
      // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor
      implementation("org.springframework.boot:spring-boot-configuration-processor:2.7.3")
    
      // https://mvnrepository.com/artifact/mysql/mysql-connector-java
      implementation("mysql:mysql-connector-java:8.0.30")
    
      // https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter
      implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2")
    
      // https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1
      implementation("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
    }
    
    tasks.withType<KotlinCompile> {
      kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "11"
      }
    }
    
    tasks.withType<Test> {
      useJUnitPlatform()
    }

     

    2. application.yml 수정
    datasource 설정에서 spring.datasource.hikari.driver-class-name 및 spring.datasource.hikari.jdbc-url 부분을 다음과 같이 수정하세요.

    • driver-class-name을 net.sf.log4jdbc.sql.jdbcapi.DriverSpy로 수정
    • jdbc:mysql 사이에 log4jdbc를 추가하여 jdbc:log4jdbc:mysql로 수정
    # datasource 설정
    spring:
      datasource:
        hikari:
          driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
          jdbc-url: jdbc:log4jdbc:mysql://localhost:3306/sample?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
          username: sample
          password: password1!

     

    3. log4jdbc.log4j2.properties 파일 추가  
    src/main/resources 폴더에 log4jdbc.log4j2.properties를 추가한 후 log4jdbc에 대한 내용을 설정하세요. 

    # log4jdbc Log 설정
    log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
    log4jdbc.dumpsql.maxlinelength=0
    
    # log4jdbc Drivers 설정
    log4jdbc.drivers=com.mysql.cj.jdbc.Driver
    log4jdbc.auto.load.popular.drivers=false

    log4jdbc.spylogdelegator.name: net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator는 log4jdbc spy의 로그 이벤트를 slf4j를 통해 처리합니다.

    log4jdbc.dumpsql.maxlinelength는 SQL문을 최대 몇 라인까지 출력할 것인가를 결정하는데, 0으로 설정하면 라인에 제한 없이 실행된 SQL문을 출력하고 설정하지 않으면 한줄로 출력됩니다.

    MySQL 8.0부터는 DriverClassName이 'com.mysql.cj.jdbc.Driver'로 변경되어, log4jdbc.drivers를 설정하지 않으면 다음과 같은 경고가 발생합니다. 

    Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'.  The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

     

    4. logback-spring.xml 설정 추가

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    
      <!-- log file path -->
      <property name="LOG_PATH" value="logs" />
      <!-- log file name -->
      <property name="LOG_FILE_NAME" value="springboot_rest_api" />
      <!-- pattern -->
      <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] [%-5level] %logger{36} - %msg%n" />
    
      <!-- Profile 별로 로그 타입을 설정 -->
      <springProfile name="logging-type-console">
        <appender name="PROFILE-APPENDER" class="ch.qos.logback.core.ConsoleAppender">
          <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
          </encoder>
        </appender>
      </springProfile>
      <springProfile name="logging-type-file">
        <appender name="PROFILE-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <!-- 파일경로 설정 -->
          <file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
    
          <!-- 출력패턴 설정 -->
          <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
          </encoder>
    
          <!-- Rolling 정책 -->
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- .gz,.zip 등을 넣으면 자동 일자별 로그파일 압축 -->
            <fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
              <!-- 파일당 최고 용량 kb, mb, gb -->
              <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
    
            <!-- 일자별 로그파일 최대 보관주기(~일), 해당 설정일 이상된 파일은 자동으로 제거 -->
            <maxHistory>30</maxHistory>
            <!--<MinIndex>1</MinIndex>
            <MaxIndex>10</MaxIndex> -->
          </rollingPolicy>
        </appender>
      </springProfile>
    
      <!-- Profile 별로 로그 레벨을 설정 -->
      <springProfile name="logging-level-local">
        <!--특정 패키지 로그 레벨 설정-->
        <property name="LOG_LEVEL_root" value="DEBUG"/>
        <property name="LOG_LEVEL_com.example.springbootrestapi" value="DEBUG"/>
        <property name="LOG_LEVEL_com.zaxxer.hikari" value="DEBUG"/>
        <property name="LOG_LEVEL_jdbc" value="WARN"/>
        <property name="LOG_LEVEL_jdbc.sqltiming" value="INFO"/>
        <property name="LOG_LEVEL_jdbc.resultsettable" value="INFO"/>
      </springProfile>
      <springProfile name="logging-level-dev">
        <property name="LOG_LEVEL_root" value="INFO"/>
        <property name="LOG_LEVEL_com.example.springbootrestapi" value="INFO"/>
        <property name="LOG_LEVEL_com.zaxxer.hikari" value="INFO"/>
        <property name="LOG_LEVEL_com.jdbc" value="WARN"/>
        <property name="LOG_LEVEL_com.jdbc.sqltiming" value="INFO"/>
        <property name="LOG_LEVEL_com.jdbc.resultsettable" value="WARN"/>
      </springProfile>
    
      <!-- com.example.springbootrestapi -->
      <logger name="com.example.springbootrestapi"
        level="${LOG_LEVEL_com.example.springbootrestapi}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <!-- hikari -->
      <logger name="com.zaxxer.hikari"
        level="${LOG_LEVEL_com.zaxxer.hikari}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <!-- jdbc -->
      <logger name="jdbc.sqlonly"
        level="${LOG_LEVEL_jdbc}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <logger name="jdbc.audit"
        level="${LOG_LEVEL_jdbc}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <logger name="jdbc.resultset"
        level="${LOG_LEVEL_jdbc}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <logger name="jdbc.connection"
        level="${LOG_LEVEL_jdbc}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <logger name="jdbc.sqltiming"
        level="${LOG_LEVEL_jdbc.sqltiming}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
      <logger name="jdbc.resultsettable"
        level="${LOG_LEVEL_jdbc.resultsettable}"
        additivity="false">
        <appender-ref ref="PROFILE-APPENDER"/>
      </logger>
    
      <!-- 로그 레벨 설정 -->
      <root level="${LOG_LEVEL_root}">
        <appender-ref ref="PROFILE-APPENDER" />
      </root>
    
    </configuration>

     

    Log4jdbc 옵션

    • jdbc.sqlonly : SQL문만을 로그로 출력하며, PreparedStatement일 경우 관련된 argument 값으로 대체된 SQL문이 출력합니다.
    • jdbc.audit : ResultSet을 제외한 모든 JDBC 호출 정보를 로그로 출력합니다.
    • jdbc.resultset : ResultSet을 포함한 모든 JDBC 호출 정보를 로그로 출력합니다.
    • jdbc.connection : Connection open, close 대한 로그를 출력합니다.
    • jdbc.sqltiming : SQL문과 해당 SQL을 실행시키는데 수행된 시간 정보(milliseconds)를 출력합니다.
    • jdbc.resultsettable : SQL 결과 조회된 데이터의 table을 로그로 출력합니다.

     

    5. 로그 확인
    /api/todos 호출 시 설정한 로그 레벨로 로그가 출력되는지 확인하세요.

    jdbc.sqlonly, jdbc.audit, jdbc.resultset, jdbc.connection의 로그 레벨을 WARN으로 설정하고, jdbc.sqltiming, jdbc.resultsettable의 로그 레벨을 INFO로 설정했을 때 다음과 같이 로그가 출력되는지 확인하세요.

     

    소스 코드는 Github Repository - https://github.com/tychejin1218/kotlin-springboot-rest-api.git (branch : section04) 를 참조하세요.

    GitHub에서 프로젝트 복사하기(Get from Version Control) - https://tychejin.tistory.com/325

    반응형

    댓글

Designed by Tistory.