千家信息网

Tomcat的Logging内部实现方式是什么

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,今天就跟大家聊聊有关Tomcat的Logging内部实现方式是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Tomcat的Logging实
千家信息网最后更新 2026年10月31日Tomcat的Logging内部实现方式是什么

今天就跟大家聊聊有关Tomcat的Logging内部实现方式是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

Tomcat的Logging实现,是通过JDK的Log,并重写了其Log的Handler来输出内容的。

下面将分析在Tomcat内部Log的实现,并深入源码,了解其根据配置,创建

Handler等一系列过程。

初始化

Tomcat的Main-Class是BootStrap这个类,而Log的初始化也是从这个类的初始化开始的,由于BootStrap类中有如下声明:

private static final Log log = LogFactory.getLog(Bootstrap.class)

所以在类实例化时,这一字段也被初始化。

从LogFactory的工厂方法开始

public Log getInstance(String name) {
if (discoveredLogConstructor == null) {
return DirectJDKLog.getInstance(name);
}
return discoveredLogConstructor.newInstance(name);

默认情况,Tomcat使用的是DirectJDKLog,因此,后续的过程都交给了

DirectJDKLog来处理。该类内部则是直接对JDK的logging调用

public DirectJDKLog(String name ) {
logger=Logger.getLogger(name);
}

而整个Logger其实还是会交给一个LogManager来管理,上一篇文章中我们也看到Tomcat也指定了自定义的LogManager,

这个类是ClassLoaderLogManager。

在Logger获取LogManager的过程中,就会涉及到读取logging.properties的过程,此时由于ClassLoaderLogManager继承了LogManager,这个readConfiguration方法由子类实现了,此时Tomcat的自定义读取方式如下:

URL logConfig = ((URLClassLoader)classLoader).findResource("logging.properties");

即在当前的classLoader中查找名为logging.properties的资源。如果当前classLoader中不存在会使用JDK自带的logging.properties,找到文件之后,会直接把这个properties文件load进来,之后对文件中的properties解析。

如同下面的代码,我们看到解析handlers,同时会解析自定义的带有prefix的handler。

// Create handlers for the root logger of this classloader
String rootHandlers = info.props.getProperty(".handlers");
String handlers = info.props.getProperty("handlers");
Logger localRootLogger = info.rootNode.logger;
if (handlers != null) {
StringTokenizer tok = new StringTokenizer(handlers, ",");
while (tok.hasMoreTokens()) {
String handlerName = (tok.nextToken().trim());
String handlerClassName = handlerName;
String prefix = "";
if (handlerClassName.length() <= 0) {
continue;
}
if (Character.isDigit(handlerClassName.charAt(0))) {
int pos = handlerClassName.indexOf('.');
if (pos >= 0) {
prefix = handlerClassName.substring(0, pos + 1);
handlerClassName = handlerClassName.substring(pos + 1);}}
try {
this.prefix.set(prefix);
Handler handler =
(Handler) classLoader.loadClass(handlerClassName).newInstance(); //解析prefix和handlerClass后设置,在newInstance后,其实执行了许多操作,包含设置和初始化具体的Handler,打开输出流等。上篇文章提到的设置Log文件的操作就在这一步。
this.prefix.set(null);
info.handlers.put(handlerName, handler);
if (rootHandlers == null) {
localRootLogger.addHandler(handler);} //解析完毕后,将handler和logger绑定。
} catch (Exception e) {}

而在loadClass(handlerClassName).newInstance中,还有比较关键的一个地方,在初始化AsynFileHandler时,类内初始化的代码包含这样两行

protected static final LoggerThread logger = new LoggerThread();
static {
logger.start();
}

这个Logger线程,则会在后面不停止的处理log,其run方法是这个样子:

while (run) {
try {
LogEntry entry = queue.poll(LOGGER_SLEEP_TIME, TimeUnit.MILLISECONDS);//log出队列
if (entry!=null) entry.flush();
} catch (InterruptedException x) {
// Ignore the attempt to interrupt the thread.
} catch (Exception x) {
x.printStackTrace();
}
}


记一个Log

而我们一般在记录log时,会直接使用log.info(xxx)这种形式,Tomcat内部也是这样的。

例如要用log记一个log.warn,这个时候,调用执行的代码是这样一个过程:

首先会调用到上面提到的DirectJDKLog中,其对应的方法会设置Log的Level等,方法是这个样子:

public final void warn(Object message) {
log(Level.WARNING, String.valueOf(message), null);
}

这行代码,会调用到Logger中的如下代码,会根据配置的Handler来进行log输出

for (Handler handler : loggerHandlers) {
handler.publish(record);
}

我们定义的Handler中包含FileHandler和ConsoleHandler,这个时候,FileHandler的publish方法执行的操作是将Log添加到一个阻塞队列中,即上面的LogThread在wait的队列,

public void publish(LogRecord record) {
LogEntry entry = new LogEntry(record,this);
boolean added = false;
try {
while (!added && !queue.offer(entry)) {...}

logThread在queue不为空时,会输出LogEntry。

我们看,这个输出Log的具体操作方式如下,会使用到上一篇文章提到的Formatter,

public void publish(LogRecord record) {
Timestamp ts = new Timestamp(System.currentTimeMillis());
String tsString = ts.toString().substring(0, 19);
String tsDate = tsString.substring(0, 10);

try {
// If the date has changed, switch log files
if (rotatable && !date.equals(tsDate)) {
try {
// Make sure another thread hasn't already done this
if (!date.equals(tsDate)) {
closeWriter();
date = tsDate;
openWriter();
}}}

String result = null;
result = getFormatter().format(record); //格式化,注意
if (writer!=null) {
writer.write(result); //这里使用初始化时创建的Writer
if (bufferSize < 0) {
writer.flush();
}

看完上述内容,你们对Tomcat的Logging内部实现方式是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

方法 代码 过程 输出 方式 内容 文件 篇文章 队列 时候 样子 面的 上一 处理 配置 上篇 关键 同时 地方 子类 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 什么是科技互联网 上海睿民互联网科技有限公司 蓝思科技飞鸽互联网 重生之互联网科技帝国 科技金融是不是互联网金融 互联网科技会 河南真二互联网科技有限公司 互联网科技小贷 腾讯科技 互联网女皇 左右互联网络科技 北京大学互联网科技怎么样 世界互联网科技公司市值排名 千方科技属于互联网企业吗 企晟互联网信息科技有限公司 上海创道互联网络科技有限公司 下一代互联网重大应用科技园 上海万顺科技互联网有限公司招聘 第三届互联网大会安防黑科技 青岛易易互联网科技 广东猫王互联网科技有限公司电话 广州大一互联网络科技有限公司 江苏根荣互联网科技 互联网科技集团 互联网科技公司怎么样 安徽鑫晟辉互联网科技 山东吉时兔互联网科技有限公司 互联网与医疗科技 杭州壁岐互联网科技有限公司 长沙互联网科技 黑龙江互联网科技公司
0