Java/일반

Java Logging

창욱씨 2020. 4. 3. 14:30

1. Logging이란

 Log란 시스템 동작 시 시스템 상태, 작동 정보를 시간의 경과에 따라 기록한 것을 말합니다. 그리고 Logging이란 정보를 제공하는 일련의 기록인 Log를 생성하도록 시스템을 작성하는 활동을 말합니다. 저장된 Log는 사용자의 패턴이나 시스템 동작 자체의 분석에 사용될 수 있으며 해킹이나 침입 등의 사고가 발생한 경우 비정상 동작의 기록을 통해 감사 추적을 수행할 수 있습니다.

Logging의 장점

  • Log는 재현하기 힘든 버그에 대한 유용한 정보를 제공
  • Log는 성능에 관한 통계와 정보를 제공할 수 있음
  • 설정이 가능할 때, Log는 예기치 못한 특정 문제들을 디버그하기 위해, 그 문제들을 처리하도록 코딩하지 않아도 일반적인 정보를 갈무리할 수 있음

2. Java.util.logging

 JDK에 포함된 기본적인 Logging 라이브러리입니다. 하지만 기능이 많이 부족해 다른 Logging 라이브러리를 더 많이 사용합니다. 우선 가장 간단한 예시는 아래와 같습니다. Log에 대한 수준(level)을 지정해 메시지를 콘솔에 표시하는 경우입니다.

import java.util.logging.Level;
import java.util.logging.Logger;

public class MainEntry {
    private final static Logger LOG = Logger.getGlobal();

    public static void main(String[] args) {
        LOG.setLevel(Level.INFO);

        LOG.severe("severe Log");
        LOG.warning("warning Log");
        LOG.info("info Log");
    }
}

 로그의 일반적인 형식은 이미 정해져 있습니다. 만약 나만의 로그 형식을 원한다면 우선 Formatter 클래스를 상속받아 다음과 같은 클래스를 정의해야 합니다.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

public class CustomLogFormatter extends Formatter {
    public String getHead(Handler h) {
        return "START LOG\n";
    }

    public String format(LogRecord rec) {
        StringBuffer buf = new StringBuffer(1000);

        buf.append(calcDate(rec.getMillis()));

        buf.append(" [");
        buf.append(rec.getLevel());
        buf.append("] ");

        buf.append("[");
        buf.append(rec.getSourceMethodName());
        buf.append("] ");

        buf.append(rec.getMessage());
        buf.append("\n");

        return buf.toString();
    }

    public String getTail(Handler h) {
        return "END LOG\n";
    }

    private String calcDate(long millisecs) {
        SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date resultdate = new Date(millisecs);
        return date_format.format(resultdate);
    }
}

 그리고 이 Formatter클래스를 다음과 같이 사용할 수 있습니다.

import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MainEntry2 {
    private final static Logger LOG = Logger.getGlobal();

    public static void main(String[] args) {
Logger rootLogger = Logger.getLogger("");
        Handler[] handlers = rootLogger.getHandlers();
        if (handlers[0] instanceof ConsoleHandler) {
            rootLogger.removeHandler(handlers[0]);
        }

        LOG.setLevel(Level.INFO);

        Handler handler = new ConsoleHandler();
      // 파일 저장을 원할 경우에는 new FileHandler()를 선언해주면 됩니다. 
        CustomLogFormatter formatter = new CustomLogFormatter();
        handler.setFormatter(formatter);
        LOG.addHandler(handler);

        LOG.severe("severe Log");
        LOG.warning("warning Log");
        LOG.info("info Log");
    }
}

3. Apache Commons Logging

 Apache 재단의 Commons 라이브러리 중에 Logging을 제공하는 라이브러리입니다. 참고로 Commons Logging은 이 자체가 로깅을 수행하지 않습니다. 다른 Logger를 설정에 따라 호출하여 Logging을 수행합니다. Commons Logging은 아래와 같이 사용합니다.

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class IbatisWithMysqlBoardDAO extends SqlMapClientDaoSupport implements BoardDAO {
    // LogFactory는 사용자의 시스템에 알맞은 Log를 생성해주는 클래스
    // Log는 Log4j와 같은 Logging 라이브러리의 구현체를 연결하기 위한 인터페이스
     protected final Log logger = LogFactory.getLog(getClass());

     public List findBoardList(int currentPage, int countPerPage) throws SQLException {
          logger.debug("로그테스트");
     }
}

 참고로 Log 구현체는 Log를 기록할 때 Commons Logging API의 Log Level을 실제로 사용하는 Logging API의 Log Level로 알맞게 매핑해 줍니다.

Commons Logging

Log4J

Java.util.logging

TRACE

DEBUG

FINEST

DEBUG

DEBUG

FINE

INFO

INFO

INFO

WARN

WARN

WARNING

ERROR

ERROR

SEVERE

FATAL

FATAL

SEVERE

4. Log4J

 Apache 재단에서 제공하며 가장 많이 사용되는 Logging 라이브러리 중 하나입니다. Log4J는 크게 Logger, Appender, Layout의 3가지 요소로 구성되어 있습니다.

Log4J의 Log Level

  • FATAL: 치명적인 에러
  • ERROR 에러
  • WARN: 경고
  • INFO: 정보
  • DEBUG: 상세 정보

Appender

  • ConsoleAppender: 콘솔에 메시지를 출력
  • FileAppender: 파일에 메시지를 기록
  • RollingFileAppender: 파일에 메시지를 기록하며, 파일이 일정 크기가 되면 다른 이름으로 저장하고 새롭게 메시지를 기록
  • DailyRollingFileAppender: 파일에 메시지를 기록하며, 하루 단위로 파일을 변경
  • SMTPAppender: 메시지를 이메일로 전송

Layout

주로 PatternLayout을 사용합니다.

  • %C: 메시지를 기록하려는 클래스의 이름을 출력(패키지 계층 제어 가능)
  • %d: 메시지 기록 시간 출력(포맷 지정 가능)
  • %p: 메시지의 우선 순위 출력
  • %m: 메시지 자체를 출력
  • %M: 메시지를 기록하려는 메소드의 이름 출력
  • %n: 플랫폼의 라인 구분자를 출력
  • %r: 어플리케이션이 시작되어 로깅 이벤트가 발생하는 시점까지의 경과 시간을 밀리세컨드로 출력
  • %l: Logging이 발생한 caller의 정보를 출력
  • %L: Logging이 발생한 caller의 라인 수를 출력
  • %x: Logging이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력
  • %X: Logging이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력
  • %F: Logging이 발생한 프로그램 파일 명을 출력
  • %t: Logging 이벤트가 발생한 스레드의 이름을 출력

Log4J의 특징

  • 속도에 최적화되어 있음
  • 이름있는 Log 계층에 기반
  • Thread-safe 함
  • property파일과 xml 형식으로 실행 중 수정 적용 가능

Log4J 설정파일 예시

<?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.mycompany.sd">
        <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>

5. Logback

 Log4j의 단점 개선 및 기능을 추가하여 개발된 Logging 라이브러리입니다.

Logback의 특징

  • 일반적인 Logging 라이브러리들은 설정을 변경하면 프로그램의 재시작이 필요합니다. 하지만 Logback은 설정 파일을 스캔하는 별도의 스레드를 두어 지정한 시간마다 설정 파일을 스캔해 프로그램의 재시작 없이 설정을 적용시킬 수 있습니다.
  • Log 파일을 생성할 때, 별도의 프로그램을 통해 압축을 진행할 필요 없도록 자동 압축을 지원하며, 시간 또는 개수를 설정하여 이를 초과할 경우 로그 파일이 자동으로 삭제되도록 할 수 있습니다.
  • Log 파일들을 원격 서버에 저장시킬 수 있는데, 문제가 발생할 경우에 일반 라이브러리들은 복구를 위해 프로그램 중단 및 재시작을 해야합니다. 하지만 Logback은 프로그램 중지 없이 장애 발생 시점으로부터 자동 복구를 지원합니다.
  • 설정 파일에 조건문을 사용할 수 있습니다.

Logback 사용법

 우선 아래 3개의 라이브러리를 받아줍니다.

logback-classic.x.x.x.jar
logback-core.x.x.x.jar
slf4j-api-x.x.x.jar

Logback 설정 파일

 Log4J와 유사합니다.

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


  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>


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

6. SLF4J

 SLF4J(Simple Logging Façade For Java)란 Façade Pattern을 적용한 Logging 프레임워크입니다. Logging과 관련된 Interface의 모음이라고 생각하면 됩니다.

Façade Pattern

 여러 개의 클래스가 하나의 역할을 수행할 때, 대표적인 인터페이스만을 다루는 클래스를 두어 원하는 기능을 처리할 수 있게 도와주는 패턴입니다.

SLF4J의 특징

  • JVM에 의해 유효성 체크가 되며, 바인딩 된 Logging Framework가 없다면 아무 동작을 하지 않음
  • 직접 Logging을 하지 않음

SLF4J의 모듈

  • SLF4J API
  • SLF4J Binding: SLF4J 인터페이스를 Logging 구현체와 연결하는 어댑터 역할을 하는 라이브러리
  • SLF4J Bridging Modules: 다른 Logging API로의 Logger 호출을 SLF4J 인터페이스로 연결하여 SLF4J가 대신 처리할 수 있도록 하는 일종의 어댑터 역할을 하는 라이브러리

참조: http://www.gisdeveloper.co.kr/?p=5174
참조: https://blog.naver.com/kotaeho0512/50033476064
참조: https://dololak.tistory.com/631?category=636500

728x90