Log4j2 dynamically generates a logger object without using the configuration file. log4j2logger
Generally, Log4j is used to place a log4j configuration file under classpath, such as log4j. in xml, the Appenders and Loggers are configured. However, when you wanted to meet a certain requirement, you wanted to record a separate log file for each task, such as job.001.log, such as job.002.log, which cannot be set using the configuration file.
Overall architecture:
Log4j composition:
Log4j consists of three important components: logger, Appenders, and Layout ).
1. Loggers: controls the log record statements to be output and limits the log information.
2. Appenders: Specifies whether the log will be printed to the console or a file.
3. Log formatter (Layout): controls the display format of log information.
So I opened the source code of Log4j and studied it. I found that the underlying code of Log4j can generate a new Logger dynamically. The key classes are:
Org. apache. logging. log4j. core. layout is responsible for org. apache. logging. log4j. core. appender is the Appender in the configuration file. We use FileAppender or RollingFileAppender, org. apache. logging. log4j. core. config. configuration and org. apache. logging. log4j. core. loggerContext is responsible for Log4j configuration.
LoggerContext
LoggerContext plays an important role in the log system. However, according to the actual situation, there may be multiple valid LoggerContext in an application.
Configuration
Each LoggerContext has a valid Configuaration, which includesAllAppenders, context-wide Filters, LoggerConfigs, and references to StrSubstitutor. During the reconfiguration, two Configuaration instances exist at the same time. Once the logstore is assigned a new Configuaration, the old Configuaration instance stops working and is discarded.
LoggerConfig
LoggerConfig will be created when Loggers are declared in the logging configuration. LoggerConfig has a column of filters. These filters will be used to record all log events. Only logs that meet the requirements will be passed to the Appenders. Because LoggerConfig needs to pass events to Appenders, it has a series of Appenders references.
Appender
It is only their capability to accept or reject logger requests. Log4j allows the log printing service to print data to multiple destinations. In Log4j, an output destination corresponds to an Appdender. Currently, the Appender can be console, files, remote socket servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various database APIs.
It was tested in Log4j2.3. Note that when you do not use Logger, you must call the stop method to remove Logger. Otherwise, an error will be reported after I test to generate more than 7000 Logger.
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 ){
// If it is false, multiple LoggerContext objects are returned. true: return a unique LoggerContext
Final LoggerContext ctx = (LoggerContext) LogManager. getContext (false); final Configuration config = ctx. getConfiguration ();
// Create a display style: PatternLayout and other log print styles. Layout layout = PatternLayout. createLayout (PatternLayout. DEFAULT_CONVERSION_PATTERN, config, null, null, true, false, null, null); // TriggeringPolicy tp = SizeBasedTriggeringPolicy. createPolicy ("10 MB"); // Appender appender = RollingFileAppender. createAppender (String. format ("// logs/test/syncshows-job-% s. log ", jobID), //"/logs/test/"+ jobID +"/syncshows-job-"+ jobID +" .log.gz ", //" true ", jobID, null, tp, null, layout, null, // null, config );
// Log printing method -- the output is a file
Appender appender = FileAppender. createAppender (String. format ("logs/test/syncshows-job-% s. log ", jobId)," true "," false "," "+ jobId, null," true "," true ", null, layout, 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 ();}/*** get Logger *** if you do not want to use slf4j, then, you can directly return the Logger of Log4j * @ param jobId * @ return */public static Logger createLogger (int jobId) {start (jobId); return LoggerFactory. getLogger ("" + jobId );}}
Test class:
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); } }}
Thank you,Thank you for reading!