最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

通過自定制LogManager實(shí)現(xiàn)程序完全自定義的logger

 更新時(shí)間:2022年03月24日 14:32:40   作者:qingkangxu  
本章主要闡述怎么完全定制化LogManager來實(shí)現(xiàn)應(yīng)用程序完全自定制的logger,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前一篇博文介紹了JDK logging基礎(chǔ)知識 

博文中也提到LogManager,本章主要闡述怎么完全定制化LogManager來實(shí)現(xiàn)應(yīng)用程序完全自定制的logger,其實(shí)對于大多數(shù)開發(fā)者來說,很少有需要定制LogManager的時(shí)候,只有是需要單獨(dú)開發(fā)一個(gè)產(chǎn)品,需要完全獨(dú)立的logger機(jī)制時(shí)才有可能需要定制LogManager,比如:

1,希望自由定制log的輸出路徑 

2,希望完全定制log的format  

3,希望日志中的國際化信息采用自己定義的一套機(jī)制等

當(dāng)然,對于大型的中間件而言,自定義LogManager則是非常有必要的。

引言

對tomcat熟悉的讀者,有可能會注意到tomcat的啟動(dòng)腳本catalina.bat中也使用定制的LogManager,如下:

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

當(dāng)tomcat的bin路徑下存在tomcat-juli.jar文件(也就是存在定制的LogManager)時(shí),那么會強(qiáng)制在JVM系統(tǒng)屬性中指定org.apache.juli.ClassLoaderLogManager作為整個(gè)JVM的LogManager,以此來完成一些特殊操作。

websphere的啟動(dòng)腳本startServer.bat中也定義了自己的LogManager,如下:

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

怎么實(shí)現(xiàn)自定義的LogManager

首先要實(shí)現(xiàn)一個(gè)繼承自java.util.logging.LogManager的類:

子類覆蓋java.util.logging.LogManager的addLogger方法,在成功添加logger之后對logger做定制化操作,從代碼中可以看出addLogger方法調(diào)用了子類的internalInitializeLogger方法,internalInitializeLogger方法中先清空logger的所有handler,然后再增加一個(gè)自定義的Handler

需要說明一下:internalInitializeLogger方法中的操作(給logger增設(shè)我們自定義的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 Logger
		if (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;
	}
	/**
	 * Internal Method to initialize a list of unitialized loggers.
	 */
	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是一個(gè)把logger日志輸出到文件中的handler,可以通過com.bes.instanceRoot系統(tǒng)屬性來指定日志文件跟路徑;其次,ServerFileHandler也指定了自己的UniformLogFormatter;最后是需要覆蓋父類的publish方法,覆蓋的publish方法在做真正的日志輸入之前會檢查日志文件是否存在,然后就是創(chuàng)建一個(gè)和日志文件對應(yīng)的輸出流,把該輸出流設(shè)置為ServerFileHandler的輸出流以至日志輸出的時(shí)候能輸出到文件中。另外,WrapperStream僅僅是一個(gè)流包裝類。

這里也需要說一下:ServerFileHandler構(gòu)造方法中的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();
  }
  /**
   * Creates the file and initialized WrapperStream and passes it on to
   * Superclass (java.util.logging.StreamHandler).
   */
  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;
  }
}

實(shí)現(xiàn)Formatter

之前已經(jīng)提到過,使用logger日志輸出的時(shí)候,handler會自動(dòng)調(diào)用自己的formatter對日志做format,然后輸出格式化之后的日志。自定義的Formatter只需要覆蓋public String format(LogRecord record)便可。這個(gè)類本身很簡單,就是日志輸出時(shí)自動(dòng)增加指定格式的時(shí)間,加上分隔符,對日志進(jìn)行國際化處理等操作。 需要注意的是類中對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之后,在啟動(dòng)JVM的命令中增加系統(tǒng)屬性便可

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

加上這個(gè)系統(tǒng)屬性之后通過java.util.logging.Logger類獲取的logger都是經(jīng)過定制的LogManager作為初始化的,日志輸出的時(shí)候便會使用上面的ServerFileHandler#publish()方法進(jìn)行日志輸出,并使用UniformLogFormatter對日志進(jìn)行格式化。

以上就是通過自定制LogManager實(shí)現(xiàn)程序完全自定義的logger的詳細(xì)內(nèi)容,更多關(guān)于自定制LogManager實(shí)現(xiàn)自定義logger的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java 中IO流字符流詳解及實(shí)例

    Java 中IO流字符流詳解及實(shí)例

    這篇文章主要介紹了Java 中IO流字符流詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法示例

    Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法示例

    這篇文章主要介紹了Java BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類用法,結(jié)合實(shí)例形式詳細(xì)分析了Java使用BigInteger類,BigDecimal類,Date類,DateFormat類及Calendar類進(jìn)行數(shù)值運(yùn)算與日期運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • SpringSecurity授權(quán)實(shí)現(xiàn)基本思路

    SpringSecurity授權(quán)實(shí)現(xiàn)基本思路

    本文介紹了SpringSecurity中使用FilterSecurityInterceptor進(jìn)行權(quán)限校驗(yàn)的基本方法,通過SecurityContextHolder獲取Authentication中的權(quán)限信息,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • 使用session實(shí)現(xiàn)簡易購物車功能

    使用session實(shí)現(xiàn)簡易購物車功能

    這篇文章主要為大家詳細(xì)介紹了使用session實(shí)現(xiàn)簡易購物車功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • idea中不用git解除關(guān)聯(lián)的方式

    idea中不用git解除關(guān)聯(lián)的方式

    IntelliJ?IDEA是一款高效的Java編程環(huán)境,提供智能編碼輔助、J2EE、Ant等集成,支持本地和遠(yuǎn)程調(diào)試,本文講述了如何在IDEA中解除版本控制和刪除.git文件夾,幫助開發(fā)者更好地管理項(xiàng)目設(shè)置和提升開發(fā)效率
    2024-10-10
  • 詳解Spring學(xué)習(xí)總結(jié)——Spring實(shí)現(xiàn)AOP的多種方式

    詳解Spring學(xué)習(xí)總結(jié)——Spring實(shí)現(xiàn)AOP的多種方式

    這篇文章主要介紹了詳解Spring學(xué)習(xí)總結(jié)——Spring實(shí)現(xiàn)AOP的多種方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • JFreeChart動(dòng)態(tài)畫折線圖的方法

    JFreeChart動(dòng)態(tài)畫折線圖的方法

    這篇文章主要為大家詳細(xì)介紹了JFreeChart動(dòng)態(tài)畫折線圖的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Java數(shù)據(jù)結(jié)構(gòu)之復(fù)雜度篇

    Java數(shù)據(jù)結(jié)構(gòu)之復(fù)雜度篇

    算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度。其作用:?時(shí)間復(fù)雜度是度量算法執(zhí)行的時(shí)間長短;而空間復(fù)雜度是度量算法所需存儲空間的大小
    2022-01-01
  • IDEA插件之Mybatis Log plugin 破解及安裝方法

    IDEA插件之Mybatis Log plugin 破解及安裝方法

    這篇文章主要介紹了IDEA插件之Mybatis Log plugin 破解方法及安裝方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼

    Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼

    這篇文章主要介紹了Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼,實(shí)現(xiàn)Callable和實(shí)現(xiàn)Runnable類似,但是功能更強(qiáng)大,具體表現(xiàn)在可以在任務(wù)結(jié)束后提供一個(gè)返回值,Runnable不行,call方法可以拋出異,Runnable的run方法不行,需要的朋友可以參考下
    2023-08-08

最新評論

汽车| 嘉黎县| 宽甸| 和田市| 黄骅市| 卢龙县| 遂溪县| 高平市| 马鞍山市| 北京市| 鸡泽县| 高平市| 梁山县| 镇沅| 游戏| 郸城县| 凤翔县| 呼和浩特市| 扶余县| 宝清县| 连江县| 建平县| 静宁县| 磐安县| 绥化市| 碌曲县| 中山市| 平舆县| 星座| 修武县| 浮梁县| 广东省| 讷河市| 巨鹿县| 贵港市| 竹山县| 手游| 阳朔县| 莱阳市| 长宁县| 孝义市|