본문 바로가기
Spring

[Spring][Mybatis][Logger] Spring Log4j를 이용해서 인터셉터로 로그 남기기 & MyBatis 쿼리 로그 출력 및 정렬

by codeok 2020. 9. 21.
반응형

현재 학습 기록용으로 블로그를 작성하고 있습니다.

부족한 내용이 있거나 맞지 않은 내용이 있으면 댓글 부탁드립니다!

하단의 블로그에서 상세하게 설명해주신 자료를 참고했습니다.

Spring MVC Project에서 Log4j를 이용해서 인터셉터 구현 및 쿼리 로그 출력과 정렬을 진행하겠습니다.

 

스프링(Spring) 개발 - (8) 로그 (Log4j) 및 인터셉터 (Interceptor) 설정

이번글에서는 앞으로 개발을 하는데 필요한 정보를 보여줄 수 있는 로그와 관련된 내용을 이야기합니다. 지금 당장은 크게 눈에 보이는게 없을수도 있겠지만, 한번 하고나면 개발하는데 굉장히

addio3305.tistory.com

TODO

1. Spring Log4j를 이용해서 인터셉터로 로그를 남긴다.
2. lo4jdbc-remix를 추가해서 MyBatis 쿼리 정렬을 한다.

 

1. Spring Log4j를 이용해서 인터셉터로 로그를 남긴다.

 

1.1 pom.xml 구성

  • log4j를 사용하기 위해서는 commons.logging 라이브러리 ( Apache의 JCL, Jakarta Commons Logging )을 사용합니다.
  • 기본적으로 아래와 같은 항목들이 추가가 되어 있기에 별 다른 설정을 하지 않고 넘어갑니다.
<dependency>
	<groupId>commons-logging</groupId>
	<artifactId>commons-logging</artifactId>
	<version>1.2</version>
</dependency>
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>${org.slf4j-version}</version>
</dependency>
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jcl-over-slf4j</artifactId>
	<version>${org.slf4j-version}</version>
	<scope>runtime</scope>
</dependency>
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>${org.slf4j-version}</version>
	<scope>runtime</scope>
</dependency>
<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.15</version>
	<exclusions>
		<exclusion>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
		</exclusion>
		<exclusion>
			<groupId>javax.jms</groupId>
			<artifactId>jms</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jdmk</groupId>
			<artifactId>jmxtools</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jmx</groupId>
			<artifactId>jmxri</artifactId>
		</exclusion>
	</exclusions>
	<scope>runtime</scope>
</dependency>

 

1.1 log4.xml

  • log4j.xml의 설정은 다음과 같이 해줍니다.
  • 20행에는 자신의 패키지명으로 변경해줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
    <!-- Appenders -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %5p [%c] %m%n" />
        </layout>   
    </appender>
     
    <appender name="console-infolog" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %5p %m%n" />
        </layout>   
    </appender>
     
    <!-- Application Loggers -->
    <!-- kr.co.devst 를 여기서는 자신의 패키지명으로 바꿔서 적어 주시면 됩니다. -->
    <logger name="kr.co.devst" additivity="false">
        <level value="debug" />
        <appender-ref ref="console"/>
    </logger>
     
    <!-- Query Loggers -->
    <logger name="jdbc.sqlonly" additivity="false">  
        <level value="INFO"/>  
        <appender-ref ref="console-infolog"/>  
    </logger>
     
    <logger name="jdbc.resultsettable" additivity="false">  
        <level value="INFO"/>  
        <appender-ref ref="console"/>  
    </logger>  
 
    <!-- Root Logger -->
    <root>
        <priority value="off"/>
        <appender-ref ref="console" />
    </root>
     
</log4j:configuration>

 

1.3 LoggerInterceptor.java

  • HandlerInterceptorAdapter을 상속받아서 preHandle, postHandle를 오버 라이딩합니다.
    • 하단에 preHandle, postHandle에 다음과 같은 내용을 넣어줍니다.
package kr.co.devst.logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoggerInterceptor extends HandlerInterceptorAdapter {
	
	protected Log log = LogFactory.getLog(LoggerInterceptor.class);

	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("==========   START   ===========   START   ==========   START    ==========");
            log.debug(" Request URI \t:  " + request.getRequestURI());
        }
        return super.preHandle(request, response, handler);
    }

	@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("==========   END   ===========   END   ==========   END    ==========");
        }
	}
}

 

