Logging

Logging이란

Logging이란 기록(Log)을 남기는 행위를 말한다. 기록을 남기는 것은 분석 및 오류를 개선하는데 매우 중요한 영향을 미치기 때문에 체계적으로 관리할 필요가 있다. 자바에서는 로그 관리를 위해 여러 프레임워크들이 존재한다. 이 문서에서는 log4j를 이용하여 로그를 작성하는 방법에 대해서 다룬다.

  • log4j

  • logback

이외에도 다양한 프레임워크들이 존재하며, spring에서는 이들을 통합하여 Slf4j 모듈로 관리할 수 있도록 구성되어 있다.

Logging Dependency

Logging을 사용하기 위한 Dependency는 다음과 같다.

  • org.slf4j.slf4j-api

  • org.slf4j.jcl-over-slf4j

  • org.slf4j.slf4j-log4j12

  • log4j.log4j

pom.xml

<dependencies>
    <!-- 생략 -->
    <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>${log4j-version}</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>
    <!-- 생략 -->
</dependencies>

위의 설정에서 <exclusions>는 로깅을 배제할 모듈을 지정하여 불필요한 로깅을 방지한다. spring mvc project를 생성하면 기본적으로 설정이 되어 있기 때문에 버전을 제외하고는 수정할 내용이 없다.

properties에 버전 설정은 다음과 같이 되어있다.

<properties>
    <org.slf4j-version>1.7.30</org.slf4j-version>
    <log4j-version>1.2.15</log4j-version>
</properties>

Logger 생성

Logger를 생성해야 Log를 출력할 수 있다. 중요한 것은 Logger의 종류가 매우 많다는 것이며, 우리는 통합 모듈인 org.slf4j.Logger를 사용할 것이다.

생성 방식 1(instance)

Logger log = LoggerFactory.getLogger(this.getClass());

원하는 위치에 위의 코드를 작성하면 Logger가 생성된다. 반드시 import를 org.slf4j.Logger로 해야 한다. Logger는 org.slf4j.LoggerFactory 클래스를 이용하여 생성하며, 생성 시 클래스 정보를 넘겨주도록 되어 있다. 따라서 현재 객체의 클래스 정보를 반환하는 this.getClass() 명령을 사용하여 정보를 넘길 수 있다. 하지만 static 방식으로 생성할 경우 this.getClass() 명령이 작동하지 않기 때문에 다른 방식을 사용해야 한다.

생성 방식 2(static)

static Logger log = LoggerFactory.getLogger(MyCustomClass.class);

해당 클래스의 멤버 필드자리에 코드를 작성하면 Logger가 생성된다. MyCustomClass는 임시로 만든 클래스이므로 해당 클래스의 이름을 적으면 된다. 모든 클래스는 static 내장 객체로 class정보 객체를 가지고 있기 때문에 이를 이용하여 static Logger를 생성할 수 있다.

생성 방식 3(annotation)

@Slf4j
public class MyCustomClass{
    //아래의 변수가 annotation의 효과를 받아 자동으로 생성된다.
    //public static final Logger log = LoggerFactory.getLogger(MyCustomClass.class);

}

따라서 편하게 Logger를 이용할 수 있게 된다.

Logging 출력

다음과 같은 테스트 코드를 src/main/test 내부에 작성한다.

@Slf4j
public class Test01 {
	
	@Test
	public void test() {
		log.debug("debug 테스트");
		log.info("info 테스트");
		log.warn("warn 테스트");
		log.error("error 테스트");
	}
	
}

아무런 설정도 하지 않은 상황이라면, 다음 결과화면을 확인할 수 있다.

warn 테스트
error 테스트

System.out.println 메소드처럼 출력은 되지만 전부 출력이 되지 않는 것을 확인할 수 있는데, 이는 Logging의 메시지 수준(Level)에 대해서 알아야 이해할 수 있다.

Logging Level

Logging에서는 메시지를 단순 출력하는 것이 아니라 심각도 수준(Level)을 부여하여 상황에 맞게 사용하도록 지원하고 있다. Log4j에서 사용하는 수준은 총 6가지이다.

  • trace : 일상적인 모든 활동에 대한 기록

  • debug : 개발에 사용하는 추적 메시지

  • info : 사용자가 알아야 할 정보 메시지

  • warn : 오류가 발생할 우려가 있는 경고 메시지

  • error : 프로세스 처리 중 발생한 오류 메시지

  • fatal : 시스템이 다운될 수 있는 치명적 오류 메시지

