Java日志組件 log5j 使用介紹

jopen 12年前發布 | 65K 次閱讀 Java 日志處理

大家都很熟悉log4j啦,log5j在log4j的基礎上提供了幾個改進,應該說是簡單和實用的封裝。有趣的是log5j主頁對自己名字的解釋,因為要感謝JDK 1.5,所以才叫了這個名字,不知道是不是升級到JDK1.7以后叫log7j :)

主頁是:http://code.google.com/p/log5j/ 大家可以看看,現在的版本是2.1.2。

log5j有幾個封裝是非常實用的,解釋功能的同時我們稍微看看代碼,有些很有趣的地方:

1,不需要指定log所在的類名了


原來的用法:

 

    private static final Logger log = Logger.getLogger( FeedTask.class );

新用法:

    private static final Logger log = Logger.getLogger();

這個可以避免復制的時候忘記改類名。

我們看看代碼,Logger里的:

 

    public static Logger getLogger() {
        return getLogger(getCallerClassName(), true);
    }

    private static String getCallerClassName() {
        //有趣
        return new Exception().getStackTrace()[2].getClassName();
    }
 

 取類名的時候用的是new了一個Exception,直接截取沒用反射,簡單直接。

2,支持message的format
原來:
 

    log.debug( "This thing broke: " + foo + " due to bar: " + bar + " on this thing: " + car );

現在:
 

    log.debug( "This thing broke: %s due to bar: %s on this thing: %s", foo, bar, car );

這個也很方便,效率也提高了,默認用了java.util.Formatter。
我們看看代碼:

LogEvent里的:
 

    public String message() {
        if (_params == null || _params.length == 0) {
            return _formatMessage;
        } else {
           //有趣
            return __tlMessageFormatter.get().format(_formatMessage, _params);
        }
    }
 

 其中format那部分共了工廠模式,實現的地方是:

 

    public class DefaultMessageFormatter implements MessageFormatter {
        private final Formatter _formatter;

        public DefaultMessageFormatter(Locale locale) {    

            //定義一個formatter
            _formatter = new Formatter(locale);
      }

      public String format(String format, Object... args) {
          StringBuilder sb = (StringBuilder) _formatter.out();
          try {
              //格式化message 
              _formatter.format(format, args);
              return sb.toString();
          } finally {
              sb.setLength(0);
          }
      }
   } 

3,新接口
可以這樣用:

 

    private static final Log log = LogFactory.getLog(); 
    try {     
        // do something     
        log.d("Success! Parameters f=$.10f and i=%d", f, i);   
    } catch (Exception e) {     
        log.e(e, "Failure! Parameters f=$.10f and i=%d", f, i);     
        // note: exception passed first separate from parameters   
    }
 

這個作者也說,仁者見仁,智者見智了。
Log實現在LogImpl里,其實Logger這個類實現在AbstractLoggable,這里有個問題,重復了。
我們回到主線Logger的調用方式上來吧。

4,可以顯式關閉Log。
這樣用:

// initialization phase   
com.spinn3r.log5j.LogManager.enableExplicitShutdown();    ...    
// in the very end of the shutdown routine   
com.spinn3r.log5j.LogManager.shutdown();
 

 這個是說如果可以接受log message丟失,并且本身應用程序可以控制自身的初始化和銷毀的話,可以用。
這個和log5j的異步log方式有關。

5,性能
簡化的寫法,看代碼:
  Logger:
  
 

    public void debug(java.lang.Object message) {
        super.debug(String.valueOf(message));
    }
 


 AbstractLoggable:
  
 

    public void debug(String formatMessage, Object... params) {
        if (_logger.isEnabled(LogLevel.DEBUG)) {
             log(LogEvent.create(_logger, _logName, LogLevel.DEBUG,
                    formatMessage, params));
        }
    }
 

可見,不需要用logger.isDebugEnabled()這樣的代碼了。

另外log5j是默認使用異步方式的。
主要實現在AsyncLogger里:

 

  private static final int MAX_QUEUE_SIZE = 100000;

  private static final AtomicLong __errorCounter = new AtomicLong();

  //存LogEvent的Queue
   private final BlockingQueue<LogEvent> __logEventQueue =
             new ArrayBlockingQueue<LogEvent>(MAX_QUEUE_SIZE);

  //寫Log的線程
   private final WriterThread _writerThread;

  //加入Event
   public void add(LogEvent event) {
         if (!__logEventQueue.offer(event)) {
             logFallback(event);
         }
     }

 這個是個生產者消費者模式,WriterThread是消費者。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!