티스토리 뷰

코딩/spring

[16주 3일차] 로그 기록

ehzim 2024. 1. 24. 13:43

Chapter 11. 로그 기록 : 로그 기록 만들기

 

 

 

 

11.1 Log4j 개요

웹 애플리케이션이 실행되는 동안 모든 요청 URL의 경로마다 접근 내역과 특정 사용자가 URL을 요청할 때의 작동 내역 등이 남아 있다.

이러한 경우 로그를 기록하기 위해 자바 기반의 로깅인 Log4j를 사용한다.

 

로그를 남긴다는 말은 접근 기록이 필요하다는 것을 의미한다.

 

 

 

11.1.1 로깅 유틸리티 Log4j

Log4j는 아파치 소프트웨어 라이선스에 따라 배포되는 로깅 프레임워크이다.

자바로 작성되어 안정적이고 유연하다. 시스템 성능에 큰 영향을 키치지 않아 선택적인 로그를 남기거나 특정 파일에 로그를 기록할 수 있는 환경을 제공한다.

 

스프링 MVC에서 로깅 유틸리티 Log4j 기능을 사용하려면 의존성 라이브러리(=dependency) 정보를 등록해야 한다.

pom.xml에 아래와 같이 의존 라이브러리를 포함하여 작성한다.

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

 

 

 

 

 

11.1.2 Log4j의 구조와 로깅 레벨

Log4j를 이용해 로그를 기록하려면 구조와 로깅 레벨을 알아야한다.

Log4j의 구조는 크게 logger, appender, layout으로 세 가지 요소로 구성되어 있다.

이것을 통해 쉽게 다양한 형태로 로깅할 수 있고 로깅 레벨을 지정해 해당 레벨 이상으로만 로깅할 수 있다.

 

 

 

looger

logger은 Log4j에서 지원하는 핵심 클래스이다.

로깅 레벨을 가지고 로그 출력 여부는 그 레벨에 따라 결정된다.

 

 

Log4j의 로깅 레벨

  레벨 설명
6 FATAL 조기 종료를 유발하는 심각한 오류가 발생한 상태를 나타낸다.
5 ERROR 기타 런타임 오류 또는 예기치 않은 상태를 나타낸다.
4 WARN 사용되지 않는 API 사용, API의 사용 빈도, 오류, 바람직하지 않거나 예기치 않은 런타임 상황의 경고성 메시지를 나타낸다.
3 INFO 시작, 종료 같은 런타임 이벤트 메시지를 나타낸다.
2 DEBUG 디버그 용도로 시스템 흐름에 대한 자세한 정보를 나타낸다.
1 TRACE 가장 하위 로깅 레벨로, 모든 로그에 대한 상세한 정보를 나타낸다.

 

숫자가 올라 갈 수록(클수록) 심각함.

 

로깅 레벨은 TRACE<DEBUG<INFO<WARN>ERROR>FETAL 순으로 레벨이 높다.

로그를 출력할 때 설정한 레벨 이상의 로그 정보가 출력된다.

만약 INFO 레벨 이상을 출력한다면 INFO, WARN, ERROR, FATAL 의 로그까지 출력된다.

 

appender

 

클래스 설명
ConsoleAppender 콘솔에 로그 정보를 출력한다.
FileAppender 파일에 로그 정보를 출력한다.
RollingFileAppender 로그 크기가 지정한 용량 이상이 되면 다른 이름의 파일로 출력한다.
DailyRollingFileAppender 하루 단위로 로그 정보를 파일에 출력한다.
SMTPAppender 로그 메시지를 이메일로 보낸다.
NTEventLogAppender 윈도의 이벤트 로그 시스템에 로그 정보를 기록한다.

 

 

 

layout

 

 

layout의 클래스 유형

클래스 설명
DateLayout 로그 정보를 날짜 중심으로 간단하게 기록한다.
HTMLLayout 로그 정보를 HTML 형식으로 기록한다.
PatternLayout 로그 정보를 사용자 정의 패턴에 따라 기록한다.
% c : 카테고리 출력
% p : 로깅 레벨 출력 
% m : 로그 내용
% d : 로깅 이벤트가 발생한 시간, yyyy - MM - dd, HH : mm : ss 등 시간 형식 사용 
% t : 로깅 이벤트를 발생한 스레드 이름
% n : 개행
% C : 클래스 이름
% F : 로깅이 발생한 파일 이름
% I : 로깅이 발생한 호출자 정보 
% L : 로깅이 발생한 코드 라인 수 
% M : 로깅이 발생한 메서드 이름
% r : 애플리케이션 시작 이후부터 로깅이 발생한 시점의 시간 
% x : 로깅이 발생한 스레드와 관련된 NDC ( Nested Diagnostic Context )
% X : 로깅이 발생한 스레드와 관련된 MDC ( Mapped Diagnostic Context )
SimpleLayout 로그 정보를 '레벨-정보' 형식으로 간단하게 기록한다.
XMLLayout 로그 정보를 XML 형식으로 기록한다.

 

 

 

11.1.3 로그 환경 설정 파일의 구성

 

 

 

 

 

 

 


11.2 인터셉터 개요

인터셉터는 웹 애플리케이션에서 특정 url을 요청할 때 컨트롤러로 가는 요청을 가로채 특정 작업을 처리할 수 있다.

 

 

11.2.1 인터셉터

인터셉터는 사용자가 url을 요청하면 컨트롤러에 요청이 들어가기 전에 가로채 특정 작업을 처리하는 것을 의미한다.

인터셉터는 핸들러 인터셉터라고 한다.

컨트롤러에 들어오는 요청 HttpRequest와 컨트롤러가 응답하는 HttpResponse를 가로채는 역할을 한다.

인터셉터는 디스패처 서블릿이 컨트롤러를 호출하기 전 후에 요청과 응답을 가로채기 때문에 아래와 같은 특정 작업을 수행하는데 사용할 수 있다.

- 응답 페이지를 출력하기 전에 서버에서 미리 데이터를 가져오는 기능

- 폼에서 제출이 중복으로 일어나는 것을 막는 기능

- 요청이 처리되기 전에 파일을 업로드하는 기능

- 각 요청에 대한 상세한 내역을 기록하는 기능

- 유효성 검사를 하는 기능 

(html 입력시 먼저 유효성 검사를 끝내야한다. 그렇기 때문에 굳이 인터셉터를 사용해 유효성 검사하는 것을 불필요하다.)

- 시간별 동작 및 성능의 병목 지점을 검사하는 기능

 

 

 

11.2.2 인터셉터 등록

인터셉터를 만드려면 HandlerInterceptor 인터페이스를 구현하거나 HandlerInterceptorAdaptor 클래스를 상속받아야 한다.

인터셉터를 구현한 클래스를 servlet-context.xml 파일의 <interceptors> 요소를 사용해 빈으로 등록한다.

 

 

 

//모든 웹 요청 URL에 적용
<interceptors>
	<bean id=" " class="인터셉터 클래스(패키지 포함)"/>
</interceptors>

//특정 웹 요청 URL에 적용
<interceptors>
	<interceptor>
        <mapping path="특정 패턴의 요청 URL" />
        <beans:bean id=" " class="인터셉터 클래스(패키지 포함)" />
    <interceptor>
</interceptors>

 

 


 

11.3 인터셉터를 이용한 로그 기록

로그를 기록하기 위해서는 HandlerInterceptor 인터페이스와 HandlerInterceptorAdpater 클래스를 사용해야한다.

 

 

11.3.1 HandlerInterceptor를 이용한 로그 기록

HandlerInterceptor 인터페이스는 preHandle(), postHandle(), afterCompletion() 세개의 메서드를 가지고 있다.

그렇기 때문에 세개의 메서드를 구현해야한다.

 

preHandle() 메서드는 웹 요청 URL이 컨트롤러에 들어가기 전에 호출되고 false로 반환하면 이후 내용은 실행되지 않는다.

postHandle() 메서드는 웹 요청 URL을 컨트롤러가 처리한 후 호출되고 컨트롤러에서 예외가 발생하면 더 이상 실행되지 않는다.

afterCompletion() 메서드는 컨트롤러가 웹 요청을 처리하여 뷰에 응답이 종료된 후 호출된다.

 

 

 

HandlerInterceptor를 사용한 메서드 호출

 

ExampleInterceptor.java

package com.springmvc.chap11;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class ExampleInterceptor implements HandlerInterceptor{

	public Logger logger = LoggerFactory.getLogger(ExampleInterceptor.class);
	
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
		//stopWatch.start(handler.toString());
		logger.info("preHandle() 호출...");
		
		if(handler instanceof HandlerMethod) {
			HandlerMethod method = (HandlerMethod) handler;
			logger.info("핸들러 메소드명 : " +method.getMethod().getName());
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		logger.info("postHandle() 호출...");
		//HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		logger.info("afterCompletion() 호출...");
		//HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}
	
	
}

 

Example02Controller.java

package com.springmvc.chap11;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class Example02Controller {
	
	public Logger logger = LoggerFactory.getLogger(ExampleInterceptor.class);
	
	@GetMapping("/exam02")
	public String requestMethod(Model model) {
		System.out.println("된다.");
		logger.info("뷰페이지 webpage11_02 호출");
		model.addAttribute("data","인터셉터 예제입니다.");
		model.addAttribute("data2", "웹 요청 URL은 /exam02 입니다.");
		return "webpage11_02";
	}
}

 

 

servlet-context.xml

	<context:component-scan base-package="com.springmvc.chap11"/>
	
	<interceptors>
		<beans:bean class="com.springmvc.chap11.ExampleInterceptor"/>
	</interceptors>

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday