본문 바로가기

Dev/Spring

[Spring] Spring Boot 시작하기 (5) - log4jdbc를 이용한 Query로깅

 

포스팅 시리즈

 

 

이번에는 저번 포스팅 끝에서 언급한 DB 요청과 응답에 대한 로깅 처리에 대해 다루겠습니다.

 

1. 의존성 주입

build.gradle 파일을 열고, DB 로그 기능을 사용하기 위해 log4jdbc 의존성을 등록합니다.

# build.gradle

compile group: 'org.bgee.log4jdbc-log4j2', name: 'log4jdbc-log4j2-jdbc4.1', version: '1.16'

 

build.gradle 파일을 수정했을 경우에는 반드시 Refresh Gradle Project로 설정 정보를 새로고침 해야 합니다.

 

 

2. application.properties 수정

데이터 베이스 드라이버 클래스 네임을 방금 전에 추가한 log4jdbc로 변경하고 url도 변경합니다.

 

# application.properties

#[변경 전]
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/SPRING_BOOT_DB?characterEncoding=UTF-8&serverTimezone=UTC

#[변경 후]
spring.datasource.driver-class-name	= net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url = jdbc:log4jdbc:mysql://localhost:3306/SPRING_BOOT_DB?characterEncoding=UTF-8&serverTimezone=UTC

#[추가할 설정]
#연결 여부 확인을 위한 테스트 쿼리
spring.datasource.hikari.connection-test-query=SELECT 1

#로깅 대상(개발 / 배포) 배포시에는 local -> prod
spring.profiles.active=local
logging.config=classpath:logback-${spring.profiles.active}.xml

 

url은 jdbc:mysql 사이에 log4jdbc를 추가해 주었습니다.

추가할 설정 중에 connection-test-query는 db와 상호작용 하기 전에 제대로 연결이 되어있는지 확인하기 위한 쿼리문으로 보통 SELECT 1로 연결 상태를 확인합니다.

이전 포스팅에서는 위 코드를 추가했어도 확인할 방법이 없었기 때문에 제외했었는데, 이번에는 한번 넣어봅니다.

 

로그를 출력할 양식과 방법 등을 지정하기 위해 logging.config의 정보를 작성해주었습니다.

저는 logback-local.xml, logback-pord.xml 파일로 나누어서 관리하겠습니다.

개발 시에는 logback-local.xml, 배포 시에는 logback-prod.xml을 참조하도록 구성했습니다.

배포 시에는 spring.profiles.active의 값을 prod로 변경하는 것으로 간편하게 참조하는 설정 파일이 변경됩니다.

 

 

3. jdbc spy 로깅 이벤트를 log4j가 받도록 처리

resources 디렉터리에 log4jdbc.log4j2.properties라는 이름으로 파일을 생성하고 파일에 아래의 내용을 작성합니다.

 

# log4jdbc.log4j2.properties

# log4jdbc spy의 로그 이벤트를 slf4j를 통해 처리한다.
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

# 로그를 표시할 줄의 제한, 0은 무제한
log4jdbc.dump.sql.maxlinelength=0

# log4jdbc의 드라이브 클래스 설정
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
log4jdbc.auto.load.popular.drivers=false

 

log4jdbc.drivers를 명시해주지 않을 경우 com.mysql.jdbc.Driver가 더 이상 사용되지 않는다고 아래와 같은 경고를 출력합니다.

 

com.mysql.jdbc.Driver 경고

하지만 설정 파일에서 com.mysql.jdbc.Driver를 따로 명시하지 않았습니다.

아마도 log4jdbc가 기능할 때 내부에서 기본적으로 com.mysql.jdbc.Driver를 사용해서 동작하는 것으로 추측됩니다.

위 경고의 조언대로 com.mysql.cj.jdbc.Driver를 사용하도록 명시하고 드라이버를 자동으로 로드하지 않도록 false값을 부여합니다.

 

 

