2008. 8. 20. 15:01

JDK1.4 Logging API의 사용을 통한 Logging

▩ JDK1.4 Logging API의 사용을 통한 Logging

출처: http://www.nulunggi.pe.kr/board/board/edit.asp?ref=1768&number=1825&page=1&txtrCount=20&tableName=board&code=D6

   - 개발시 발생하는 에러외에 운영과정에서 발생하는 버그를 찾는 데 도움을 줌
   - 시스템이 운영되는 과정에서 발생하는 문제를 기록해 두었다가 복구용으로 사용함
   - 남겨야하는 모든 기록은 전부 남겨야 한다.
   - 불필요한 너무 많은 로그는 남기지 않는다.
   - 특히 로그메세지는 특정 사용자와 관련되어 있는 경우 아이디가 반드시 기록되도록 한다.
   -

1. 기본적인 Console 로그
>>>>> jdk14Logger.java
import java.util.logging.Logger;

public class Jdk14Logger1
{
    public static void main(String args[]){
        Logger.global.info("프로그램을 실행 했습니다.");
    }
}



2. Log Level
   - Level.SEVERE: 프로그램이 복구할 수 없는 치명적인 에러, 즉시 조치 필요
   - Level.WARNING: 심각한 에러이지만 즉각적인 처리를 하지 않아도 되는 경우
   - Level.INFO: 프로그램 실행 정보를 기록
   - Level.CONFIG: 프로그램 환경 정보 기록
   - Level.FINE, FINER, FINEST: 프로그램의 흐름을 추적할 때 사용(디버깅)
   - Level.ALL: 모든 로그 레벨을 기록
   - Level.OFF: 모든 로그 레벨을 기록하지 않음

   - ConsoleHandler의 기본 로그 레벨은 INFO임

>>>>> LoggerTest.java: Level의 지정
import java.util.logging.Logger;
import java.util.logging.Level;

public class Jdk14Logger2 {

    public static void main(String[] args) {
        Logger.global.setLevel(Level.WARNING);
       
        Logger.global.info("Start Program");
        Logger.global.config("Configuration");
        Logger.global.fine("Fine Level");
        Logger.global.warning("Warning Level");
        Logger.global.finer("Finer Level");
        Logger.global.severe("Severe Level");
        Logger.global.info("info Program");
    }
}



3. Logger Method
   - servere(String msg)
   - warning(String msg)
   - info(String msg)
   - config(String msg)
   - fine(String msg)
   - finer(String msg)
   - finest(String msg)

   - log(Level, String msg)
   - log(Level, String msg, Object param1)
   - log(Level, String msg, Throwable thrown)
   - logp(Level, String sourceClass, String sourceMethod, String msg)



4. JDK 1.4는 로거의 계층을 트리구조로 관리함

                 global
                   │
           ┌───┴───┐
           │              │
         visit            sky
           │              │
   ┌───┴───┐      │
   │              │      │
  edit            write   visit


Logger globalLogger = Logger.global;
Logger logger1 = Logger.getLogger("visit");  
Logger logger2 = Logger.getLogger("visit.edit");
Logger logger3 = Logger.getLogger("visit.write");
Logger logger4 = Logger.getLogger("sky.visit");



5. 로깅 API의 구조
   - Logger의 로깅 메소드가 호출되면 LogRecord 객체가 생성되고 그 객체는
     Logger에 등록되어 있는 Handler에 전달된다.
     LogRecord를 전달받은 핸들러는 그 핸들러가 이용하는 저장 방법에 따라 로그 데이터를
     기록한다.

   - LogRecord --> Logger:Filter --> Handler:Filter --> File, Console, DB에 출력함
                                                     │
                    │
                    └ Formatter



6. Jdk1.4에 등록된 Handler
   - MemoryHandler  : 메모리에 로그 데이터 저장
   - FileHandler    : 파일에 저장
     . /: 경로 구분자
     . %t: 시스템의 임시 디렉토리
     . %h: 현재 사용자의 홈 디렉토리
     . %g: 순환 로그의 구분에 필요한 문자
     . %u: 파일명 충돌을 피하기 위해 사용되는 고유숫자
     . %%: %문자 표현

   - SocketHandler  : 특정 서버로 전송
   - ConsoleHandler : 콘솔 화면에 출력
   - StreamHandler  : 이 클래스를 상속하여 새로운 핸들러 구현




▩ Logging API의 실습

1. FileHandler에서 XMLFormater의 사용

>>>>> Jdk14Logger3.java
import java.util.logging.Logger;
import java.util.logging.FileHandler;
import java.util.logging.Level;

public class Jdk14Logger3 {
    public static void main(String[] args) throws java.io.IOException {
        Logger jdk14Logger = Logger.getLogger("nulunggi.logger");
        jdk14Logger.setUseParentHandlers(false); 
        jdk14Logger.setLevel(Level.WARNING);
       
        FileHandler handler = new FileHandler("%h/java%u.log", 64*1024,3,true);
       
        jdk14Logger.addHandler(handler);
       
        jdk14Logger.severe("시스템에 심각한 문제가 발생했습니다.");
        jdk14Logger.warning("데이터베이스 접속에 실패 했습니다.");
    }
}



C:\Documents and Settings\Administrator폴더에 java0.log.0 파일이 생성되어 있습니다.



2. FileHandler에서 SimpleFormater의 사용

>>>>> LoggerFileText.java
import java.util.logging.Logger;
import java.util.logging.FileHandler;
import java.util.logging.SimpleFormatter;
import java.util.logging.Level;

public class Jdk14Logger4 {

    public static void main(String[] args) throws java.io.IOException {
        Logger jdk14Logger = Logger.getLogger("nulunggi.logger");
        jdk14Logger.setUseParentHandlers(false);
        jdk14Logger.setLevel(Level.FINE);
       
        FileHandler handler = new FileHandler("%h/java%u.log", 64*1024,3,true);
        jdk14Logger.addHandler(handler);
       
        SimpleFormatter formatter = new SimpleFormatter();
        handler.setFormatter(formatter);
       
        jdk14Logger.severe("시스템에 심각한 문제가 발생했습니다.");
        jdk14Logger.warning("데이터베이스 접속에 실패 했습니다.");
    }
}



3. 설정 파일: jre/lib/logging.properties
############################################################
#      Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property. 
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#      Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter


############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
visit.level = WARNING




▩ Log4J 활용하기
   - http://logging.apache.org/log4j/docs/index.html
   - Download: http://jakarta.apache.org/site/binindex.cgi
   - jakarta-log4j-1.2.8\dist\lib안에 있는 log4j-1.2.8.jar 파일을
      C:\j2sdk1.4.2_03\jre\lib\ext, D:\resin-2.1.11\lib폴더에 복사합니다.

1. Log Level
   - Level.FATAL: 치명적인 시각한 에러 발생시 사용
   - Level.ERROR: 어플리케이션이 수행 가능한 정도의 에러 발생시 사용
   - Level.WARN: 시스템에 문제를 일으킬수 있는 정도의 에러 발생시 사용
   - Level.INFO: 어플리케이션의 정보를 기록할때 사용
   - Level.DEBUG: 어플리케이션의 상태에 대한 상세 정보를 나타낼 때 사용


2. 로그 기록 Method
   - FATAL 로그 메시지 기록
     . fatal(Object message)
     . fatal(Object message, Throwable t)
   - ERROR 로그 메시지 기록
     . error(Object message)
     . error(Object message, Throwable t)
   - WARN 로그 메시지 기록
     . warn(Object message)
     . warn(Object message, Throwable t)
   - INFO 로그 메시지 기록
     . info(Object message)
     . info(Object message, Throwable t)
   - DEBUG 로그 메시지 기록
     . debug(Object message)
     . debug(Object message, Throwable t)


3. Console Log의 실습
   - BasicConfigurator.configure()은 기본적으로 콘솔 로그를 포함함

>>>>> log4jTest1.java
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.BasicConfigurator;

public class log4jTest1 {

    public static void main(String[] args) throws java.io.IOException {
        BasicConfigurator.configure();
       
        Logger logger = Logger.getLogger("visit");
        logger.setLevel(Level.INFO);
       
        Logger barlogger = Logger.getLogger("visit.log4jTest1");
       
        logger.info("방명록 테스트 시작.");
        logger.debug("DEBUG 레벨 로그.");
       
        barlogger.info("log4jTest1 로그 기록");
        barlogger.debug("log4jTest1 DEBUG 레벨 로그");

    }
}



4. PatternLayout의 변환 캐릭터
   - C: 로그 메시지를 기록하려는 클래스의 완전한 이름 출력
   - d: 로그 메시지를 기록한 시간을 기록한다.
   - p: 로그 메시지의 우선순위 출력
   - m: 로그메시지 자체
   - M: 로그메시지를 기록하려는 메소드의 이름
   - n: 플랫폼의 라인 구분자를 출력한다.
   - %: %%는 '%'를 출력한다.


5. Appender의 종류
   - org.apache.log4j.ConsoleAppender: 콘솔에 로그메시지를 출력한다.
   - org.apache.log4j.FileAppender: 파일에 로그메시지를 기록한다.
   - org.apache.log4j.RollingFileAppender: 파일에 로그메시지를 기록하고, 파일이 일정 크기가 되면 다른이름으로 저장하고
     , 새롭게 로그 메시지를 기록하기 시작한다.
   - org.apache.log4j.DailyRollingFileAppender: 파일에 로그 메시지를 기록하며, 하루 단위로 로그 파일을 변경한다.
   - org.apache.log4j.net.SMTPAppender: 로그메시지를 이메일로 전송한다.
   - org.apache.log4j.nt.NTEventLogAppender: NT의 이벤트 로그 시스템에 로그메시지를 전송한다.



6. 속성 파일을 이용한 로그의 기록
>>>>> log4j.properties
log4j.rootLogger=INFO, console

log4j.logger.visit.bean=DEBUG, R
log4j.additivity.visit.bean=false

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.SimpleLayout

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=d:/temp/java/test.log
log4j.appender.R.MaxFileSize=64KB
log4j.appender.R.MaxBackupIndex=3
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{1}.%M - %m%n


속성의 해설:
- 루트로거의 루트는 visit이다.
- 루트로거는 console Appender를 사용한다.
- console Appender는 SimpleLayout를 상용한다.
- visit.bean의 레벨은 DEBUG이다.
- visit.bean의 레벨의 로거는 상위 레벨의 Appender를 상용하지 않는다.
- visit.bean은 RollingFileAppender를 사용한다.
- RollingFileAppender는 D:\temp\java 폴더에 기록한다.
- RollingFileAppender가 기록하는 최대 로그 파일의 크기는 64Kb로 한다.
- RollingFileAppender는 최대 3개의 백업 로그를 만든다.
- RollingFileAppender는 PatternLayout을 사용한다.
- PatternLayout은 [%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{1}.%M - %m%n 을 사용한다.


속성파일의 사용은 PropertyConfigurator.configure("log4j.properties")을 추가한다.

>>>>> log4jTest3.java
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.PropertyConfigurator;

public class log4jTest3 {

    public static void main(String[] args) {
        PropertyConfigurator.configure("log4j.properties");
       
        Logger rootLogger = Logger.getRootLogger();
        rootLogger.info("프로그램 시작");
       
        Logger mailLogger = Logger.getLogger("visit.bean");
       
        mailLogger.info("테스트 시작.");
        mailLogger.debug("DEBUG 레벨 로그.");
       
        mailLogger.info("visit 로그 기록");
        mailLogger.debug("visit LOG DEBUG 레벨 로그");
       
        rootLogger.info("프로그램 끝");
    }
}




▩ 방명록에 Log4j적용하기
   - 자료실 325번 참고

>>>>> log4j.properties
log4j.rootLogger=INFO, console

log4j.logger.visit.bean=DEBUG, R
log4j.additivity.visit.bean=false

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.SimpleLayout

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=D:/resin-2.1.11/doc/jvisit_100_mysql_bean/logging/visit.log
log4j.appender.R.MaxFileSize=64KB
log4j.appender.R.MaxBackupIndex=3
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} %C{1}.%M - %m%n



>>>>> Log4j를 적용한 VisitMgr.java 빈즈
package visit;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.PropertyConfigurator;

public class VisitMgr {
    private final String JDBC_DRIVER = "org.gjt.mm.mysql.Driver";
    private final String JDBC_URL = "jdbc:mysql://localhost:3306/mysqldb?useUnicode=true&characterEncoding=euc-kr";
    private final String USER = "nulunggi";
    private final String PASS = "123";

    Logger rootLogger = Logger.getRootLogger();
    Logger visitLogger = Logger.getLogger("visit.bean");

    public VisitMgr(){
        PropertyConfigurator.configure("D:/resin-2.1.11/doc/jvisit_100_mysql_bean/logging/log4j.properties");   
        rootLogger.info("빈이 호출되었습니다.");
        visitLogger.info("VisitMgr빈의 생성자가 호출되었습니다.");

        try{
            Class.forName(JDBC_DRIVER);
        }catch(Exception e){
            visitLogger.fatal(USER + "계정에 대한 MySQL JDBC 드라이버 로딩 실패");
            System.err.println("Error: JDBC 드라이버 로딩 실패");
        }
    }
   
    public Vector getVisitList(){
        visitLogger.info("getVisitList()메소드가 호출되었습니다.");
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        Vector recList = new Vector();
        String strQuery = "SELECT num,wname,wcontent,reg_date,password FROM visit ORDER BY num DESC";

        try{
            conn = DriverManager.getConnection(JDBC_URL, USER, PASS);

            visitLogger.info("Mysql mysqldb 데이터베이스 접속되었습니다.");
           
            stmt = conn.createStatement();
            rs = stmt.executeQuery(strQuery);
            while(rs.next()){
                VisitBean recBean = new VisitBean();
                recBean.setNum(rs.getInt("num"));
                recBean.setWname(rs.getString("wname"));
                recBean.setWcontent(rs.getString("wcontent"));
                recBean.setReg_date(rs.getString("reg_date"));
                recBean.setPassword(rs.getString("password"));
               
                recList.add(recBean);   
            }
        }catch(Exception e){
           
            visitLogger.error(strQuery + "를 실행하는 중 에러가 발생했습니다.");
           
            System.out.println("Exception:" + e);
        }finally{
            if(rs != null) try{rs.close();} catch(SQLException e){}
            if(stmt != null) try{stmt.close();} catch(SQLException e){}
            if(conn != null) try{conn.close();} catch(SQLException e){}
            System.out.println("getVisitList() 메소드가 호출되었습니다.");
        }
        return recList;
    }
}



'My work space > Java' 카테고리의 다른 글

Ⅰ. UML 개요  (0) 2008.08.20
J2EE , J2SE 한글 API [다운가능]  (0) 2008.08.20
프로그래밍에유용한사이트  (0) 2008.08.20
AWT/SWING 성능 비교(기본 출력 기능)  (0) 2008.08.20
소켓(Socket)  (0) 2008.08.20