大家平时使用Log4j一般都是在classpath下放置一个log4j的配置文件,比如log4j.xml,里面配置好Appenders和Loggers,但是前一阵想做某需求的时候,想要的效果是每一个任务都要有一个单独的日志文件记录下来,比如job.001.log,job.002.log这种,这种完全不能使用配置文件来设置。

整体架构:

给log4j 增加 requestid log4j.logger配置_配置文件

Log4j的组成:

Log4j由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。

1.日志记录器(Loggers):控制要输出哪些日志记录语句,对日志信息进行级别限制。
2.输出端(Appenders):指定了日志将打印到控制台还是文件中。

3.日志格式化器(Layout):控制日志信息的显示格式。

于是点开Log4j的源码,研究了一番,发现使用Log4j的底层代码完全可以动态生成新的Logger,比较关键的类有


1



2



3


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。

Configuration

每一个LoggerContext都有一个有效的Configuaration,它包含了所有的Appenders、context-wide Filters、LoggerConfigs以及对StrSubstitutor的引用。在重新配置期间,两个Configuaration会同时存在;一旦日志器被重新赋予新的Configuaration,旧的Configuaration就会停止工作并丢弃。

LoggerConfig

LoggerConfig将会在Loggers在logging configuration中被声明的时候创建。在LoggerConfig 拥有一列类的过滤器(Filter),这些过滤器将会过来所有的记录日志的事件,只有符合要求的日志才会被传递到Appenders。因为LoggerConfig需要将事件传递给Appenders,所以它拥有一系列Appenders的引用。

Appender

根据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。


1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53



54



55



56



57



58



59



60



61



62



63



64



65


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);



}



}



测试类:

1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16


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);



}



}



}