讓log4j通過判斷日誌消息的內容後再進行日誌的輸出。
如果我們要在一個有成百上千個用戶的系統中通過日誌信息來判斷某一個用戶的行爲是否正確的話,可以想象會有多大的難度。(要從成百上千個用戶產生的日誌中準確的定位到某一個用戶幾乎是不可能的)所以這就產生了一個新的需求,log4j不僅可以配置級別,同時他應該還可以配置輸出那個設備的日誌,也就是日誌是否輸出不僅要根據級別,還要根據日誌和業務的關係。
實現的原理
Logger對象中debug方法的參數類型是java.long.Object類型,平時我們都是直接將想要輸出的日誌以java.long.String類型傳給debug方法,現在我們將會以一個大小是2的String[]類型作爲參數,String[0]中存放和這條日誌相關聯的業務信息,String[1]中存放要輸出的日誌信息。其他的info error 等方法都採用相同的辦法。
現在就是要解決Appender問題了。最簡單的辦法是自己創建一個Appende類,讓這個類去繼承我們以前用的Appender類,並重寫doAppend(LoggingEvent event)方法就可以了。
實例代碼:
PurposefulConsoleAppender.java
package com.kun.appender;
import org.apache.log4j.ConsoleAppender; import org.apache.log4j.spi.LoggingEvent;
public class PurposefulConsoleAppender extends ConsoleAppender { public static final String PURPOSE_ALL = "ALL";
protected String purpose = PURPOSE_ALL;
public String getPurpose() { return purpose; }
public void setPurpose(String purpose) { this.purpose = purpose; }
@Override public synchronized void doAppend(LoggingEvent event) { if (event.getMessage() instanceof String[]) { String[] message = (String[]) event.getMessage(); if (getPurpose().equalsIgnoreCase(PURPOSE_ALL) || PURPOSE_ALL.equalsIgnoreCase(message[0]) || getPurpose().equals(message[0])) { Throwable throwable = null; if (event.getThrowableInformation() != null) { throwable = event.getThrowableInformation().getThrowable(); } LoggingEvent newEvent = new LoggingEvent( event.fqnOfCategoryClass, event.getLogger(), event.timeStamp, event.getLevel(), message[1], throwable); super.doAppend(newEvent); } } else { super.doAppend(event); }
} }
|
TestLog4jPurposeful.java
package com.kun;
import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator;
public class TestLog4jPurposeful { public static Logger logger = Logger.getLogger(TestLog4jPurposeful.class);
public static void printLog() { if (logger.isDebugEnabled()) { logger.debug(new String[]{"11","debug!!"}); } if (logger.isInfoEnabled()) { logger.info(new String[]{"22","info!!"}); } logger.error(new String[]{"11","error!!"}); }
public static void main(String[] args) { PropertyConfigurator.configure("./log4j.properties");
while (!Thread.interrupted()) { TestLog4jPurposeful.printLog();
try { Thread.sleep(1000); } catch (InterruptedException e) { } } } }
|
log4j.properties (log4j的配置文件)
#-----------------------------------------------------------------------------! # Global configuration for log4j #-----------------------------------------------------------------------------! # Do use default configuration. #----------------------------------------------------------------------------! #Configure categories (loggers) #----------------------------------------------------------------------------! #ROOT CATEGORY (Usually sufficient to set this one only) log4j.rootCategory=debug,PURPOSEFULCONSOLE # YOUR CATEGORIES (to customize logging per class/pkg/project/etc) #----------------------------------------------------------------------------! #Configure appenders (log destinations/targets) and their options ! #----------------------------------------------------------------------------! #WRITE TO CONSOLE (stdout or stderr): log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.ImmediateFlush=true log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm}] (%F:%M:%L) - %m%n
#WRITE TO PURPOSEFULCONSOLE (stdout or stderr): log4j.appender.PURPOSEFULCONSOLE=com.kun.appender.PurposefulConsoleAppender log4j.appender.PURPOSEFULCONSOLE.ImmediateFlush=true log4j.appender.PURPOSEFULCONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.PURPOSEFULCONSOLE.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm}] (%F:%M:%L) - %m%n log4j.appender.PURPOSEFULCONSOLE.Purpose=22 |