4. logback-local.xml, logback-prod.xml 작성

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 로그 경로 변수 선언 -->
    <property name="LOG_DIR" value="${user.home}/logs/app" />
    <property name="LOG_PATH" value="${LOG_DIR}/app.log"/>
	
    <!-- log4jdbc 옵션 설정 -->
    <logger name="jdbc" level="OFF"/>
    <!-- connection open close 로깅 여부 -->
    <logger name="jdbc.connection" level="OFF"/>
    <!-- SQL문만 로깅할지 여부 -->
    <logger name="jdbc.sqlonly" level="OFF"/>
	
    <!-- 쿼리문 수행에 걸린 시간 로깅 -->
    <logger name="jdbc.sqltiming" level="DEBUG"/>
    
    <!-- ResultSet외 모든 JDBC 호출 정보를 로깅할지 여부   -->
    <logger name="jdbc.audit" level="OFF"/>
    
    <!-- ResultSet 포함 모든 JDBC 호출 정보를 로깅 -->
    <logger name="jdbc.resultset" level="OFF"/>
    <logger name="jdbc.resultsettable" level="INFO"/>
    
    <!-- use Spring default values -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    
    <!-- 콘솔 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    
    <!-- SQL 결과 조회된 데이터의 table을 로그로 남긴다. -->
	<logger name="jdbc.resultsettable" level="ON" additivity="false">
		<appender-ref ref="CONSOLE"/>
	</logger>
	
    <!-- Rolling File Appender -->
    <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 파일 경로 -->
        <file>${LOG_PATH}</file>
        <!-- 출력패턴 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%-5level] : %msg%n</pattern>
        </encoder>
        <!-- Rolling 정책 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- .gz,.zip 등을 넣으면 자동으로 일자별 로그파일 압축 -->
            <fileNamePattern>${LOG_DIR}/app_%d{yyyy-MM-dd}_%i.log.gz</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 파일당 최고 용량 10MB -->
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 일자별 로그파일 최대 보관주기(일단위) 만약 해당 설정일 이상된 파일은 자동으로 제거-->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
    </appender>
 
    <root level="INFO"> <!-- DEBUG -->
        <appender-ref ref="CONSOLE"/> <!-- 콘솔 출력 -->
        <appender-ref ref="ROLLING_FILE"/> <!-- 파일 출력 -->
    </root>
</configuration>

본 예제에서는 편의상 logback-local.xml과 logback-prod.xml의 내용을 같게 했습니다.

이후 필요에 따라 적절히 수정해서 사용해 주세요.

 

logback 설정에 관한 추가 정보는 아래의 링크를 참고해 주세요.

www.baeldung.com/logback

 

A Guide To Logback | Baeldung

Explore the fundamentals of using Logback in your application.

www.baeldung.com

 

위에서 작성된 logback은 콘솔 출력, 파일 출력 두 가지 기능을 수행합니다.

콘솔 출력 부분은 아래의 xml을 include 해서 Spring 기본 로그 스타일을 그냥 사용하도록 하겠습니다.

<!-- use Spring default values -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

 

 

나머지는 사용 환경에 따라 얼마든지 변경 가능한 설정 정보들이니 반드시 위 파일의 내용을 따를 필요는 없습니다.

 

5. 서버 실행 및 로그 확인

서버를 재시작하고 쿼리문을 요청하는 컨트롤러에 접근했을 때, 위와 같이 sqltiming, resultsettable 로그가 출력된다면 정상 적용된 것입니다.

 

logback.xml에서 파일로 로그를 남길 경우 설정에 따라 로그 파일은 ${user.home}/logs/app이라는 경로에 생성되도록 설정했습니다. 위 경로는 윈도 기준으로 C:\Users\유저명\logs\app입니다.

 

logs/app 디렉터리

app.log 파일을 열어보면 콘솔에서 출력해 주었던 로그와 유사한 형태로 로그가 기록된 것을 확인할 수 있습니다.

이것으로 jdbc 쿼리 로깅에 관한 포스팅을 마치겠습니다.