'log4j'에 해당되는 글 3건

  1. 2008.03.28 log4j 사용법

자바세계에서 Log4j를 이용하지 않고 로깅을 한다는 것은 요즘 거의 있을 수 없는 지경까지 왔다.
남들은 다 알고 있고, 활용하고 있는 log4j를 나만 모른다면 나만 바보 되는 것 아닌가?

이참에 log4j를 확실히 알아보고 실제로 활용해보자.

자! 들어간다.
log4j를 변형한 많은 변종들이 난무하고 있지만 그래도 대부분 오리지날과 유사하므로 오리지날로 배워보자.

1. log4j를 다운로드 받는다.
http://logging.apache.org/log4j/1.2/download.html 로 가서 맘에 드는 걸로 다운로드 받는다.

다운로드 받은 파일을 /home/midgard/software 에 저장하고 압축을 푼다.
linux에서 하는 쉬운 방법은
shell>tar xvfz ap*.gz <enter>

apache-log4j-1.2.15 폴더가 생기고 관련 파일이 그 아래에 생긴다.

2. Application에서 logging 한다.
package com.kisinfo.sarah.log4j.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.log4j.Logger;

import com.kisinfo.sarah.log4j.task.TimeTask;


public class TimeServer {
 
 public static void main(String[] args) {
  Logger logger = Logger.getLogger(TimeServer.class);
  try {
   ServerSocket ss = new ServerSocket(8989);
   logger.debug("server bind to 8989 port");
   while (true) {
    Socket s = ss.accept();  
    logger.info("server connection accpted");
    Runnable task = new TimeTask(s);
    logger.debug("server created timetask");
    new Thread(task).start();  
    logger.debug("server created thread and let it handle client request");
   }
  }
  catch(IOException io) {
   logger.fatal("server get an IOException and exit");
  }
 }
}
 - TimeServer.java

package com.kisinfo.sarah.log4j.task;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;

import org.apache.log4j.Logger;

public class TimeTask implements Runnable {
 private Logger logger = Logger.getLogger(this.getClass());
 private Socket s;
 
 public TimeTask(Socket s) {
  this.s = s;
 }
 
 public void run()  {
  BufferedReader br = null;
  PrintWriter pw = null;
  try {
   pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
   logger.debug("receive time request from client " + s.getRemoteSocketAddress());
   pw.println(new Date().toString());
   logger.debug("send time response to client");
   pw.flush();          
  }
  catch(IOException ie) {
   logger.error("IOException occured");
  }
  finally {
   try {
    if (pw != null)
     pw.close();
    if (s != null)
     s.close();
   }
   catch(Exception ignore) {
    logger.warn("ignoring Exception");
   }
  }
 }
}
- TimeTask.java


package com.kisinfo.sarah.log4j.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import org.apache.log4j.Logger;


public class TimeClient {
 private Logger logger = Logger.getLogger(this.getClass());
 
 public String getCurrentTime() throws IOException {
  Socket s = null;
  PrintWriter pw = null;
  BufferedReader br = null;
  try {
   s = new Socket("localhost",8989);
   logger.info("connection success to server");
   br = new BufferedReader(new InputStreamReader(s.getInputStream()));
   logger.debug("get time response from server");
   String time = br.readLine();
   logger.debug("server time is " + time);
   return time;
  }
  catch(IOException ie) {
   logger.error("IOException occured");
   throw ie;
  }
  finally {
   try {
    if (br != null)    
     br.close();
    if (s != null)
     s.close();
   }
   catch(Exception e) {
    logger.warn("Exception ignoring");
   }
  }
 }

 public static void main(String[] args) {
 
  try {
   String current = new TimeClient().getCurrentTime();
  }
  catch(Exception e) {
   e.printStackTrace();
  }
 }
}
- TimeClient.java


4. compile *.java 프로그램

5. log4j 설정
압축을 푼 폴더 아래 tests 폴더 아래 input 아래 xml 폴더에 있는 defaultInit.xml 를 복사한 후 이름을 log4j.xml로 수정한 다음 시작해보자
아래가 바로 그 오리지날 내용이다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<log4j:configuration debug="true" xmlns:log4j="http://jakarta.apache.org/log4j/"
>

  <appender name="D1" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
    </layout>
  </appender>

  <root>
    <priority value ="OFF" />
    <appender-ref ref="D1" />
  </root>

</log4j:configuration>


