Search code examples
javalog4j2webmethods

Log4j2 - to write separate log files for every appender/logger - webMethods


I am trying to create log4j2 log files for code in webMethods. The logger Name , the message and LEVEL will be passed by the user in run time, and based on that separate log files needs to be created per appender.

I have managed to make it work with the below set up

Log4j2 XML

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <RollingFile name="ROLL_ITLFileHandler" fileName="/esblogdata/logs/ITLFileHandler.log" filePattern="/esblogdata/logs/ITLFileHandler%d{yyyy-MM-dd}.log">
            <PatternLayout>
                <Pattern>%m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Appenders>
        <RollingFile name="ROLL_PublishCarrierEvent" fileName="/esblogdata/logs/PublishCarrierEvent.log" filePattern="/esblogdata/logs/PublishCarrierEvent%d{yyyy-MM-dd}.log">
            <PatternLayout>
                <Pattern>%m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Appenders>
        <RollingFile name="ROLL_ABC" fileName="/esblogdata/logs/ABC.log" filePattern="/esblogdata/logs/ABC%d{yyyy-MM-dd}.log">
            <PatternLayout>
                <Pattern>%m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Appenders>
        <RollingFile name="ROLL_EFG" fileName="/esblogdata/logs/EFG.log" filePattern="/esblogdata/logs/EFG%d{yyyy-MM-dd}.log">
            <PatternLayout>
                <Pattern>%m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Logger name="ITLFileHandler" level="DEBUG" additivity="true">
            <AppenderRef ref="ROLL_ITLFileHandler"/>
        </Logger>
        <Logger name="PublishCarrierEvent" level="DEBUG" additivity="true">
            <AppenderRef ref="ROLL_PublishCarrierEvent"/>
        </Logger>
        <Logger name="ABC" level="DEBUG" additivity="true">
            <AppenderRef ref="ROLL_ABC"/>
        </Logger>
        <Logger name="EFG" level="DEBUG" additivity="true">
            <AppenderRef ref="ROLL_EFG"/>
        </Logger>
        <Root level="DEBUG">
            <AppenderRef ref="ROLL_ITLFileHandler"/>
            <AppenderRef ref="ROLL_PublishCarrierEvent"/>
            <AppenderRef ref="ROLL_ABC"/>
            <AppenderRef ref="ROLL_EFG"/>
        </Root>
    </Loggers>
</Configuration>

Java Code to write Logs

            //Set Level - severity received from user in in run time as INFO, DEBUG etc.,
            Level level = Level.getLevel(severity);         
            ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();

            //LOG4J_CFG points to the location where log4j2 XML is kept
            ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File(LOG4J_CFG)));
            Configuration configuration = factory.getConfiguration(null, configurationSource);  
            
            // Get context instance
            LoggerContext context = new LoggerContext("test");          
            
            //Start logging system
            context.start(configuration);
                    
            // Get a reference for logger (logger name will be passed in runtime by user which will be similar to the Logger name Ex: ITLFilehandler, ABC, XYZ in above XML
            Logger logger = context.getLogger(loggerName);
            logger.log(level, finalMessage);            
            context.close();

But the problem is with the above set up, the logs are written only to the same file which is present in the last appender EFG.log

No matter what logger name i pass in the runtime (ABC, XYZ etc.,) everything goes to the same file EFG.log

Can someone guide here on what is wrong please ?

Thanks Ragav J


Solution

  • I have managed to fix this. There were couple of issues.

    • The code/set up for me worked only if used a LoggerContext. I had implemented that incorrectly when the log4j2 XML was being loaded, which caused all the trouble.
    • The suggestion provided above by FKhan also helped a lot with a slight change. The Routes pattern should be having a singe colon and not two. Corrected this from $${ctx::fileName} to $${ctx:fileName}

    The below Log4j2XML and Java service works perfectly where users can dynamically pass the log file name at run time

    Log4j2 XML

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="DEBUG">
        <Appenders>
            <Routing name="Routing">
                <Routes pattern="$${ctx:fileName}">
                    <Route>
                        <RollingFile name="RoutingLog" fileName="/esblogdata/logs/${ctx:fileName}.log" filePattern="/esblogdata/logs/${ctx:fileName}%d{yyyy-MM-dd}.log">
                            <PatternLayout>
                                <Pattern>%m%n</Pattern>
                            </PatternLayout>
                            <Policies>
                                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                            </Policies>
                        </RollingFile>
                    </Route>
                </Routes>
            </Routing>
        </Appenders>
        <Loggers>
            <Logger name="RoutingLogger" level="debug" additivity="true">
                <AppenderRef ref="Routing" level ="DEBUG"/>
            </Logger>
            <Root level="debug">
                    <appender-ref ref="Routing" />
                </Root>
        </Loggers>
    </Configuration>
    
    

    Java Code for creating log files

                            //Logging process LOG4J_CFG - String location of XML file
                            ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
                            ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File(LOG4J_CFG)));
                            Configuration configuration = factory.getConfiguration(null, configurationSource);
                            //debugLog ("Config setu up complete");
                            
                            // Get context instance
                            final LoggerContext context = new LoggerContext("test");
                            
                            
                            // Start logging system
                            context.start(configuration);
                                    
                            // Get a reference for logger
                            Logger logger = context.getLogger("Routing");
                            
                        
                            //Log data - finalLogFilename and finalMessage string to passed by users                    
                            ThreadContext.put("fileName", finalLogFileName);                            
                            logger.debug(finalMessage);                         
                            ThreadContext.remove("fileName");           
                    
                            
                            //Close Context
                            context.close();
    

    Thanks again for Piotr P. Karwasz and FKhan for the suggestions and pointers.