BACK_END/Spring 공부

Spring - 로깅

harry595 2021. 3. 8. 21:40

로깅이란?

- 정보를  제공하는 일련의 기록인 로그를 생성하도록 시스템을 작성하는 활동

- 프린트 줄 넣기는 간단히, 일시적인 로그만을 생성한다.

- 시스템 설계자들은 시스템의 복잡성 때문에 로그를 이해하고 사용해야 함

- 로그가 제공하는 정보의 양은 이상적으로는 프로그램이 실행되는 중에도 설정 가능해야 함

- 일반적인 로그 기록의 이점 (버그에 대한 유용한 정보, 성능에 관한 통계와 정보, 일반적 정보)

 

로그를 출력하는 방법

- System.out.print() 이용 (성능과 효율이 떨어짐)

- 로깅 라이브러리 이용

-- ex) java.util.logging, Apache Commons logging, Log4j, Logback

 

SLF4J

- logging 관련 라이브러리는 다양해서 이 라이브러리들을 통일된 방식으로 사용하는 방법

- 로깅 Facade, 로깅에 대한 추상 레이어를 제공, interface들의 모음

 

maven에 SLF4J와 logback 의존성 추가하기

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

<dependency>
	<groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
    <exclusions>
      <exclusion>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
      </exclusion>
    </exclusions>
</dependency>

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

 

spring 라이브러리에서 commons-logging을 제거하면, spring을 사용할 때 commons-logging을 찾으며 오류 발생. 이러한 오류를 제거하기 위해 jcl-over-slf4j를 추가함

 

logback.xml (설정 방법)

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</Pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/tmp/access.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/tmp/access-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>

        <encoder>
            <Pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</Pattern>
        </encoder>
    </appender>

    <logger name="org.springframework" level="info"/>
    <logger name="kr.or.connect" level="debug"/>

    <root level="debug">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

Appender (어디에 어떤 폼으로 로그를 남길 지 기록)

- ConsoleAppender : 콘솔에 로그를 어떤 포맷으로 출력할 지

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <Pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</Pattern>
    </encoder>
</appender>

- FileAppender : 파일에 로그를 어떤 포맷으로 출력할 지

- RollingFileAppender : 로그의 양이 많아지면 관리가 어려워 하루단위로 로그를 관리하는 법

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>access.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>access-%d{yyyy-MM-dd}.log</fileNamePattern>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
        <Pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</Pattern>
    </encoder>
</appender>

 

Log Level (로그 중요성의 단계)

1. trace 2. debug 3. info 4. warn 5. error

아래처럼 사용 가능 (어떤 패키지 이하의 클래스에서 어떤 level 이상의 log를 저장할 지)

<logger name="org.springframework" level="info"/>
<logger name="kr.or.connect" level = "debug" />
<root>
    <appender-ref ref = "CONSOLE" />
    <appender-ref ref = "FILE" />
</root>

위의 root 태그는 모든 대상에 콘솔과 파일 어팬더를 적용한다는 의미

 

Logger 객체 선언 (로그를 남기고자 하는 클래스에 로거 객체를 필드로 선언)

import.org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...

private Logger logger = LoggerFactory.getLogger(this.getClass());

로그 출력 메소드 (문자열 결합을 위해 + 연산자 사용 X, 로고의 수준에 따라 debug(),info()등 사용)

logger.trace("{} {} 출력", "값1", "값2");
logger.debug("{} {} 출력", "값1", "값2");
~~

 

LogInterceptor.java 수정 (기존 print -> logger 사용)

package kr.or.connect.guestbook.interceptor;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LogInterceptor extends HandlerInterceptorAdapter{
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
//		System.out.println(handler.toString() + " 가 종료되었습니다.  " + modelAndView.getViewName() + "을 view로 사용합니다.");
		logger.debug("{} 가종료되었습니다. {} 를 view로 사용합니다.", handler.toString(), modelAndView.getViewName());
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
//		System.out.println(handler.toString() + " 를 호출했습니다.");
		logger.debug("{} 를 호출했습니다.", handler.toString());
		return true;
	}

	
}