iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么自定制LogManager实现程序完全自定义的logger
  • 452
分享到

怎么自定制LogManager实现程序完全自定义的logger

2023-06-29 16:06:31 452人浏览 泡泡鱼
摘要

本篇内容主要讲解“怎么自定制LogManager实现程序完全自定义的logger”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么自定制LogManager实现程序完全自定义的logger”吧!

本篇内容主要讲解“怎么自定制LogManager实现程序完全自定义的logger”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么自定制LogManager实现程序完全自定义的logger”吧!

引言

Tomcat熟悉的读者,有可能会注意到tomcat的启动脚本catalina.bat中也使用定制的LogManager,如下:

if not exist "%CATALINA_HOME%\bin\tomcat-juli.jar" Goto noJuliset JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"

当tomcat的bin路径下存在tomcat-juli.jar文件(也就是存在定制的LogManager)时,那么会强制在JVM系统属性中指定org.apache.juli.ClassLoaderLogManager作为整个JVM的LogManager,以此来完成一些特殊操作。

WEBsphere的启动脚本startServer.bat中也定义了自己的LogManager,如下:

java.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager

怎么实现自定义的LogManager

首先要实现一个继承自java.util.logging.LogManager的类:

子类覆盖java.util.logging.LogManager的addLogger方法,在成功添加logger之后对logger做定制化操作,从代码中可以看出addLogger方法调用了子类的internalInitializeLogger方法,internalInitializeLogger方法中先清空logger的所有handler,然后再增加一个自定义的Handler

需要说明一下:internalInitializeLogger方法中的操作(给logger增设我们自定义的handler)是我们自定义LogManager的一大目的。

