log4J2自定義pattern參數輸出


log4j2官網地址:http://logging.apache.org/log4j/2.x/manual/extending.html#PatternConverters

 

原文地址https://blog.csdn.net/hfismyangel/article/details/80182662

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;

@Plugin(name = "TIDPatternConverter", category = PatternConverter.CATEGORY)//Plugin 表示的是這是一個插件,name是名稱,category為PatternConverter.CATEGORY(目前插件只有這個選擇)ConverterKeys表示的就是自定義的參數,可以多個
@ConverterKeys({ "T", "TID" })  //
public class TIDPatternConverter extends LogEventPatternConverter {   //定義一個類繼承LogEventPatternConverter

    private static final TIDPatternConverter INSTANCE = new TIDPatternConverter();

    public static TIDPatternConverter newInstance(   //定義的這個類必須提供一個newInstance方法,參數是final String[] options,返回值為定義的類(對於是否是單例沒有明確的要求)
            final String[] options) {
        return INSTANCE;
    }

    private TIDPatternConverter(){   //提供一個私有的構造函數,調用父類的構造函數,函數需要提供兩個參數 第一個參數是轉換器的名稱,第二個是css樣式
        super("TID", "TID");
    }

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {  //還有主要的工作format,這里有兩個參數,LogEvent是系統已經存在的一些可選數據,StringBuilder 表示的是最終的輸出字符流。一般都是將自定義的append進去
        toAppendTo.append(Thread.currentThread().getId());
    }

}

   

定義好了之后,然后在log4j2的配置文件中設置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn"
packages="com.hoperun.zhulongxiang.asnc_print_different_logfile">
<Appenders>
    <console name="console" target="system_out">
		<!-- 只輸出level及以上級別的信息(onmatch),其他的直接拒絕(onmismatch)。默認就是trace。      
		<thresholdfilter 
			level="trace" onmatch="accept" onmismatch="deny"/> -->
		<patternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-10T] [%-5level] %l - %m%n" />    
	</console>
</Appenders>
<Loggers>
	<Root level="INFO">
		<AppenderRef ref="console" />
	</Root>
</Loggers>
</Configuration>

    這個方法好像自己試了下沒有試通,這個T本來就有,可以直接用(待定)

下面這個方法使用log4j2自帶的功能  MDC

MDC的概念:Manufacturing Data Collection  生產數據實時采集和分析
有時實際開發過程沒有發現的BUG在生產環境才出現,需要到生產環境去分析實時日志來進行BUG跟蹤;LOG4J2提供了MDC功能可以將特定用戶的日志單獨處理輸出到特定的文件中。
 
1.DynamicThresholdFilter 從整體上控制日志默認輸出級別,對於特定的值可以調整日志級別
 <!--ThreadContext.put("loginId", "User1"); 除了User1之外其他的日志都默認是ERROR級別,USER1相關的日志是DEBUG級別  -->
 
 <DynamicThresholdFilter key="loginId"
  defaultThreshold="ERROR" onMatch="ACCEPT" onMismatch="DENY">
  <KeyValuePair key="User1" value="DEBUG" />
 </DynamicThresholdFilter>

   

2.ThreadContextMapFilter 控制文件的記錄內容,符合條件才記錄到文件,其他都拒絕寫入日志
<!-- 我只記錄USER1的日志信息,找生產環境BUG用的。 -->
  <File name="testUserLog" fileName="target/testUserLog2" append="true">
    <ThreadContextMapFilter onMatch="ACCEPT"    onMismatch="DENY">
       <KeyValuePair key="loginId" value="User1" />
    </ThreadContextMapFilter>
   <PatternLayout   pattern="%n%t %-5p %c{2} MDC%X - %m" />
  </File>

  

3.在WEB應用中可以在過濾器filter中加入以下代碼:
ThreadContext.put("loginId",Session.getAttribute("userId")); //userId代表的就是登陸會話的工號信息
如果是APP,可以使用代理模式(如果用SPRING,可以使用aop,如果沒有SPRING,可以使用CGLIB或者其他)來實現
在log4j2.xml文件中使用 %X{loginId}  就可以在日志中輸出.
 