1.4 servlet-context.xml

  • 30~36행에 있는 <mvc:interceptors> 태그를 추가해줍니다.
    • <mvc:mapping path="/**"/>는 모든 경로에서 들어오는 요청을 인터셉트해준다는 것입니다.
    • beans태그의 class는 실제 LoggerInterceptor를 작성한 [패키지명. 클래스명]입니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
	xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing 
		infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving 
		up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
		in the /WEB-INF/views directory -->
	<beans:bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<beans:bean id="loggerInterceptor"
				class="kr.co.devst.logger.LoggerInterceptor"></beans:bean>
		</mvc:interceptor>
	</mvc:interceptors>

	<context:component-scan
		base-package="kr.co.devst" />
		
</beans:beans>

 

1.5 TestController.java

  • 인터셉터가 정상적으로 작동을 하는지 테스트해보겠습니다.
package kr.co.devst.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@Controller
public class TestController {
	
	private static final Log log = LogFactory.getLog(TestController.class);
	
	@RequestMapping(value = "/test", method = RequestMethod.GET)
	public String goTest() {
		
		return "test";
	}
}

 

 

1.5 test.jsp

  • test.jsp를 webapp/WEB-INF/views 밑에 생성을 해줍니다.
  • TestController에서 test를 리턴해주면 servlet-context.xml에서 설정해준 접두사인 prefix="/WEB-INF/views"와 접미사인 suffix=". jsp"가 test의 앞 뒤에 붙어서 /WEB-INF/views/test.jsp가 됩니다. 그래서 다음과 같은 경로에 test.jsp를 찾아가게 되는 것입니다.  
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h1>인터셉터 test jsp입니다.</h1>

</body>
</html>

 

  • 실행을 하고 TestController.java에서 /test 경로로 클라이언트에서 요청이 들어오면 test를 리턴해줘서 경로에서 localshost:8080/test를 입력하면 아래의 콘솔과 같이 나오게 됩니다. 

 

2. log4jdbc-remix를 추가해서 MyBatis 쿼리 정렬을 한다.

  • Spring에서 위와 같은 설정을 하고 추후에 DAO와 MyBatis에 DB 작업까지 하면 위의 설정만으로는 쿼리가 길어져도 정렬되어 보이지 않아서 불편한 경우가 있습니다.
  • log4jdbc-remix 라이브러리를 추가해서 해결해보도록 하겠습니다.

 

2.1 pom.xml

  • log4j-remix를 추가해줍니다.
<!-- log4jdbc-remix -->
<dependency>
	<groupId>org.lazyluke</groupId>
	<artifactId>log4jdbc-remix</artifactId>
	<version>0.2.7</version>
</dependency>

 

2.2 root-context.xml

  • 2행에서 bean id="dataSourceSpied'를 13행에서 <constructor-arg ref="dataSourceSpied" /> ref로 설정해줍니다.
  • property에는 자신의 db와 username, password를 입력해줍니다.
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="dataSourceSpied"
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName"
		value="com.mysql.cj.jdbc.Driver"></property>
	<property name="url"
		value="jdbc:mysql://${your mysql ip/port}"></property>
	<property name="username" value="${username}"></property>
	<property name="password" value="${password}"></property>
</bean>

<bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
	<constructor-arg ref="dataSourceSpied" />
	<property name="logFormatter">
		<bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
			<property name="loggingType" value="MULTI_LINE" />
			<property name="sqlPrefix" value="SQL : " />
		</bean>
	</property>
</bean>

 

2.3 서버 실행해서 SQL 쿼리 정렬여부 확인하기

  • 여기서는 따로 코드 Controller, Service, DAO, MyBatis 작성은 하지 않겠습니다.
  • 자신의 SQL 결과를 콘솔에서 확인을 하시면 보시는 거와 같이 깔끔하게 정렬이 되어서 나오는 것을 볼 수 있습니다.

 

지금까지 Spring에서 log4j를 이용해서 클라이언트가 요청하는 url 을 남기는 것과 SQL 쿼리를 정렬해서 출력하는 것을 살펴봤습니다.

반응형

'Spring' 카테고리의 다른 글

Spring Boot jsp 사용  (0) 2024.03.17
nGrinder & Spring Boot API 성능 테스트  (0) 2023.03.05
nGrinder 성능 테스트 플랫폼 설치  (0) 2023.03.05
[spring] Lombok 이란?  (0) 2020.09.10
[jsp][servlet] Forward VS Redirect(차이점)  (0) 2020.09.03