package com.bes.logging;import java.util.logging.Handler;import java.util.logging.Level;import java.util.logging.LogManager;import java.util.logging.Logger;public class ServerLogManager extends LogManager {private static ServerFileHandler handlerSingleton;private static ServerLogManager thisInstance;private Object lockObj = new Object();public ServerLogManager() {super();}public static synchronized ServerLogManager getInstance() {if (thisInstance == null) {thisInstance = new ServerLogManager();}return thisInstance;}public boolean addLogger(Logger logger) {boolean result = super.addLogger(logger); //initialize Loggerif (logger.getResourceBundleName() == null) {try {Logger newLogger = Logger.getLogger(logger.getName(),getLoggerResourceBundleName(logger.getName()));assert (logger == newLogger);} catch (Throwable ex) {//ex.printStackTrace();}}synchronized (lockObj) {internalInitializeLogger(logger);}return result;}private void internalInitializeLogger(final Logger logger) {// Explicitly remove all handlers.Handler[] h = logger.getHandlers();for (int i = 0; i < h.length; i++) {logger.removeHandler(h[i]);}logger.addHandler(getServerFileHandler());logger.setUseParentHandlers(false);logger.setLevel(Level.FINEST);// only for test}private static synchronized Handler getServerFileHandler() {if (handlerSingleton == null) {try {handlerSingleton = ServerFileHandler.getInstance();handlerSingleton.setLevel(Level.ALL);} catch (Exception e) {e.printStackTrace();}}return handlerSingleton;}public String getLoggerResourceBundleName(String loggerName) {String result = loggerName + "." + "LogStrings";return result;}}

自定义的LogManager中使用到的ServerFileHandler

如下:

该ServerFileHandler是一个把logger日志输出到文件中的handler,可以通过com.bes.instanceRoot系统属性来指定日志文件跟路径;其次,ServerFileHandler也指定了自己的UnifORMLogFormatter;最后是需要覆盖父类的publish方法,覆盖的publish方法在做真正的日志输入之前会检查日志文件是否存在,然后就是创建一个和日志文件对应的输出流,把该输出流设置为ServerFileHandler的输出流以至日志输出的时候能输出到文件中。另外,WrapperStream仅仅是一个流包装类。

这里也需要说一下:ServerFileHandler构造方法中的setFormatter(new UniformLogFormatter());操作是我们自定义LogManager的第二大目的。

package com.bes.logging;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.logging.LogRecord;import java.util.logging.StreamHandler;public class ServerFileHandler extends StreamHandler {  private WrapperStream wrappedStream;  private String absoluteFileName = null;  static final String LOG_FILENAME_PREFIX = &quot;server&quot;;  static final String LOG_FILENAME_SUFFIX = &quot;.log&quot;;  private String logFileName = LOG_FILENAME_PREFIX + LOG_FILENAME_SUFFIX;  public static final ServerFileHandler thisInstance = new ServerFileHandler();  public static synchronized ServerFileHandler getInstance() {    return thisInstance;  }  protected ServerFileHandler() {    try {      setFormatter(new UniformLogFormatter());    } catch (Exception e) {      e.printStackTrace();    }  }  public synchronized void publish(LogRecord record) {    if (wrappedStream == null) {      try {        absoluteFileName = createFileName();        openFile(absoluteFileName);      } catch (Exception e) {        throw new RuntimeException(            &quot;Serious Error Couldn't open Log File&quot; + e);      }    }    super.publish(record);    flush();  }  public String createFileName() {    String instDir = &quot;&quot;;    instDir = System.getProperty(&quot;com.bes.instanceRoot&quot;);    if(instDir == null || &quot;&quot;.equals(instDir)){      instDir = &quot;.&quot;;    }    return instDir + &quot;/&quot; + getLogFileName();  }    private void openFile(String fileName) throws IOException {    File file = new File(fileName);    if(!file.exists()){      if(file.getParentFile() != null &amp;&amp; !file.getParentFile().exists()){        file.getParentFile().mkdir();      }      file.createNewFile();    }    FileOutputStream fout = new FileOutputStream(fileName, true);    BufferedOutputStream bout = new BufferedOutputStream(fout);    wrappedStream = new WrapperStream(bout, file.length());    setOutputStream(wrappedStream);  }  private class WrapperStream extends OutputStream {    OutputStream out;    long written;    WrapperStream(OutputStream out, long written) {      this.out = out;      this.written = written;    }    public void write(int b) throws IOException {      out.write(b);      written++;    }    public void write(byte buff[]) throws IOException {      out.write(buff);      written += buff.length;    }    public void write(byte buff[], int off, int len) throws IOException {      out.write(buff, off, len);      written += len;    }    public void flush() throws IOException {      out.flush();    }    public void close() throws IOException {      out.close();    }  }  protected String getLogFileName() {    return logFileName;  }}

实现Formatter

之前已经提到过,使用logger日志输出的时候,handler会自动调用自己的formatter对日志做format,然后输出格式化之后的日志。自定义的Formatter只需要覆盖public String format(LogRecord record)便可。这个类本身很简单,就是日志输出时自动增加指定格式的时间,加上分隔符,对日志进行国际化处理等操作。 需要注意的是类中对ResourceBundle做了缓存以提高效率。

package com.bes.logging;import java.text.MessageFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.ResourceBundle;import java.util.logging.Formatter;import java.util.logging.LogManager;import java.util.logging.LogRecord;public class UniformLogFormatter extends Formatter {  private Date date = new Date();  private HashMap loggerResourceBundleTable;  private LogManager logManager;  private static final char FIELD_SEPARATOR = '|';  private static final String CRLF = System.getProperty(&quot;line.separator&quot;);  private static final SimpleDateFormat dateFormatter = new SimpleDateFormat(      &quot;yyyy-MM-dd'T'HH:mm:ss.SSSZ&quot;);  public UniformLogFormatter() {    super();    loggerResourceBundleTable = new HashMap();    logManager = LogManager.getLogManager();  }  public String format(LogRecord record) {    return uniformLogFormat(record);  }  private String uniformLogFormat(LogRecord record) {    try {      String logMessage = record.getMessage();      int msgLength = 150; // typical length of log record      if (logMessage != null)        msgLength += logMessage.length();      StringBuilder recordBuffer = new StringBuilder(msgLength);      // add date to log      date.setTime(record.getMillis());      recordBuffer.append(dateFormatter.format(date)).append(          FIELD_SEPARATOR);      // add log level and logger name to log      recordBuffer.append(record.getLevel()).append(FIELD_SEPARATOR);      recordBuffer.append(record.getLoggerName()).append(FIELD_SEPARATOR);      if (logMessage == null) {        logMessage = &quot;The log message is null.&quot;;      }      if (logMessage.indexOf(&quot;{0}&quot;) >= 0) {        try {          logMessage = java.text.MessageFormat.format(logMessage,              record.getParameters());        } catch (Exception e) {          // e.printStackTrace();        }      } else {        ResourceBundle rb = getResourceBundle(record.getLoggerName());        if (rb != null) {          try {            logMessage = MessageFormat.format(                rb.getString(logMessage),                record.getParameters());          } catch (java.util.MissingResourceException e) {          }        }      }      recordBuffer.append(logMessage);      recordBuffer.append(CRLF);      return recordBuffer.toString();    } catch (Exception ex) {      return &quot;Log error occurred on msg: &quot; + record.getMessage() + &quot;: &quot;          + ex;    }  }  private synchronized ResourceBundle getResourceBundle(String loggerName) {    if (loggerName == null) {      return null;    }    ResourceBundle rb = (ResourceBundle) loggerResourceBundleTable        .get(loggerName);    if (rb == null) {      rb = logManager.getLogger(loggerName).getResourceBundle();      loggerResourceBundleTable.put(loggerName, rb);    }    return rb;  }}

 完成了定制的LogManager之后,在启动JVM的命令中增加系统属性便可

java -Djava.util.logging.manager=com.bes.logging.ServerLogManager

加上这个系统属性之后通过java.util.logging.Logger类获取的logger都是经过定制的LogManager作为初始化的,日志输出的时候便会使用上面的ServerFileHandler#publish()方法进行日志输出,并使用UniformLogFormatter对日志进行格式化。

到此,相信大家对“怎么自定制LogManager实现程序完全自定义的logger”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 怎么自定制LogManager实现程序完全自定义的logger

本文链接: https://www.lsjlt.com/news/325586.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么自定制LogManager实现程序完全自定义的logger
    本篇内容主要讲解“怎么自定制LogManager实现程序完全自定义的logger”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么自定制LogManager实现程序完全自定义的logger”吧!...
    99+
    2023-06-29
  • 通过自定制LogManager实现程序完全自定义的logger
    目录引言怎么实现自定义的LogManager自定义的LogManager中使用到的ServerFileHandler实现Formatter前一篇博文介绍了JDK logging基础知...
    99+
    2024-04-02
  • 怎么完全掌握Vue自定义指令
    这篇文章主要介绍“怎么完全掌握Vue自定义指令”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么完全掌握Vue自定义指令”文章能帮助大家解决问题。准备:自定义指令介绍除了核心功能默认内置的指令 (v...
    99+
    2023-07-05
  • DataGridView中怎么实现自定义排序
    要在DataGridView中实现自定义排序,可以通过实现DataGridView的SortCompare事件来实现。SortCom...
    99+
    2024-03-12
    DataGridView
  • 小程序自定义tabbar如何实现
    小编给大家分享一下小程序自定义tabbar如何实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!tabBar如果小程序是一个多 tab 应用(客户端窗口的底部或顶...
    99+
    2023-06-26
  • Python3怎么实现自定义比较排序
    本篇内容介绍了“Python3怎么实现自定义比较排序”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!自定义比较排序/运算符Python3和Py...
    99+
    2023-06-29
  • mybatis-plus自定义排序的实现
    目录需求:1.导入依赖2.配置文件3.创建分页需要的缓存4.创建实体类5.mapper6.测试7.结果需求: 先时间升序排序,相同的时间在按状态排序,状态的顺序为1 在线 4 潜伏 ...
    99+
    2023-01-09
    mybatis-plus 自定义排序 mybatis-plus 排序
  • AndroidCompose自定义TextField实现自定义的输入框
    目录概览简单自定义BasicTextField示例实现自定义样式的BasicTextField使用BasicTextField自定义百度输入框概览 众所周知Compose中默认的Te...
    99+
    2024-04-02
  • 小程序怎么自定义弹框
    本篇内容主要讲解“小程序怎么自定义弹框”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“小程序怎么自定义弹框”吧!页面简单布局<button bindtap='Elastic...
    99+
    2023-07-02
  • 如何实现小程序的自定义组件
    要实现小程序的自定义组件, 需要以下步骤: 创建一个自定义组件的文件夹,例如 components/myComponent。 ...
    99+
    2024-04-17
    小程序
  • 微信小程序怎么实现自定义导航栏
    今天小编给大家分享一下微信小程序怎么实现自定义导航栏的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、要实现自定义导航栏,首...
    99+
    2023-06-29
  • node.js怎么自定义实现EventEmitter
    这篇文章主要介绍了node.js怎么自定义实现EventEmitter的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node.js怎么自定义实现EventEmitter文章都会有所收获,下面我们一起来看看吧。一...
    99+
    2023-06-17
  • Flutter怎么实现自定义themes
    这篇“Flutter怎么实现自定义themes”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Flutter怎么实现自定义th...
    99+
    2023-07-05
  • springboot自定义配置及自定义对象映射的全流程
    目录一、使用@Value注解获取(一个一个获取)1.1 使用方法1.2 举例说明二、自定义对象映射2.1 使用方法2.2 举例说明一、使用@Value注解获取(一个一个获取)1.1 ...
    99+
    2024-04-02
  • JavaScript自定义Promise实现流程
    目录1. 初始结构2. 定义状态3. this指向4. then 方法5. 执行异常6. 支持异步(重头戏1)7. 回调保存(重头戏2)8. 重难点解读9. 链式功能(重头戏3)1....
    99+
    2022-11-13
    JavaScript Promise JavaScript Promise原理 JS Promise
  • 微信小程序如何实现自定义Toast
    这篇文章主要介绍微信小程序如何实现自定义Toast,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!微信小程序 自定义Toast实例代码Toast样式可以根据需求自定义,本例中是圆形&l...
    99+
    2024-04-02
  • 微信小程序实现自定义导航栏
    本文实例为大家分享了微信小程序自定义导航栏的具体代码,供大家参考,具体内容如下 1、要实现自定义导航栏,首先得在全局进行相关配置 app.json页面 "window": {    ...
    99+
    2024-04-02
  • vue怎么实现自定义全局右键菜单
    本篇内容介绍了“vue怎么实现自定义全局右键菜单”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果如图所示:注意:需要在项目中找到页面整体布...
    99+
    2023-06-29
  • OpenLayer实现自定义坐标点的绘制
    目录实现步骤引入相应的库绘制自定义图标获取当前地图所有图层判断重新绘制图标位置效果展示实现步骤 引入相应的库 import 'ol/ol.css'; import Map f...
    99+
    2024-04-02
  • C#序列化怎么自定义
    在C#中,可以通过实现ISerializable接口来自定义对象的序列化方式。ISerializable接口要求实现GetObjec...
    99+
    2024-03-01
    C#
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作