你們平時使用Log4j通常都是在classpath下放置一個log4j的配置文件,好比log4j.xml,裏面配置好Appenders和Loggers,可是前一陣想作某需求的時候,想要的效果是每個任務都要有一個單獨的日誌文件記錄下來,好比job.001.log,job.002.log這種,這種徹底不能使用配置文件來設置。apache
總體架構:架構
Log4j由三個重要的組成構成:日誌記錄器(Loggers),輸出端(Appenders)和日誌格式化器(Layout)。
1.日誌記錄器(Loggers):控制要輸出哪些日誌記錄語句,對日誌信息進行級別限制。
2.輸出端(Appenders):指定了日誌將打印到控制檯仍是文件中。app
3.日誌格式化器(Layout):控制日誌信息的顯示格式。socket
因而點開Log4j的源碼,研究了一番,發現使用Log4j的底層代碼徹底能夠動態生成新的Logger,比較關鍵的類有ide
org.apache.logging.log4j.core.Layout負責格式
org.apache.logging.log4j.core.Appender就是配置文件裏的Appender,咱們使用FileAppender,也可使用RollingFileAppender,
org.apache.logging.log4j.core.config.Configuration和org.apache.logging.log4j.core.LoggerContext是負責Log4j的配置的。
在日誌系統中,LoggerContext扮演者重要的角色。然而,根據實際狀況,一個應用中可能存在多個有效的LoggerContext。測試
每個LoggerContext都有一個有效的Configuaration,它包含了全部的Appenders、context-wide Filters、LoggerConfigs以及對StrSubstitutor的引用。在從新配置期間,兩個Configuaration會同時存在;一旦日誌器被從新賦予新的Configuaration,舊的Configuaration就會中止工做並丟棄。spa
LoggerConfig將會在Loggers在logging configuration中被聲明的時候建立。在LoggerConfig 擁有一列類的過濾器(Filter),這些過濾器將會過來全部的記錄日誌的事件,只有符合要求的日誌纔會被傳遞到Appenders。由於LoggerConfig須要將事件傳遞給Appenders,因此它擁有一系列Appenders的引用。debug
根據logger請求選擇去接受或者拒絕該只是他們的一個能力。Log4j容許日誌打印服務打印到多個目的地上。在Log4j的說法是一個輸出的目的地對應着一個Appdender。如今的Appender容許是console, files, remote socket servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various database APIs。日誌
是在Log4j2.3下測試經過的。注意在不使用Logger的時候必定要調用stop方法將Logger移除,否則我本身測試生成7000多個Logger後便會報錯open too many file。code
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.config.AppenderRef; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.layout.PatternLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * */ public class JobLogFactory { private JobLogFactory() { } public static void start(int jobId) {
//爲false時,返回多個LoggerContext對象, true:返回惟一的單例LoggerContext
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); final Configuration config = ctx.getConfiguration();
//建立一個展現的樣式:PatternLayout, 還有其餘的日誌打印樣式。 Layout layout = PatternLayout.createLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN, config, null, null, true, false, null, null); //TriggeringPolicy tp = SizeBasedTriggeringPolicy.createPolicy("10MB"); //Appender appender = RollingFileAppender.createAppender(String.format(" // logs/test/syncshows-job-%s.log", jobID), // "/logs/test/" + jobID + "/syncshows-job-" + jobID + ".log.gz", // "true", jobID, null, null, null, tp, null, layout, null, // null, null, null, config);
// 日誌打印方式——輸出爲文件
Appender appender = FileAppender.createAppender( String.format("logs/test/syncshows-job-%s.log", jobId), "true", "false", "" + jobId, null, "true", "true", null, layout, null, null, null, config); appender.start(); config.addAppender(appender); AppenderRef ref = AppenderRef.createAppenderRef("" + jobId, null, null); AppenderRef[] refs = new AppenderRef[]{ref}; LoggerConfig loggerConfig = LoggerConfig.createLogger("false", Level.ALL, "" + jobId, "true", refs, null, config, null); loggerConfig.addAppender(appender, null, null); config.addLogger("" + jobId, loggerConfig); ctx.updateLoggers(); } public static void stop(int jobId) { final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); final Configuration config = ctx.getConfiguration(); config.getAppender("" + jobId).stop(); config.getLoggerConfig("" + jobId).removeAppender("" + jobId); config.removeLogger("" + jobId); ctx.updateLoggers(); } /** * 獲取Logger * * 若是不想使用slf4j,那這裏改爲直接返回Log4j的Logger便可 * @param jobId * @return */ public static Logger createLogger(int jobId) { start(jobId); return LoggerFactory.getLogger("" + jobId); } }
測試類:
import org.slf4j.Logger; /** * simple test */ public class LoggerTest { public static void main(String[] args) { for(int i=0;i<50000;i++) { Logger logger = JobLogFactory.createLogger(i); logger.info("Testing testing testing 111"); logger.debug("Testing testing testing 222"); logger.error("Testing testing testing 333"); JobLogFactory.stop(i); } } }
致謝,感謝您的閱讀!