Logging Setting

위에서 살펴본 Logging Level 과 더불어 알아야 할 것이 Logging 설정이다. Logging 설정을 통해 우리가 원하는 수준의 메시지만 볼 수 있도록 설정할 수 있다. 특정 수준만 골라서 보는 것은 불가능하며, 지정한 수준보다 심각한 수준은 모두 출력된다.

  • 메시지 수준을 debug로 설정하면, debug 또는 그보다 심각한 수준의 메시지가 출력된다.

    • debug, info, warn, error, fatal

  • 메시지 수준을 warn으로 설정하면, warn 또는 그보다 심각한 수준의 메시지가 출력된다.

    • warn, error, fatal

설정파일은 src/main/resourcessrc/test/resources에 각각 log4j.xml이란 이름으로 존재한다(Spring MVC Project 기준)

설정 파일을 수정하여 원하는 형태의 로깅을 구현할 수 있다.

Logging Setting File Config

기본적으로 제공되는 log4j.xml 파일을 열면 다음과 같은 화면이 나온다.

위의 화면은 전체적인 디자인을 볼 수 있도록 제공되는 화면으로, 전체적인 구조를 볼 수 있지만 코드를 살펴보기 어려우므로 보는 방식을 변경해야 한다.

Source 탭을 클릭하면 다음과 같은 코드를 확인할 수 있다.

<?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">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.hakademy.app">
		<level value="info" />
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
	</logger>

	<logger name="org.springframework.web">
		<level value="info" />
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

파일 형태

파일의 형태를 살펴보면 다음과 같다.

xml header

<?xml version="1.0" encoding="UTF-8"?>

xml이면 반드시 있어야 하는 헤더 선언이다.

문서 선언(DTD : Document Type Definition)

<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">

이 문서에서 사용할 태그의 정의 정보가 들어있다.

XML Namespace 선언(xmlns) 및 최상위 영역 생성

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

</log4j:configuration>

이 설정에서 사용할 최상위 영역을 선언하고, xmlns 설정을 통해 내부에서 사용할 정보들을 불러온다.

appender

공식 API 문서 보기 Appender 태그는 로그 출력 도구이다. 모든 출력 클래스는 Appender를 상속받아 구현해야 하며 주요 Appender는 다음과 같다.

  • org.apache.log4j.ConsoleAppender

    • 콘솔에 출력을 수행하는 도구

  • org.apache.log4j.FileAppender

    • 파일에 출력을 수행하는 도구

  • org.apache.log4j.RollingFileAppender

    • 파일에 지정한 방식에 의해 분할 출력을 수행하는 도구

  • org.apache.log4j.DailyRollingFileAppender

    • 파일에 일자별로 출력을 수행하는 도구

  • org.apache.log4j.JdbcAppender

    • Database에 출력을 수행하는 도구

  • org.apache.log4j.SMTPAppender

    • 이메일에 출력을 수행하는 도구

  • org.apache.log4j.NTEventAppender

    • 윈도우 시스템 로그에 출력을 수행하는 도구

ConsoleAppender 예시

<appender name="console" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n" />
    </layout>
</appender>

FileAppender 예시

<appender name="xml" class="org.apache.log4j.FileAppender">
    <param name="file" value="D:/log.xml"></param>
    <param name="Append" value="true"></param>
    <layout class="org.apache.log4j.xml.XMLLayout"></layout>
</appender>

DailyRollingFileAppender 예시

<appender name="daily" class="org.apache.log4j.DailyRollingFileAppender">
    <param name="file" value="D:/log/daily"></param>
    <param name="Append" value="true"></param>
    <!-- 파일의 날짜 패턴 -->
    <param name="DatePattern" value="'.'yyyy-MM-dd'.log'"></param>
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n" />
    </layout>
</appender>

Appender 옵션 설명

Target 설정

ConsoleAppender에서 설정하며 표준 출력 통로(System.out)을 지정하여 메시지가 콘솔 화면에 출력되도록 설정한다.

<param name="Target" value="System.out" />

File

FileAppender, DailyRollingFileAppender 등과 같이 파일에 출력하는 Appender에서 사용한다. 상대경로로 작성 시 프로젝트 root를 기준으로 설정되며, 절대경로로 작성도 가능하다. 만약 폴더가 존재하지 않는다면 폴더를 생성해준다.

<param name="file" value="D:/log.xml"></param>

Append

로그를 덧붙일 것인지(Append), 덮어쓸 것인지(Overwrite) 설정할 수 있다.

<param name="Append" value="true"></param>

layout

공식 API 문서 보기 Layout을 통하여 출력되는 메시지의 형태를 설정할 수 있다. Log4j의 모든 레이아웃은 Layout을 상속받아 구현되도록 되어 있다. 그 중 패턴을 지정할 수 있는 PatternLayout의 주요 형식은 다음과 같다.

  • %p : priority, 메시지의 수준이 출력될 자리

  • %m : message, 출력하고자 하는 메시지의 자리

  • %n : new-line, 개행 문자의 자리

  • %c : category, 로그가 출력되는 대상의 카테고리가 출력될 자리

  • %d : date, 시간이 출력될 자리

모든 자리는 숫자를 이용하여 형식을 설정할 수 있다.

  • %5p : 메시지 수준을 +5 형식으로 출력(5칸에 우측(+) 정렬)

  • %-5p : 메시지 수준을 -5 형식으로 출력(5칸에 좌측(-) 정렬)

Layout 예시

<layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n" />
</layout>

logger

logger 설정을 이용해서 패키지별 또는 써드파티(3rd party)의 Logging level을 설정할 수 있다. 만약 생략할 경우 root 설정을 따라간다. 삭제해도 무방하다.

예시

<logger name="org.springframework.core">
    <level value="warn" />
</logger>

root

로그 메시지의 출력 수준과 방식을 설정할 수 있다.

  • priority : 로그 출력 수준을 지정

  • appender-ref : 로그 출력 Appender의 id를 설정. 복수 개 설정 가능

예시

<root>
    <priority value="debug" />
    <appender-ref ref="console" />
    <appender-ref ref="daily" />
</root>

최종 파일 양식

기본적인 설정들이 되어 있는 파일 양식은 다음과 같다.

<?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/">

	<!-- 
		Appender : 로그를 출력하는 도구(위치 결정 도구)
		- ...Appender라는 이름을 가짐
		- ConsoleAppender : 출력을 콘솔창에 수행
		- FileAppender : 출력을 파일에 수행
		- DailyRollingFileAppender : 출력을 일정 기간 단위의 파일에 수행
		- JdbcAppender : 출력을 DB에 수행
		- SMTPAppender :  출력을 이메일에 수행
		- NTEventAppender : 출력을 윈도우 시스템 로그에 수행
		
		Layout : 출력 형식
		- %p : priority, 메시지 수준(Level)
		- %m : message, 출력하고자 하는 메시지
		- %n : newline, 개행(엔터)
		- %c : category, 카테고리 출력, 뒤에 {n}를 붙이면 패키지 깊이(depth)를 설정할 수 있음
		- %d : date, 시간 설정(자바 시간양식과 동일. SimpleDateFormat 참조)
				- y(연), M(월), d(일), E(요일), a(오전/오후) 
				- H(24시), h(12시), m(분), s(초), S(밀리초)
	-->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n" />
		</layout>
	</appender>
	
	<appender name="xml" class="org.apache.log4j.FileAppender">
<!-- 		<param name="file" value="log.xml"></param> -->
		<param name="file" value="D:/log.xml"></param>
		<param name="Append" value="true"></param>
		<layout class="org.apache.log4j.xml.XMLLayout"></layout>
	</appender>
	
	<appender name="daily" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="file" value="D:/log/daily"></param>
		<param name="Append" value="true"></param>
		<!-- 파일의 날짜 패턴 -->
		<param name="DatePattern" value="'.'yyyy-MM-dd'.log'"></param>
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n" />
		</layout>
	</appender>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="warn" />
	</logger>	
	
	<logger name="org.springframework.beans">
		<level value="warn" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="warn" />
	</logger>

	<logger name="org.springframework.web">
		<level value="warn" />
	</logger>
	
	<!-- Root Logger -->
	<root>
		<priority value="debug" />
		<appender-ref ref="console" />
        <!-- <appender-ref ref="daily" /> -->
	</root>
	
</log4j:configuration>

Last updated