如下代碼已經測試過可以輸出沒問題。
import java.util.UUID;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class TestRequestListener implements ServletRequestListener {
	protected static final Logger LOGGER = LoggerFactory.getLogger(TestRequestListener.class);

	public void requestInitialized(ServletRequestEvent arg0) {
		ThreadContext.put("id", UUID.randomUUID().toString());

	}

	public void requestDestroyed(ServletRequestEvent arg0) {
		ThreadContext.clearMap();
	}
}

在log4j2.xml文件中使用 %X{id}

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn"
packages="com.hoperun.zhulongxiang.asnc_print_different_logfile">
<Appenders>
    <console name="console" target="system_out">
	<patternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} {%X{id}} [%-5level] %l - %m%n" />
    </console>
</Appenders>
<Loggers>
	<Root level="INFO">
		<AppenderRef ref="console" />
	</Root>
</Loggers>
</Configuration>

  

 

 以上是log4j2的配置,使用log4j可以繼承patternLayout和patternParser,自定義一個patternConverter實現。如下:自己還沒有親自試過下面的方法

   https://blog.csdn.net/huaieli1/article/details/58601306

import org.apache.log4j.helpers.FormattingInfo;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;
 
public class ExPatternParser extends PatternParser {
	 
	 public ExPatternParser(String pattern) {
	   super(pattern);
	  }
	 
	 /**
	   * 重寫finalizeConverter,對特定的占位符進行處理,T表示線程ID占位符
	   */
	  @Override
	  protected void finalizeConverter(char c) {
	   if (c == 'T') {
	    this.addConverter(new ExPatternConverter(this.formattingInfo));
	   } else {
	    super.finalizeConverter(c);
	   }
	  }
	 
	 private static class ExPatternConverter extends PatternConverter {
	 
	  public ExPatternConverter(FormattingInfo fi) {
	    super(fi);
	   }
	 
	  /**
	    * 當需要顯示線程ID的時候,返回當前調用線程的ID
	    */
	   @Override
	   protected String convert(LoggingEvent event) {
	    return String.valueOf(Thread.currentThread().getId());
	   }
    }
}

  

import org.apache.log4j.PatternLayout;
import org.apache.log4j.helpers.PatternParser;
 
public class ExPatternLayout extends PatternLayout {
	 
	 public ExPatternLayout(String pattern) {
	   super(pattern);
	  }
	 
	 public ExPatternLayout() {
	   super();
	  }
	  
	  /**
	   * 重寫createPatternParser方法,返回PatternParser的子類
	   */
	  @Override
	  protected PatternParser createPatternParser(String pattern) {
	   return new ExPatternParser(pattern);
	  }
	 }

  修改Log4j的配置文件,將輸出樣式修改為拓展類ExPatternLayout

#設置輸出樣式  
log4j.appender.appender1.layout=org.apache.log4j.ExPatternLayout 

  

到此已經擴展完成,將以上內容編譯后(可以打成jar包)和log4j.jar一同使用(使用同一個類裝載器裝載),然后配置log4j.properties類,修改

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout為

log4j.appender.stdout.layout=ex.log4j.ExPatternLayout

在輸出格式中增加%T(log4j定義%t表示線程名稱,%T沒有定義,所以這里使用%T表示線程ID),log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %T %c %5p - %m%n

下面就按照平常的習慣使用log4j即可,再輸出的日志中就會包含線程ID,例如:2009-03-29 10:43:58 1 test.log.Log4jTest  INFO - ok

時間后面的'1'就表示線程id,當在多線程環境下,例如web環境,用這種方式就能很容易區分出一次web請求過程中打印出的日志信息,而不會和其他web請求打印出的日志信息混淆。這樣即增加的日志的可讀性,也不會輸出太多的無用信息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM