이전 글에서는 컨트롤러에서 사용자에게 메시지를 전달하는 기능을 구현해 보았습니다. 이번에는 애플리케이션에 로그백(Logback)을 적용하고, MyBatis XML Mapper에 선언된 SQL 쿼리가 실행되었을 때 해당 SQL 쿼리의 로그를 콘솔에 출력하는 방법을 알아보도록 하겠습니다.
1. logback-spring.xml 추가하기
resources 디렉터리에 logback-spring.xml을 추가하고, 다음의 코드를 작성해 주세요.
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- Appenders -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %5p [%c] %m%n</Pattern>
</encoder>
</appender>
<appender name="console-infolog" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>%d %5p %m%n</Pattern>
</encoder>
</appender>
<!-- Logger -->
<logger name="com.study" level="DEBUG" appender-ref="console" />
<logger name="jdbc.sqlonly" level="INFO" appender-ref="console-infolog" />
<logger name="jdbc.resultsettable" level="INFO" appender-ref="console-infolog" />
<!-- Root Logger -->
<root level="off">
<appender-ref ref="console" />
</root>
</configuration>
먼저 xml에 선언한 설정에 대해 간략히 알아보겠습니다.
태그 | 설명 |
appender | 전달받은 로그를 어디에 출력할지 결정합니다. (콘솔 출력, 파일 저장, 데이터베이스 저장 등) |
encoder | appender에 포함되어 출력할 로그의 형식을 지정합니다. |
logger | 로그를 출력하는 요소로, level 속성을 통해 출력할 로그의 레벨을 조절하여 appender에 전달합니다. 첫 번째 logger에서 com.study는 java 디렉터리의 Java 패키지 경로를 의미합니다. |
다음으로 로그의 레벨에 대해 알아보겠습니다.
레벨 | 설명 |
fatal | 아주 심각한 에러가 발생한 상태를 나타냅니다. |
error | 요청을 처리하던 중 문제가 발생한 상태를 나타냅니다. |
warn | 프로그램 실행에는 문제가 없지만, 나중에 시스템 에러의 원인이 될 수 있는 경고성 메시지를 나타냅니다. |
info | 어떠한 상태 변경과 같은 정보성 메시지를 나타냅니다. |
debug | 개발 시에 디버그 용도로 사용하는 메시지입니다. |
trace | 디버그 레벨이 너무 광범위한 것을 해결하기 위해 좀 더 상세한 이벤트를 나타냅니다. |
마지막으로 로그의 타입에 대해 알아보겠습니다.
타입 | 설명 |
sqlonly | SQL을 로그로 남기며, Prepared Statement와 관련된 파라미터는 자동으로 변경되어 SQL을 출력합니다. |
sqltiming | SQL과 SQL 실행 시간(milliseconds 단위)을 출력합니다. |
audit | ResultSet을 제외한 모든 JDBC 호출 정보를 출력합니다. JDBC 관련 문제를 추적하는 경우를 제외하고는 사용이 권장되지 않습니다. |
resultset | ResultSet을 포함한 모든 JDBC 호출 정보를 출력합니다. |
resultsettable | SQL 조회 결과를 테이블 형태로 출력합니다. |
connection | Connection의 연결과 종료에 관련된 로그를 출력합니다. 커넥션 누수 문제 해결에 도움이 됩니다. |
2. 애플리케이션 실행하기
이제, 게시글 리스트 페이지로 접속해 보시면 IDE 콘솔에 SQL 쿼리 로그가 출력되는데요. 출력된 로그는 PostService의 findAllPost( )에서 호출하는 PostMapper의 findAll( )과 연결된 SQL 쿼리입니다.
(이미지를 클릭하시면 확대해 보실 수 있습니다.)
3. Log4JDBC 라이브러리 추가하기
콘솔에 SQL 쿼리가 출력되긴 하지만, 한눈에 알아보기 힘든 문제가 있습니다. 쿼리 로그가 깔끔하게 정렬된 상태로 출력되고, 쿼리에 대한 추가적인 정보를 제공받을 수 있도록 Log4JDBC를 추가해 보도록 하겠습니다.
build.gradle의 dependencies에 Log4JDBC 라이브러리를 추가하고, IDE 우측 상단의 코끼리를 클릭해서 그레이들을 다시 로드해 주세요.
(implementation은 꼭 implementation끼리 뭉쳐있어야 합니다.)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' /* Thymeleaf Layout */
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16' /* Log4JDBC */
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
4. UTF-8 인코딩 설정하기
Logback이 적용됐을 때 간혹 한글이 깨지는 문제가 발생할 수 있는데요. 이를 방지하기 위해 IDE와 내장 톰캣에 인코딩 설정을 추가해 주도록 하겠습니다.
4-1) IDE VM 옵션 추가
인텔리제이에서 Ctrl + Shift + A를 누르고, Actions 탭에 vm을 검색한 후 가장 상단의 Edit Custom VM Options를 클릭해 주세요.
파일이 열리면, 다음의 설정을 추가해 주세요.
-Dfile.encoding=UTF-8
4-2) 내장 톰캣(Embedded Tomcat) VM 옵션 추가
인텔리제이 상단의 Run - Edit Configurations를 클릭해 주세요.
창이 열리면, 우측 상단의 Modify options - Add VM options를 클릭해 주세요.
VM options 항목이 추가되면 마찬가지로 다음의 설정을 추가해 주세요.
-Dfile.encoding=UTF-8
4-3) properties 파일 인코딩 설정
SQL 쿼리 정렬을 설정하기 위해서는 properties 파일이 필요한데요. IDE에서 properties 파일 인코딩이 설정되어 있지 않으면 문제가 발생할 수 있으니, 설정(Ctrl + Alt + S) 창에서 "encoding"을 검색한 후 다음과 같이 설정해 주세요.
5. log4jdbc.log4j2.properties 추가하기
resources 디렉터리에 log4jdbc.log4j2.properties 파일을 추가하고, 코드를 작성해 주세요.
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0
6. jdbc-url과 driver-class-name 변경하기
application.properties의 데이터 소스 설정을 다음과 같이 변경해 주세요. DB 정보는 여러분의 환경에 알맞게 설정해 주셔야 합니다.
spring.datasource.hikari.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.hikari.jdbc-url=jdbc:log4jdbc:mariadb://localhost:3306/board?serverTimezone=Asia/Seoul&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.hikari.username=username
spring.datasource.hikari.password=password
spring.datasource.hikari.connection-test-query=SELECT NOW() FROM dual
7. 인텔리제이 및 애플리케이션 재실행하기
VM 옵션을 확실히 적용하기 위해 IDE와 애플리케이션을 재실행한 후 다시 게시글 리스트로 접속해 보시면, IDE 콘솔에 SQL 쿼리 로그와 함께 게시글 정보가 테이블 형태로 정렬되어 출력됨을 확인하실 수 있습니다.
게시글을 생성하는 INSERT 쿼리도 정상적으로 파라미터가 매핑되어 출력됩니다.
마치며
SQL 쿼리 로그 출력은 개발 단계에서는 너무나도 필수적인 기능입니다. 디버깅 모드와 함께 사용하면 문제를 더욱 효율적으로 추적(해결) 할 수 있습니다.
다음 글에서는 애플리케이션에 스프링 인터셉터(Spring Interceptor)를 적용해 볼 건데요. 인터셉터란 이름 그대로 "무언가를 가로챈다."라는 의미를 가지고 있습니다. 스프링에서 인터셉터는 컨트롤러의 특정 URI에 접근하는 과정에서 무언가를 제어할 필요가 있을 때 사용됩니다.
예를 들어, 로그인 한 회원 정보를 조회하는 "/member/mypage.do"라는 URI로 접근한다고 가정했을 때, 로그인하지 않은 사용자가 누군가의 마이 페이지에 접근이 가능하다면 이는 보안상 커다란 문제가 될 것이고, 인터셉터를 잘 활용하면 이러한 문제들을 해결(방지) 할 수 있답니다.
오늘도 방문해 주신 여러분께 진심으로 감사의 말씀을 전합니다. 좋은 하루 보내세요 :)
댓글