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

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

今天跟大家说一下Tomcat Logging的内部实现,可能很多人不太懂。为了让大家更好的了解,边肖为大家总结了以下内容,希望大家能从这篇文章中有所收获。

Tomcat的日志实现是通过JDK的日志输出内容,并重写其日志处理程序。

下面将分析Log in Tomcat的实现,并深入源代码了解如何根据配置创建它。

处理程序和其他进程。

初始化

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

privatedstatifiloglog=logfactory . getlog(bootstrap . class)

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

从LogFactory的工厂方法开始。

公共日志getInstance(字符串名称){ 0

if(discovered log constructor==null){ 0

返回DirectJDKLog.getInstance(名称);

}

返回discovered logconstructor . new instance(名称);

默认情况下,Tomcat使用DirectJDKLog,因此所有后续进程都将移交给

DirectJDKLog来处理。类内是一个直接对JDK的日志调用。

公共DirectJDKLog(字符串名称){ 0

logger=Logger.getLogger(名称);

}

事实上,整个日志管理器仍将由日志管理器管理。在上一篇文章中,我们还看到Tomcat还指定了一个自定义日志管理器。

这个班是ClassLoaderLogManager.

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

URLlogConfig=((URlCLaSS loader)CLaSS loader)。find ReSource(' logging . properties ');

也就是说,在当前的类加载器中找到名为logging.properties的资源。如果当前的类加载器没有JDK自带的logging.properties,在找到文件后,它会直接加载属性文件,然后分析文件中的属性。

正如下面的代码,我们可以看到处理程序被解析,带有前缀的定制处理程序也被解析。

//为此类加载器的根记录器创建处理程序

string RootHandlers=info . props . GetProperty('。处理程序');

字符串处理程序=info.props.getProperty('处理程序');

logger localhotlogger=info . rootnode . logger;

if (handlers!=null){ 0

StringTokenizer Tok=new StringTokenizer(处理程序,',');

while(Tok . hasmoretokens()){ 0

string handlerName=(Tok . next token()。trim());

string handlerClassName=handlerName;

字符串前缀='

quot;;
       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内部实现方式是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/138487.html

(0)

相关推荐

  • css3中设置文本阴影的属性是(css3球体掉落动画带阴影效果)

    技术css3怎么实现图片阴影效果这篇文章主要讲解了“css3怎么实现图片阴影效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“css3怎么实现图片阴影效果”吧!css3实

    攻略 2021年12月16日
  • 分析和数据科学怎么提高业务效率

    技术分析和数据科学怎么提高业务效率这篇文章主要介绍“分析和数据科学怎么提高业务效率”,在日常操作中,相信很多人在分析和数据科学怎么提高业务效率问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”

    攻略 2021年10月22日
  • 如何进行JavaScript中getter/setter的实现

    技术如何进行JavaScript中getter/setter的实现如何进行JavaScript中getter/setter的实现,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望

    攻略 2021年10月29日
  • 瑜珈教程,怎样能快速掌握瑜伽的动作

    技术瑜珈教程,怎样能快速掌握瑜伽的动作要想快速的掌握瑜伽动作要从两方面入手瑜珈教程。1、了解人体。了解基础的人体结构知识,了解基础的人体运动知识。瑜伽每一个动作都是由人去完成的。所以对人体肌肉、骨骼、关节运动都要有所了解

    生活 2021年10月24日
  • 阴茎增粗,阴茎增粗增长有什么办法

    技术阴茎增粗,阴茎增粗增长有什么办法男性增大增粗的方法阴茎增粗: 许多人知道,经常参加体育锻炼有助于改善男性性能力。但是,却很少有人知道,直接锻炼阴茎提高性能力的效果可能回更好、更直接。它能强健阴茎,让勃起神经与组织变得

    生活 2021年10月26日
  • Alibaba Sentinel LeapArray源码分析

    技术Alibaba Sentinel LeapArray源码分析这篇文章主要介绍“Alibaba Sentinel LeapArray源码分析”,在日常操作中,相信很多人在Alibaba Sentinel LeapArr

    攻略 2021年11月17日