로깅(Logging)
로그(Log)란 프로그램 개발이나 운영 시 발생하는 문제점을 추적하거나 운영 상태를 모니터링 하기 위한 텍스트를 말한다.
로그를 남기기 위해서 가장 쉬운 방법은 System.out.println()을 이용하는 것이다.
좀 더 향상된 방법은 프로그래머가 직접 로깅을 위한 클래스를 만들어 사용하는 것이다.
다음은 로그를 파일에 남기는 자바 클래스이다.
Log.java
package net.java_school.util;
import java.io.*;
import java.util.Date;
public class Log {
public String logFile = "C:/debug.log";
FileWriter fw = null;
public Log() {
try {
fw = new FileWriter( logFile, true );
} catch ( IOException e ){}
}
public void close() {
try {
fw.close();
} catch ( IOException e ){}
}
public void debug( String msg ) {
try {
fw.write( new Date()+ " : " );
fw.write( msg + " \r\n" );
fw.flush();
} catch ( IOException e ) {
System.err.println( "IOException!" );
}
}
}
아래와 같은 파일을 만들어 테스트한다.
LogTest1.java
package net.java_school.logtest;
import net.java_school.util.Log;
public class LogTest1 {
public void xxx() {
Log log = new Log(); // 출력스트림을 얻는다.
log.debug("로그 테스트!"); // 로그 메시지 남기기
log.close(); // 출력스트림을 닫는다.
}
public static void main(String[] args) {
LogTest1 test = new LogTest1();
test.xxx();
}
}
log4j
사용자 정의 로깅 클래스를 이용하는 것보다는 로깅 프레임워크를 이용하는 것이 좋다.
대표적인 로깅 프레임워크는 log4j가 있다.
자바 API에서도 로깅을 제공하고 있지만 현실은 log4j라는 아파치 그룹의 오픈 소스가 더 많은 호응을 받고 있기 때문에
여기서는 log4j를 소개하고 있는 것이다.
log4j를 사용하기 위해서는 아래 경로에서 log4j 바이너리 파일을 다운로드 한다.
http://logging.apache.org/log4j/1.2/download.html
압축을 푼 후 jar파일(log4j-1.2.15.jar)을 클래스패스로 설정되어 있는 경로에 복사하고 아래와 같은 프로퍼티 파일을 클래스패스로 설정되어 있는
경로에 생성해야 한다.
log4j.properties
log4j.rootLogger = INFO,console log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.layout = org.apache.log4j.SimpleLayout log4j.appender.file = org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File = C:/debug.log log4j.appender.file.DatePattern = '.'yyyy-MM-dd log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern = [%d]%5p [%t] (%F:%L) - %m%n log4j.logger.net.java_school = DEBUG,file
다음으로 아래와 같이 테스트를 위한 파일을 만들어 테스트해 본다.
LogTest2.java
package net.java_school.logtest.log4j;
import org.apache.log4j.Logger;
public class LogTest2 {
// 로거 얻기
private Logger log = Logger.getLogger(LogTest2.class);
//또는 private Logger log = Logger.getLogger(this.getClass());
public void xxx() {
if (log.isInfoEnabled()) {
log.info("info message");
}
}
public static void main(String[] args) {
LogTest2 test = new LogTest2();
test.xxx();
}
}
테스트 후 콘솔과 C:/debug.log 파일에 로그 메시지를 확인한다.
LogTest1.java 와 같이 파일에 로그를 남기지만 로그를 남긴 후 출력스트림을 닫는 코드는 없다.
log4j.properties 파일의 내용 설명
log4j는 3개의 컴포넌트로 이루어져 있다.
logger, appender, layout 이 그것인데 이들 컴포넌트가 협력하여 로그의 레벨에 따라 기록되도록 한다.
또한 런타임에 이들 메시지가 어떻게 포맷되고 어디에 리포트되어야 하는지를 컨트롤하는 것도 가능하게 한다.
- Logger : 로그의 주체(로그 파일을 작성하는 클래스)로 로깅 메세지를 Appender에 전달
- Appender : 전달된 로깅 메세지의 출력 대상을 지정
- Layout : 어떤 형식으로 출력할 것이지를 결정
log4j.rootLogger = INFO,console
rootLogger는 최상위 로거다. 언제나 존재하고 모든 로거들 중 계층적으로 가장 위에 위치한다.
루트 로거의 로그 레벨과 어펜더를 지정하고 있다.
참고로, 여기서는 하나의 어펜더를 지정했지만 어펜더는 여러개 지정할 수 있다.
console은 사용자가 지은 어펜더 이름이다.
로그 레벨은 TRACE > DEBUG > INFO > WARN > ERROR > FATAL 인데 INFO 로 설정되었으므로 INFO 이상의 로그는
기록된다.
log4j.appender.console = org.apache.log4j.ConsoleAppender
console이란 이름의 어펜더가 실제 어떤 클래스인지를 나타내고 있다.
org.apaceh.log4j.ConsoleAppdender는 로깅 메세지를 콘솔에 출력하고자 할 때 사용하는 클래스이다.
log4j에서 로그메시지가 출력되는 목적지가 어펜더이다.
현재 콘솔, 파일, GUI 컴포넌트, 리모트 소켓 서버, JMS, NT Event 로거, 리모트 UNIX Syslog 데몬에 대한 어펜더가 존재한다.
log4j.appender.console.layout = org.apache.log4j.SimpleLayout
console어펜더는 SimpleLayout으로 출력한다.
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
file은 사용자가 지은 어펜더의 이름이다.
file어펜더가 org.apache.log4j.DailyRollingFileAppender클래스임을 나타내고 있다.
DailyRollingFileAppender클래스는 로그 출력을 파일에 쌓이도록 하고자 할 때 사용하는 클래스이다.
log4j.appender.file.File = C:/debug.log
file어펜더가 지정하는 출력대상 파일의 절대 경로를 지정하고 있다.
log4j.appender.file.DatePattern = '.'yyyy-MM-dd
날짜가 지난 로그는 파일명이 debug.log.2009-08-27 에 저장되도록 지정하고 있다.
log4j.appender.file.layout = org.apache.log4j.PatternLayout
file어펜더는 org.apache.log4j.PatternLayout을 사용한다는 설정이다.
PatternLayout을 사용하면 사용자가 정한 패턴에 따라 출력되도록 설정할 수 있다.
log4j.appender.file.layout.ConversionPattern=[%d]%5p [%t] (%F:%L) - %m%n
출력 패턴을 지정하고 있다.
log4j.logger.net.java_school = DEBUG,file
net.java-school이라는 이름의 새로운 로거를 설정하고 있다.
로거 이름을 net.java_school이란 팩키지 이름으로 설정하면 해당 팩키지에 속한 자바 클래스는 물론
net.java_school.logtest.log4j 팩키지의 모든 자바 클래스가 남기는 모든 로그는 이 로거에 의해 기록된다.
net.java_school 로거는 로그 레벨은 DEBUG, 어펜더는 file이다.
Log 처리 메시지 및 로그 레벨
- FATAL : 가장 심각한 오류, 콘솔에 출력
- ERROR : 일반적인 오류, 콘솔에 출력
- WARN : 주의를 요하는 경우, 콘솔에 출력
- INFO : 런타임 시 관심있는 이벤트, 콘솔에 출력
- DEBUG : 시스템 흐름과 관련된 상세정보, 로그 파일로만 출력
- TRACE : 가장 상세한 형태의 정보, 로그 파일로만 출력
log4j Appender 주요 클래스
- ConsoleAppender : 콘솔에 로그 메시지 출력
- FileAppender : 파일에 로그 메시지 기록
- RollingFileAppender : 파일에 로그 메시지 기록하고, 파일 크기가 일정 수준 이상이 되면 다른 이름의 새파일을 생성하고 기록
- DailyRollingFileAppender : 파일에 로그 메시지 기록하고, 하루 단위로 로그 파일을 변경해서 기록
- SMTPAppender : 로그 메시지를 이메일로 전송
- NTEventAppender : 윈도우즈 시스템 이벤트 로그로 메시지 전송
log4j Layout 클래스
- DateLayout : 로그 메시지를 날짜 중심으로 간단하게 기록
- HTMLLayout : 로그 메시지를 HTML 형식으로 기록
- PatternLayout : 로그 메시지를 사용자 정의 패턴에 따라 기록
- SimpleLayout : 레벨-메시지 형식의 가장 간단하게 로그 기록
- XMLLayout : 로그 메시지를 XML 형식으로 기록
log4j 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)
log4.xml
다음은 log4j.properties 파일 대신 log4j.xml 파일을 설정 파일로 이용하는 방법이다.
log4j.properties 파일을 지우고 같은 설정 내용인 log4j.xml 파일을 클래스 패스가 걸려있는 경로에 생성한다.
log4.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.SimpleLayout"/>
</appender>
<appender name="file" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="C:/debug.log" />
<param name="datePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d]%5p [%t] (%F:%L) - %m%n"/>
</layout>
</appender>
<logger name="net.java_school">
<level value="DEBUG"/>
<appender-ref ref="file"/>
</logger>
<root>
<level value="INFO"/>
<appender-ref ref="console"/>
</root>
</log4j:configuration>
Test2.java 를 다시 실행하여 테스트한다.
자카르타 Commons 로깅
아파치 그룹의 자카르타 commons-logging 팩키지는 개발자들에게 공통 로깅 API를 제공하기 위해 만들어진 프레임워크로 애플리케이션이 특정 로깅 API에 종속되는 것을 막아준다. 현재 많은 서드 파티 로깅 프레임워크들이 commons-logging 기반으로 구현되어 있다.
commons-logging 사용법
http://commons.apache.org/downloads/download_logging.cgi
에서 Binary 파일을 다운로드한다. (만약 위 링크가 깨진다면 http://www.apache.org 에서
commons 선택하고 http://commons.apache.org 에서
Logging 선택하면 다운로드 경로를 찾을 수 있다)
commons-logging은 자체적으로 로깅을 지원한다기보다는 여러 로깅 API를 표준화된 방법으로 사용할 수 있게 해주는 개념이기 때문에,
실제 로깅 처리를 위한 별도의 로깅 구현 솔루션이 필요하다.
사실 지금 다운로드한 commons-logging 팩키지에도 SimpleLog 클래스란 로깅 구현체가 포함되어 있지만 콘솔을 이용한 출력만 되므로
잘 쓰이지 않는다.
여기서는 로깅 구현체로 log4j를 사용하는 방법을 제시한다.
아래 프로퍼티 파일을 클래스 패스 경로에 만들어 놓는다.
commons-logging.properties
org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger
아래와 같은 테스트 파일을 만들어 테스트 해 본다.
실습을 위해선 먼저 commons-logging jar 파일(commons-logging-1.1.1.jar)을 클래스 패스에 추가해야 한다.
LogTest3.java
package net.java_school.logtest.log4j;
/* 이 부분이 log4j를 단독으로 사용할 때와 다르다 */
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class LogTest3 {
// 로거 얻기 역시 log4j를 단독으로 사용할 때와 다르다
private Log log = LogFactory.getLog(LogTest3.class);
// 또는 private Log log = LogFactory.getLog(this.getClass());
public void xxx() {
if (log.isInfoEnabled()) {
log.info("info message");
}
}
public static void main(String[] args) {
LogTest3 test = new LogTest3();
test.xxx();
}
}
