Logging이란
Logging
이란 기록(Log
)을 남기는 행위를 말한다.
기록을 남기는 것은 분석 및 오류를 개선하는데 매우 중요한 영향을 미치기 때문에 체계적으로 관리할 필요가 있다.
자바에서는 로그 관리를 위해 여러 프레임워크들이 존재한다.
이 문서에서는 log4j
를 이용하여 로그를 작성하는 방법에 대해서 다룬다.
이외에도 다양한 프레임워크들이 존재하며, spring에서는 이들을 통합하여 Slf4j
모듈로 관리할 수 있도록 구성되어 있다.
Logging Dependency
Logging
을 사용하기 위한 Dependency는 다음과 같다.
pom.xml
Copy <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
에 버전 설정은 다음과 같이 되어있다.
Copy <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)
Copy Logger log = LoggerFactory.getLogger(this.getClass());
원하는 위치에 위의 코드를 작성하면 Logger가 생성된다. 반드시 import를 org.slf4j.Logger로 해야 한다.
Logger는 org.slf4j.LoggerFactory
클래스를 이용하여 생성하며, 생성 시 클래스 정보 를 넘겨주도록 되어 있다.
따라서 현재 객체의 클래스 정보를 반환하는 this.getClass()
명령을 사용하여 정보를 넘길 수 있다.
하지만 static 방식으로 생성할 경우 this.getClass()
명령이 작동하지 않기 때문에 다른 방식을 사용해야 한다.
생성 방식 2(static)
Copy static Logger log = LoggerFactory.getLogger(MyCustomClass.class);
해당 클래스의 멤버 필드
자리에 코드를 작성하면 Logger가 생성된다. MyCustomClass
는 임시로 만든 클래스이므로 해당 클래스의 이름을 적으면 된다.
모든 클래스는 static 내장 객체로 class정보 객체를 가지고 있기 때문에 이를 이용하여 static Logger를 생성할 수 있다.
생성 방식 3(annotation)
Copy @Slf4j
public class MyCustomClass{
//아래의 변수가 annotation의 효과를 받아 자동으로 생성된다.
//public static final Logger log = LoggerFactory.getLogger(MyCustomClass.class);
}
따라서 편하게 Logger를 이용할 수 있게 된다.
Logging 출력
다음과 같은 테스트 코드를 src/main/test
내부에 작성한다.
Copy @Slf4j
public class Test01 {
@Test
public void test() {
log.debug("debug 테스트");
log.info("info 테스트");
log.warn("warn 테스트");
log.error("error 테스트");
}
}
아무런 설정도 하지 않은 상황이라면, 다음 결과화면을 확인할 수 있다.
System.out.println
메소드처럼 출력은 되지만 전부 출력이 되지 않는 것을 확인할 수 있는데, 이는 Logging의 메시지 수준(Level)에 대해서 알아야 이해할 수 있다.
Logging Level
Logging
에서는 메시지를 단순 출력하는 것이 아니라 심각도 수준(Level)을 부여하여 상황에 맞게 사용하도록 지원하고 있다.
Log4j
에서 사용하는 수준은 총 6가지이다.
trace
: 일상적인 모든 활동에 대한 기록
warn
: 오류가 발생할 우려가 있는 경고 메시지
error
: 프로세스 처리 중 발생한 오류 메시지
fatal
: 시스템이 다운될 수 있는 치명적 오류 메시지
Logging Setting
위에서 살펴본 Logging Level 과 더불어 알아야 할 것이 Logging 설정
이다.
Logging 설정
을 통해 우리가 원하는 수준의 메시지만 볼 수 있도록 설정할 수 있다.
특정 수준만 골라서 보는 것은 불가능하며, 지정한 수준보다 심각한 수준은 모두 출력된다.
메시지 수준을 debug
로 설정하면, debug
또는 그보다 심각한 수준의 메시지가 출력된다.
debug, info, warn, error, fatal
메시지 수준을 warn
으로 설정하면, warn
또는 그보다 심각한 수준의 메시지가 출력된다.
설정파일은 src/main/resources
와 src/test/resources
에 각각 log4j.xml
이란 이름으로 존재한다(Spring MVC Project 기준)
설정 파일을 수정하여 원하는 형태의 로깅을 구현할 수 있다.
Logging Setting File Config
기본적으로 제공되는 log4j.xml
파일을 열면 다음과 같은 화면이 나온다.
위의 화면은 전체적인 디자인을 볼 수 있도록 제공되는 화면으로, 전체적인 구조를 볼 수 있지만 코드를 살펴보기 어려우므로 보는 방식을 변경해야 한다.
Source
탭을 클릭하면 다음과 같은 코드를 확인할 수 있다.
Copy <?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>
파일 형태
파일의 형태를 살펴보면 다음과 같다.
Copy <?xml version="1.0" encoding="UTF-8"?>
xml이면 반드시 있어야 하는 헤더 선언이다.
문서 선언(DTD : Document Type Definition)
Copy <!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
이 문서에서 사용할 태그의 정의 정보가 들어있다.
XML Namespace 선언(xmlns) 및 최상위 영역 생성
Copy <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
</log4j:configuration>
이 설정에서 사용할 최상위 영역을 선언하고, xmlns 설정을 통해 내부에서 사용할 정보들을 불러온다.
appender
org.apache.log4j.ConsoleAppender
org.apache.log4j.FileAppender
org.apache.log4j.RollingFileAppender
파일에 지정한 방식에 의해 분할 출력을 수행하는 도구
org.apache.log4j.DailyRollingFileAppender
org.apache.log4j.JdbcAppender
org.apache.log4j.SMTPAppender
org.apache.log4j.NTEventAppender
ConsoleAppender 예시
Copy <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 예시
Copy <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 예시
Copy <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)을 지정하여 메시지가 콘솔 화면에 출력되도록 설정한다.
Copy <param name="Target" value="System.out" />
File
FileAppender
, DailyRollingFileAppender
등과 같이 파일에 출력하는 Appender에서 사용한다.
상대경로로 작성 시 프로젝트 root를 기준으로 설정되며, 절대경로로 작성도 가능하다.
만약 폴더가 존재하지 않는다면 폴더를 생성해준다.
Copy <param name="file" value="D:/log.xml"></param>
Append
로그를 덧붙일 것인지(Append), 덮어쓸 것인지(Overwrite) 설정할 수 있다.
Copy <param name="Append" value="true"></param>
layout
%p
: priority, 메시지의 수준이 출력될 자리
%m
: message, 출력하고자 하는 메시지의 자리
%c
: category, 로그가 출력되는 대상의 카테고리가 출력될 자리
모든 자리는 숫자를 이용하여 형식을 설정할 수 있다.
%5p
: 메시지 수준을 +5 형식으로 출력(5칸에 우측(+
) 정렬)
%-5p
: 메시지 수준을 -5 형식으로 출력(5칸에 좌측(-
) 정렬)
Layout 예시
Copy <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
설정을 따라간다.
삭제해도 무방하다.
예시
Copy <logger name="org.springframework.core">
<level value="warn" />
</logger>
root
로그 메시지의 출력 수준과 방식을 설정할 수 있다.
appender-ref
: 로그 출력 Appender의 id를 설정. 복수 개 설정 가능
예시
Copy <root>
<priority value="debug" />
<appender-ref ref="console" />
<appender-ref ref="daily" />
</root>
최종 파일 양식
기본적인 설정들이 되어 있는 파일 양식은 다음과 같다.
Copy <?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>