commons.logging1.1.1源代码研究(3)-- 日志器Log接口,SimpleLog实现
2009-09-02 11:40
519 查看
Log接口的定义如下:
package org.apache.commons.logging; public interface Log { // ----------------------------------------------------- Logging Properties /** * <p> Is debug logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than debug. </p> * * @return true if debug is enabled in the underlying logger. */ public boolean isDebugEnabled(); /** * <p> Is error logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than error. </p> * * @return true if error is enabled in the underlying logger. */ public boolean isErrorEnabled(); /** * <p> Is fatal logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than fatal. </p> * * @return true if fatal is enabled in the underlying logger. */ public boolean isFatalEnabled(); /** * <p> Is info logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than info. </p> * * @return true if info is enabled in the underlying logger. */ public boolean isInfoEnabled(); /** * <p> Is trace logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than trace. </p> * * @return true if trace is enabled in the underlying logger. */ public boolean isTraceEnabled(); /** * <p> Is warn logging currently enabled? </p> * * <p> Call this method to prevent having to perform expensive operations * (for example, <code>String</code> concatenation) * when the log level is more than warn. </p> * * @return true if warn is enabled in the underlying logger. */ public boolean isWarnEnabled(); // -------------------------------------------------------- Logging Methods /** * <p> Log a message with trace log level. </p> * * @param message log this message */ public void trace(Object message); /** * <p> Log an error with trace log level. </p> * * @param message log this message * @param t log this cause */ public void trace(Object message, Throwable t); /** * <p> Log a message with debug log level. </p> * * @param message log this message */ public void debug(Object message); /** * <p> Log an error with debug log level. </p> * * @param message log this message * @param t log this cause */ public void debug(Object message, Throwable t); /** * <p> Log a message with info log level. </p> * * @param message log this message */ public void info(Object message); /** * <p> Log an error with info log level. </p> * * @param message log this message * @param t log this cause */ public void info(Object message, Throwable t); /** * <p> Log a message with warn log level. </p> * * @param message log this message */ public void warn(Object message); /** * <p> Log an error with warn log level. </p> * * @param message log this message * @param t log this cause */ public void warn(Object message, Throwable t); /** * <p> Log a message with error log level. </p> * * @param message log this message */ public void error(Object message); /** * <p> Log an error with error log level. </p> * * @param message log this message * @param t log this cause */ public void error(Object message, Throwable t); /** * <p> Log a message with fatal log level. </p> * * @param message log this message */ public void fatal(Object message); /** * <p> Log an error with fatal log level. </p> * * @param message log this message * @param t log this cause */ public void fatal(Object message, Throwable t); }
其中主要的方法有:
is<Level>Enabled() -- 是否某个层次的日志开启
<Level>(Object message) -- 记录日志消息
<Level>(Object message, Throwable t) -- 记录日志消息和异常
其中<Level>指trace,debug,info,wran,error,fatal
SimpleLog实现:
simplelog.properties必须放在根路径下,是配置文件配置前缀:“org.apache.commons.logging.simplelog.”
showlogname -- 是否显示日志名(true/false )
showShortLogname -- 是否显示短日志名(true /false)
showdatetime -- 是否显示时间(true/false )
dateTimeFormat -- 日期格式(默认为yyyy/MM/dd HH:mm:ss:SSS zzz)
defaultlog -- 指定默认日志的层次(info,debug等)
log.<类的完全路径名> -- 指定某一类的日志的层次
比如:org.apache.commons.logging.simplelog.log.Test.TestClass=debug
org.apache.commons.logging.simplelog.log.Test.TestA=info
那么Test.TestClass类的日志层次为debug;而Test.TestA的日志层次为info
SimpleLog一些重要代码分析:
(1)构造函数public SimpleLog(String name) { logName = name; // Set initial log level // Used to be: set default log level to ERROR // IMHO it should be lower, but at least info ( costin ). setLevel(SimpleLog.LOG_LEVEL_INFO); // Set log level from properties String lvl = getStringProperty(systemPrefix + "log." + logName); int i = String.valueOf(name).lastIndexOf("."); while(null == lvl && i > -1) { name = name.substring(0,i); lvl = getStringProperty(systemPrefix + "log." + name); i = String.valueOf(name).lastIndexOf("."); } if(null == lvl) { lvl = getStringProperty(systemPrefix + "defaultlog"); } if("all".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_ALL); } else if("trace".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_TRACE); } else if("debug".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_DEBUG); } else if("info".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_INFO); } else if("warn".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_WARN); } else if("error".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_ERROR); } else if("fatal".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_FATAL); } else if("off".equalsIgnoreCase(lvl)) { setLevel(SimpleLog.LOG_LEVEL_OFF); } }
其中while循环处实现了日志器层次的继承性,即:
(1)如果没有设置,则黙认为info
(2)如果对某一类明确了日志层次,如:org.apache.commons.logging.simplelog.log.Test.TestA(Test.TestA类),则使用这个明确的日志层次;如果没明确,则向上寻找org.apache.commons.logging.simplelog.log.Test;如果还没找到,则找org.apache.commons.logging.simplelog.defaultlog
(2)日志函数
protected void log(int type, Object message, Throwable t) { // Use a string buffer for better performance StringBuffer buf = new StringBuffer(); // Append date-time if so configured if(showDateTime) { Date now = new Date(); String dateText; synchronized(dateFormatter) { dateText = dateFormatter.format(now); } buf.append(dateText); buf.append(" "); } // Append a readable representation of the log level switch(type) { case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break; case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break; case SimpleLog.LOG_LEVEL_INFO: buf.append("[INFO] "); break; case SimpleLog.LOG_LEVEL_WARN: buf.append("[WARN] "); break; case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break; case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break; } // Append the name of the log instance if so configured if( showShortName) { if( shortLogName==null ) { // Cut all but the last component of the name for both styles shortLogName = logName.substring(logName.lastIndexOf(".") + 1); shortLogName = shortLogName.substring(shortLogName.lastIndexOf("/") + 1); } buf.append(String.valueOf(shortLogName)).append(" - "); } else if(showLogName) { buf.append(String.valueOf(logName)).append(" - "); } // Append the message buf.append(String.valueOf(message)); // Append stack trace if not null if(t != null) { buf.append(" <"); buf.append(t.toString()); buf.append(">"); java.io.StringWriter sw= new java.io.StringWriter(1024); java.io.PrintWriter pw= new java.io.PrintWriter(sw); t.printStackTrace(pw); pw.close(); buf.append(sw.toString()); } // Print to the appropriate destination write(buf); }
这段代码很简单,要注意的是:
showlogname 显示的是完全的类名(包括包名);showShortLogname只显示类名
注意:SimpleDateFormat不是线程安全的,在多线程中必须同步
Date formats are not synchronized.
* It is recommended to create separate format instances for each thread.
* If multiple threads access a format concurrently, it must be synchronized
(3)具体的日志方法
public final void fatal(Object message, Throwable t) { if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) { log(SimpleLog.LOG_LEVEL_FATAL, message, t); } }
先判断是否这个层次的日志开启,然后调用写日志方法
(4)得到资源的方法
private static InputStream getResourceAsStream(final String name) { return (InputStream)AccessController.doPrivileged( new PrivilegedAction() { public Object run() { ClassLoader threadCL = getContextClassLoader(); if (threadCL != null) { return threadCL.getResourceAsStream(name); } else { return ClassLoader.getSystemResourceAsStream(name); } } }); }
AccessController的doPrivileged方法给了其中的代码“特权”,从而不用checkPermissions.
以下得到ClassLoader
private static ClassLoader getContextClassLoader() { ClassLoader classLoader = null; if (classLoader == null) { try { // Are we running on a JDK 1.2 or later system? Method method = Thread.class.getMethod("getContextClassLoader", (Class[]) null); // Get the thread context class loader (if there is one) try { classLoader = (ClassLoader)method.invoke(Thread.currentThread(), (Class[]) null); } catch (IllegalAccessException e) { ; // ignore } catch (InvocationTargetException e) { /** * InvocationTargetException is thrown by 'invoke' when * the method being invoked (getContextClassLoader) throws * an exception. * * getContextClassLoader() throws SecurityException when * the context class loader isn't an ancestor of the * calling class's class loader, or if security * permissions are restricted. * * In the first case (not related), we want to ignore and * keep going. We cannot help but also ignore the second * with the logic below, but other calls elsewhere (to * obtain a class loader) will trigger this exception where * we can make a distinction. */ if (e.getTargetException() instanceof SecurityException) { ; // ignore } else { // Capture 'e.getTargetException()' exception for details // alternate: log 'e.getTargetException()', and pass back 'e'. throw new LogConfigurationException ("Unexpected InvocationTargetException", e.getTargetException()); } } } catch (NoSuchMethodException e) { // Assume we are running on JDK 1.1 ; // ignore } } if (classLoader == null) { classLoader = SimpleLog.class.getClassLoader(); } // Return the selected class loader return classLoader; }
以下是Thread类的getContextClassLoader()方法,可能会报SecurityException
public ClassLoader getContextClassLoader() { if (contextClassLoader == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = ClassLoader.getCallerClassLoader(); if (ccl != null && ccl != contextClassLoader && !contextClassLoader.isAncestor(ccl)) { sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); } } return contextClassLoader;
相关文章推荐
- commons.logging1.1.1源代码研究(4)-- JDK14Logger实现
- commons.logging1.1.1源代码研究(2)-- 基本使用及配置文件
- commons.logging1.1.1源代码研究(1)-- 组织结构
- Jakarta Commons Logging(JCL)之应用篇­­——与Log4j/JDK5 log实现日志输出
- Apache commons logging自动查找当前实现Log顺序
- commons-logging和slf4j都是日志的接口
- 在Spring中配置使用commons-logging的simplelog来输出日志
- 在Spring中配置使用commons-logging的simplelog来输出日志
- Apache Commons Logging 是如何决定使用哪个日志实现类的
- commons-logging日志实现解耦
- 代码实现获取log日志和logcat使用方法
- python实现log日志的示例代码
- java 日志接口 commons-logging
- JNI开发第二篇通过反射实现C中调用java代码,并实现Log打印日志
- Java核心代码(十)日志log4j,java.util.logging,commons-logging
- 使用commons.logging中的SimpleLog显示调试和日志信息
- 最右校招-服务器日志分析:一个十万行log统计问题的c语言代码的实现2
- 代码实现获取log日志
- commons-logging实现日志解耦
- 代码实现获取log日志和logcat使用方法