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)
위의 방식들은 Logger를 직접 만들어야 한다는 불편한 점이 있는데, 이를 개선한 형태가 Annotation 형태이다. Lombok
라이브러리에서 지원하는 기능이며 @Slf4j
를 대상클래스 위에 선언하면 자동으로 다음 Logger가 생성된다. #lombok-3
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
공식 API 문서 보기
Appender
태그는 로그 출력 도구 이다.
모든 출력 클래스는 Appender
를 상속받아 구현해야 하며 주요 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
공식 API 문서 보기
Layout
을 통하여 출력되는 메시지의 형태를 설정할 수 있다.
Log4j의 모든 레이아웃은 Layout
을 상속받아 구현되도록 되어 있다.
그 중 패턴을 지정할 수 있는 PatternLayout
의 주요 형식은 다음과 같다.
%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>