您的位置:首页 > 编程语言

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;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: