关于tomcat日志系统的实现

本文详细介绍了Tomcat日志系统,包括Logger接口、LoggerBase抽象类以及FileLogger类的实现。FileLogger负责将日志写入文件,根据日期切换日志文件,并提供了开启、关闭日志的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于tomcat日志系统的实现:

日志对于容器来说,也是一个组件而已,其实很容易理解,对象在容器中创建、工作、销毁,所产生的信息以及错误是需要记录的,下面看看tomcat日志系统。


对于这些接口和类我们一一介绍:

Logger

public interface Logger {

    // ----------------------------------------------------- Manifest Constants

    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;

    // ------------------------------------------------------------- Properties

    public Container getContainer();

    public void setContainer(Container container);

    public String getInfo();

    public int getVerbosity();

    public void setVerbosity(int verbosity);

    // --------------------------------------------------------- Public Methods

    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);

}

接口中定义了日志级别的常量,日志级别可以通过setVerbosity(int verbosity);进行设置,并且声明了log重载方法。

 

LoggerBase

该类是一个抽象类,它实现了Logger接口中除log(String msg)之外的所有方法,该方法需要在子类中进行覆盖,所有的其他log方法都调用了该方法。因为每一个子类都将信息记录到不同的地方,所以该方法在LoggerBase中被留空。

现在来看该类的冗余级别。它被定义为一个 protected 的名为 verbosity 的变量,默认值为 ERROR。

protected int verbosity = ERROR;

冗余级别可以使用 setVerbosity 方法改变,传递这些字符串给方法即可 FATAL, ERROR, WARNING, INFORMATION, 或 DEBUG。Listing7.2 展示了LoggerBase 类中 setVobosity 方法的实现。

public void setVerbosityLevel(Stringverbosity) {

if("FATAL".equalsIgnoreCase(verbosity))

this.verbosity = FATAL;

else if("ERROR".egualsIgnoreCase(verbosity))

this.verbosity = ERROR;

else if("WARNING".equalsIgnoreCase(verbosity))

this.verbosity = WARNING;

else if("INFORMATION".equalsIgnoreCase(verbosity))

this.verbosity = INFORMATION;

else if("DEBUG".equalsIgnoreCase(verbosity))

this.verbosity = DEBUG;

}

有两个 log 方法会接受一个整型参数作为它的冗余级别。

public void log(String message, intverbosity) {

if (this.verbosity >= verbosity)

log(message);

}

public void log(String message, Throwablethrowable, int verbosity) {

if (this.verbosity >= verbosity)

log(message, throwable);

}

 

FileLogger

这个类将日志记录到文件中,它将从关联容器收到的信息写到文件中,每个信息可以选择性的加上时间戳。在第一次实例化的时候,该类的实例会创建一个文件,该文件的名字带有日期信息。如果日期改变了,它会创建一个新的文件并把信息写在里面。类的实例允许在日志文件的名字上添加前缀和后缀。在 Tomcat4 中,FileLogger 类实现了 Lifecycle 接口,所以它可以跟其它实现org.apache.catalina.Lifecycle 接口的组件一样启动和停止。在Tomcat5 中,

它是实现了 Lifecycle 接口的 LoggerBase 类的子类。Tomcat 4 中 LoggerBase 类的 start 和 stop 方法实现仅仅触发了监听器“感兴趣的”文件日志的开始和停止事件。注意 stop方法调用了该类的关闭日志文件的私有方法(close 方法)。

public void start() throwsLifecycleException {

// Validate and update our currentcomponent state

if (started)

throw new LifecycleException

(sm.getString("fileLogger.alreadyStarted"));

lifecycle.fireLifecycleEvent(START_EVENT,null);

started = true;

}

public void stop() throwsLifecycleException {

// Validate and update our currentcomponent state

if (!started)

throw new LifecycleException

(sm.getString("fileLogger.notStarted"));

lifecycle.fireLifecycleEvent(STOP__EVENT,null);

started = false;

close ();

}

FileLogger 类中最重要的方法是 log 方法,

public void log(String msg) {

// Construct the timestamp we will use, ifreguested

Timestamp ts = newTimestamp(System.currentTimeMillis());

String tsString = ts.toString().substring(0,19);

String tsDate = tsString.substring(0, 10);

// If the date has changed, switch logfiles

if (!date.equals(tsDate)) {

synchronized (this) {

if (!date.equals(tsDate)) {

close ();

date = tsDate;

open ();

}

}

}

// Log this message, timestamped ifnecessary

if (writer != null) {

if (timestamp) {

writer.println(tsString + " " +msg);

}else {

writer.println(msg);

}

}

}

log 方法接受一个消息并把消息写到日志文件中。在FileLogger 实例的生命周

期中,log 方法可以打开或关闭多个日志文件。如果日期改变了的话,log 方法

关闭当前文件并打开一个新文件。接下来看看 open、 close 和 log 这些方法是如

何工作的。

open 方法

open 方法在指定目录中创建一个新日志文件。

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(newFileWriter(pathname, true), true);

}

catch (IOException e) {

writer = null;

}

}

open 方法首先应该创建日志的目录是否存在,如果目录不存在,则首先创建目

录。目录存放在该类的变量中。

File dir = new File(directory);

if (!dir.isAbsolute())

dir = newFile(System.getProperty("catalina.base"), directory);

dir.mkdirs();

然后组成该文件的路径名,由目录路径、前缀、日期和后缀组成。

try (

String pathname = dir.getAbsolutePath() +File.separator +

prefix + date + suffix;

接下来构造 java.io.PrintWriter 类的一个实例,然后将该 PringWriter 实例给

改了的变量 writer。log 方法使用 writer 来记录信息。

writer = new PrintWriter(newFileWriter(pathname, true), true);

The close method

Close 方法清空 PrintWriter 变量 writer,然后关闭PrintWriter 并将 writer

设置为 null,并将 date 设置为空字符串。

private void close() {

if (writer == null)

return;

writer.flush();

writer.close();

writer = null;

date = "";

}

log 方法

Log 方法首先创建一个java.sql.Timestamp 类的实例,该类是 java.util.Date

的瘦包装器 (thin wrapper)。初始化时间戳的目的是更容易的得到当前时间。

在该方法中,将当前时间的 long 格式传递给 Timestamp 类并构建 Timestamp 类

实例。

Timestamp ts = newTimestamp(System.currentTimeMillis());

使用 Timestamp 类的 toString 方法,可以得到当前时间的字符串表示形式,字

符串输出的形式如下格式:

yyyy-mm-dd hh:mm: SS.fffffffff

其中 fffffffff 表示从 00:00:00 开始的毫微秒。在方法中使用 subString 方法

得到日期和小时。

String tsString =ts.toString().substring(0, 19);

接下来使用如下语句得到日期:

String tsDate = tsString.substring(0, 10);

接下来 log 方法比较 tsData 和 String 变量 date 的值,如果 tsDate 和 date 的

值不同,它关闭当前日志文件,将 tsDate 的值赋给 date 并打开一个新日志文件。  

// If the date has changed, switch logfiles

if (!date.equals(tsDate)) {

synchronized (this) {

if (!date.equals(tsDate)) {

close();

date = tsDate;

open();

}

}

}

最后,日志方法将 PrintWriter 实例的输出流写入到日志文件中。如果布尔变量

timestamp 的值为真,将timestamp(tsString)的值作为前缀,否则不使用前缀。

// Log this message, timestamped ifnecessary

if (writer != null) {

if (timestamp) {

writer.println(tsString + " " +msg);

}

else {

writer.println(msg);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值