6. 프로그램의 실행
shell>cd /home/midgard/software/apache-log4j-1.2.15 <enter>
shell>javac -d classes -classpath apache-log4j-1.2.15:classes <enter>
shell>java -classpath apache-log4j-1.2.15:classes -Dlog4j.configuration=file:///home/midgard/software/apache-log4j-1.2.15/log4j.xml com.kisinfo.sarah.log4j.server.TimeServer <enter>

log4j: reset attribute= "false".
log4j: Threshold ="null".
log4j: Level value for root is  [OFF].
log4j: root level set to OFF
log4j: Class name: [org.apache.log4j.ConsoleAppender]
log4j: Parsing layout of class: "org.apache.log4j.PatternLayout"
log4j: Setting property [conversionPattern] to [%-5p %c{2} - %m%n].
log4j: Adding appender named [D1] to category [root].


7. log4j.xml 의 수정
ㄱ. appender 지정
     현재 appender는 "D1"이라는 이름으로 ConsoleAppender 하나가 있는데 이넘 대신에 sarah 라는 이름의 FileAppender 하나 만들겠음
  <appender name="D1" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
    </layout>
  </appender>

   -> 변경함
  <appender name="sarah" class="org.apache.log4j.FileAppender">
    <param name="File"   value="/home/midgard/software/apache-log4j-1.2.15/sarah
.log" />
    <param name="Append" value="false" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
    </layout>
  </appender>

ㄴ. category 지정
   <root> category를 지워버리고 아래의 카테고리를 지정

   <category name="com.kisinfo.sarah.log4j">
     <priority value="DEBUG" />
     <appender-ref ref="sarah"/>
   </category>


 8. appender를 추가하고자 할때
 - TimeServer가 로깅하는 것은 server.log에 TimeTask가 로깅하는 것은 task.log에 기록하고자 한다면
 appender를 2개 추가한다.

  <appender name="server" class="org.apache.log4j.FileAppender">
    <param name="File"   value="/home/midgard/software/apache-log4j-1.2.15/serve
r.log" />
    <param name="Append" value="true" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
    </layout>
  </appender>

  <appender name="task" class="org.apache.log4j.FileAppender">
    <param name="File"   value="/home/midgard/software/apache-log4j-1.2.15/task.
log" />
    <param name="Append" value="true" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
    </layout>
  </appender>

- Category를 추가한다.
   추가한 category의 출력이 어느 Appender로 향하는지 지정해준다. 각각 server , task appender로 보낸다.
 
   <category name="com.kisinfo.sarah.log4j.server.TimeServer">
     <priority value="DEBUG" />
     <appender-ref ref="server"/>
   </category>

   <category name="com.kisinfo.sarah.log4j.server.TimeTask">
     <priority value="DEBUG" />
     <appender-ref ref="task"/>
   </category>

9. Logging Level을 변경하고자 할때
  logging 레벨은 category에서 변경하면 된다.
  appender로 연결되어 있는 category 에서 priority value 값을 적절하게 지정하면 된다.
  DEBUG로 지정하면 application 소스에 logger.debug(...) logger.info(...), logger.warn(...) logger.error(..), logger.fatal(...)로 로깅한 모든것이 appender로 보내어지고,
  INFO로 지정하면 application 소스에 logger.debug(..)로 로깅한 것은 전달되지 않는다.
  WARN으로 지정하면 logger.warn(...),logger.error(...),logger.fatal(...)로 지정한 것만 전달된다.
  개발 모드에서는 DEBUG가 적당하고 운영모드에서는 INFO 혹은 WARN으로 운영할 수 있도록 하자.


  그리고 하나의 category에 여러개의 appender를 지정할 수 있으므로 하나의 로깅정보가 여러개의 appender로 보내질 수 있다.
  예을들어
    <category name="com.kisinfo.sarah.log4j.server.TimeTask">
     <priority value="DEBUG" />
     <appender-ref ref="task"/>
     <appender-ref ref="server"/>
   </category>

10. 로깅 포맷의 변경
  logging 포맷은 각 appender에서 지정할 수 있는데
  <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>을

  <param name="ConversionPattern" value="%d %-5p [%l] %m%n"/>로 변경해보자.

  좀더 많은 로깅정보가 포함 될 것이다.

자신의 애플리케이션 특성에 맞게 log4j.xml 정보를 적절히 조정하면 된다.




 


Posted by
,