本文接下来分析tomcat的日志记录器,日志记录器是用来记录消息的组件,在tomcat中,日志记录器需要与某个servlet容器相关连;在org.apache.catalina.logger包下,tomcat提供了几种不同类型的日志记录器。

tomcat中的日志记录器都必须实现org.apache.catalina.Logger接口



public interface Logger {    

public static final int FATAL = Integer.MIN_VALUE;

public static final int ERROR = 1;

public static final int WARNING = 2;

public static final int INFORMATION = 3;

public static final int DEBUG = 4;

public Container getContainer();

public void setContainer(Container container);

public String getInfo();

public int getVerbosity();

public void setVerbosity(int verbosity);

public void addPropertyChangeListener(PropertyChangeListener listener);

public void log(String message);

public void log(Exception exception, String msg);

public void log(String message, Throwable throwable);

public void log(String message, int verbosity);

public void log(String message, Throwable throwable, int verbosity);

public void removePropertyChangeListener(PropertyChangeListener listener);
}


通常,当传入的日志级别verbosity大于Logger被设置的级别时,message会被记录,否则被忽略

Logger接口共定义了五种日志级别,分别为FATAL ERROR WARNING INFORMATION DEBUG

Tomcat提供了三种类型的日志记录器,分别为SystemOutLogger、SystemErrLogger、FileLogger,在org.apache.catalina.logger包下,均继承自org.apache.catalina.logger.LoggerBase类

LoggerBase类实现了org.apache.catalina.Logger接口,在tomcat5中还实现了Lifecycle接口

LoggerBase类为抽象类,实现了Logger接口中除abstract void log(String msg)外的全部方法实现,所有的其他重载方法最终都会调用该方法(templet模式),我们还可以调用setVerbosity()方法设置日志级别

具体日志类都比较简单,下面是SystemOutLogger类的实现



public class SystemOutLogger
extends LoggerBase {

protected static final String info =
"org.apache.catalina.logger.SystemOutLogger/1.0";

public void log(String msg) {

System.out.println(msg);

}
}


SystemErrLogger类



public class SystemErrLogger
extends LoggerBase {

protected static final String info =
"org.apache.catalina.logger.SystemErrLogger/1.0";

public void log(String msg) {

System.err.println(msg);
}
}


FileLogger类稍微复杂一点,将从servlet容器中接收到的消息写入到一个文件中(在tomcat4中,FileLogger类实现了Lifecycle接口)



public class FileLogger
extends LoggerBase
implements Lifecycle {
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
private StringManager sm =
StringManager.getManager(Constants.Package);

private boolean started = false;

private String suffix = ".log";

private boolean timestamp = false;

private PrintWriter writer = null;
public void log(String msg) {

// Construct the timestamp we will use, if requested
Timestamp ts = new Timestamp(System.currentTimeMillis());
String tsString = ts.toString().substring(0, 19);
String tsDate = tsString.substring(0, 10);

// If the date has changed, switch log files
if (!date.equals(tsDate)) {
synchronized (this) {
if (!date.equals(tsDate)) {
close();
date = tsDate;
open();
}
}
}

// Log this message, timestamped if necessary
if (writer != null) {
if (timestamp) {
writer.println(tsString + " " + msg);
} else {
writer.println(msg);
}
}

}

private void close() {

if (writer == null)
return;
writer.flush();
writer.close();
writer = null;
date = "";
}

/**
* Open the new log file for the date specified by <code>date</code>.
*/
private void open() {

// Create the directory if necessary
File dir = new File(directory);
if (!dir.isAbsolute())
dir = new File(System.getProperty("catalina.base"), directory);
dir.mkdirs();

// Open the current log file
try {
String pathname = dir.getAbsolutePath() + File.separator +
prefix + date + suffix;
writer = new PrintWriter(new FileWriter(pathname, true), true);
} catch (IOException e) {
writer = null;
}

}

public void addLifecycleListener(LifecycleListener listener) {

lifecycle.addLifecycleListener(listener);
}
public LifecycleListener[] findLifecycleListeners() {

return lifecycle.findLifecycleListeners();
}

public void removeLifecycleListener(LifecycleListener listener) {

lifecycle.removeLifecycleListener(listener);
}

public void start() throws LifecycleException {

// Validate and update our current component state
if (started)
throw new LifecycleException
(sm.getString("fileLogger.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
}

public void stop() throws LifecycleException {

// Validate and update our current component state
if (!started)
throw new LifecycleException
(sm.getString("fileLogger.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
close();
}

}