Java日志组件 log5j 使用介绍

jopen 12年前
     <p>大家都很熟悉log4j啦,log5j在log4j的基础上提供了几个改进,应该说是简单和实用的封装。有趣的是log5j主页对自己名字的解释,因为要感谢JDK 1.5,所以才叫了这个名字,不知道是不是升级到JDK1.7以后叫log7j :)</p>    <p>主页是:<a href="/misc/goto?guid=4959517984203393532" rel="nofollow">http://code.google.com/p/log5j/</a> 大家可以看看,现在的版本是2.1.2。</p>    <p>log5j有几个封装是非常实用的,解释功能的同时我们稍微看看代码,有些很有趣的地方:</p>    <p>1,不需要指定log所在的类名了</p>    <p><br /> 原来的用法:</p>    <p>  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    private static final Logger log = Logger.getLogger( FeedTask.class );</pre>    <p>新用法:</p>    <p></p>    <pre class="brush:java; toolbar: true; auto-links: false;">    private static final Logger log = Logger.getLogger();</pre>    <p>这个可以避免复制的时候忘记改类名。</p>    <p>我们看看代码,Logger里的:</p>    <p> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    public static Logger getLogger() {         return getLogger(getCallerClassName(), true);     }       private static String getCallerClassName() {         //有趣         return new Exception().getStackTrace()[2].getClassName();     }  </pre>    <p> 取类名的时候用的是new了一个Exception,直接截取没用反射,简单直接。</p>    <p>2,支持message的format<br /> 原来:<br />  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    log.debug( "This thing broke: " + foo + " due to bar: " + bar + " on this thing: " + car );</pre>    <p>现在:<br />  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    log.debug( "This thing broke: %s due to bar: %s on this thing: %s", foo, bar, car );</pre>    <p>这个也很方便,效率也提高了,默认用了java.util.Formatter。<br /> 我们看看代码:</p>    <p>LogEvent里的:<br />  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    public String message() {         if (_params == null || _params.length == 0) {             return _formatMessage;         } else {            //有趣             return __tlMessageFormatter.get().format(_formatMessage, _params);         }     }  </pre>    <p> 其中format那部分共了工厂模式,实现的地方是:</p>    <p> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    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);           }       }    } </pre>    <p></p>    <p>3,新接口<br /> 可以这样用:</p>    <p> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    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        }  </pre>    <p>这个作者也说,仁者见仁,智者见智了。<br /> Log实现在LogImpl里,其实Logger这个类实现在AbstractLoggable,这里有个问题,重复了。<br /> 我们回到主线Logger的调用方式上来吧。</p>    <p>4,可以显式关闭Log。<br /> 这样用:<br /> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">// initialization phase    com.spinn3r.log5j.LogManager.enableExplicitShutdown();    ...     // in the very end of the shutdown routine    com.spinn3r.log5j.LogManager.shutdown();  </pre>    <p> 这个是说如果可以接受log message丢失,并且本身应用程序可以控制自身的初始化和销毁的话,可以用。<br /> 这个和log5j的异步log方式有关。</p>    <p>5,性能<br /> 简化的写法,看代码:<br />   Logger:<br />   <br />  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    public void debug(java.lang.Object message) {         super.debug(String.valueOf(message));     }  </pre>    <p></p>    <p><br />  AbstractLoggable:<br />   <br />  </p>    <pre class="brush:java; toolbar: true; auto-links: false;">    public void debug(String formatMessage, Object... params) {         if (_logger.isEnabled(LogLevel.DEBUG)) {              log(LogEvent.create(_logger, _logName, LogLevel.DEBUG,                     formatMessage, params));         }     }  </pre>    <p></p>    <p>可见,不需要用logger.isDebugEnabled()这样的代码了。</p>    <p>另外log5j是默认使用异步方式的。<br /> 主要实现在AsyncLogger里:</p>    <p> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">  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);          }      }</pre>    <p> 这个是个生产者消费者模式,WriterThread是消费者。</p>