Log4J2 Architecture
Extended diagram of architecture accord to the description and source code.reference https://logging.apache.org/log4j/2.x/index.html
The original diagram that is on the official web page is
Why Log4j2
Alternatives:
SLF4J, LogBack
Why Log4j2
1.- Log4J1
and Logback loss events while reconfigurating. Log4j2 Don’t.
Appenders can be configurated to allow
exception
2.- Next
generation Asyncronous Loggers based on LMAX Disruptor Library. Multi-threaded
scenarios Asynchronous Logger have 10 times higher throughput, low latency.
3.- Log4j2
is garbage free.
4.- Plugin
system for easy extend the framework by adding new Appenders, Filters, Layouts,
Lookups.
6.- Support
custom log levels.
7.- Support
Lambd Expressions.
8.- Support
Message object, for passing it though logging system. Message Types can be
custom also the Layouts, Filters, Lookups to manipulate them.
9.- Support
Filters can be configurated to process
events before they are handled by a Logger. Or Appender.
10.-
Appenders accept a Layout, allowing the data to be transported in any format
desired.
11.- Layout
always return a byte array, can by used on any Appender, not only those of
OutputStream
12.- Syslog
appender supports TCP, UDP
Architecture description
The diagram UML is self explanatory, following the relations and the cardinality.
Consider that exists also a AsyncAppender.
Configuration Example
The posibilities of configurations are so many, on diferent file formats like XML, JSON, YAML, properties. To Start in a Simple maner is described on next picture the flow control of logEvent generated on the Application.The program to be used for test log4j2
Main App for Test
public class Scheduler { final static Logger logger = LogManager.getLogger();
//final static Logger logger = LogManager.getLogger( Scheduler.class); // same public static void main(String... args) { LoggerContext loggerContext = LoggerContext.getContext();
System.out.println( String.format("logger.getName(), getLevel() = %s, %s", logger.getName(), logger.getLevel())); //com.bext.Scheduler
System.out.println( "loggerContext.getName(): " + loggerContext.getName()); // Default
System.out.println( "Congifuration.toString(): " + LoggerContext.getContext().getConfiguration().toString());
//Configurator.setRootLevel( Level.ALL);
logger.trace("Scheduler [...");
if (!logger.isTraceEnabled()) System.out.println("Scheduler Trace is Disabled");
if (!logger.isInfoEnabled()) System.out.println("Scheduler Info id Disabled");
if (!logger.isDebugEnabled()) System.out.println("Scheduler Debug is Disabled");
if (!logger.isWarnEnabled()) System.out.println("Scheduler Warn is Disabled");
if (!logger.isErrorEnabled()) System.out.println("Scheduler Error is Disabled");
if (!logger.isFatalEnabled()) System.out.println("Scheduler Fatal is Disabled");
logger.debug("Scheduler logging debug");
logger.info("Scheduler logging info");
logger.warn("Scheduler logging warn ");
logger.error("Scheduler logging error ");
logger.fatal("Scheduler logging fatal "); ServiceA serviceA = new ServiceA(); serviceA.info(); logger.trace("Scheduler ...]"); } }
Auxiliar class ServiceA
public class ServiceA { final static Logger logger = LogManager.getLogger();
//final static Logger logger = LogManager.getLogger( ServiceA.class); public String info() { System.out.println( String.format("logger.getName(), getLevel() = %s, %s", logger.getName(), logger.getLevel()));
logger.trace("ServiceA.info() [...");
if (!logger.isTraceEnabled()) System.out.println("ServiceA Trace is Disabled");
if (!logger.isInfoEnabled()) System.out.println("ServiceA Info id Disabled");
if (!logger.isDebugEnabled()) System.out.println("ServiceA Debug is Disabled");
if (!logger.isWarnEnabled()) System.out.println("ServiceA Warn is Disabled");
if (!logger.isErrorEnabled()) System.out.println("ServiceA Error is Disabled");
if (!logger.isFatalEnabled()) System.out.println("ServiceA Fatal is Disabled");
logger.debug("logging debug");
logger.info("logging info");
logger.warn("logging warn ");
logger.error("logging error ");
logger.fatal("logging fatal ");
logger.trace("ServiceA.info() ...]");
return "MessageSerivice.info Junit5"; } }
Lets Start with a simle config file which generates an output of a simple scheduler that calls a simple service. this outpus goes to STDOUT
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" strict="true" name="XMLConfigTest" packages="">
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%d{HH:mm:ss.SSS} |%-5p | %-15c{1} | %m%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
We get lots of info, before and after the info we are interested on, that's because the Configuration status is on TRACE, So let filter to FATAL to discard the info related to the log4j2 framework.
...
2019-11-27 13:41:15,057 main TRACE Unregistering but no MBeans found matching 'org.apache.logging.log4j2:type=18b4aac2,component=Loggers,name=*,subtype=RingBuffer'
2019-11-27 13:41:15,057 main DEBUG Registering MBean org.apache.logging.log4j2:type=18b4aac2
2019-11-27 13:41:15,058 main DEBUG Registering MBean org.apache.logging.log4j2:type=18b4aac2,component=StatusLogger
2019-11-27 13:41:15,058 main DEBUG Registering MBean org.apache.logging.log4j2:type=18b4aac2,component=ContextSelector
2019-11-27 13:41:15,058 main DEBUG Registering MBean org.apache.logging.log4j2:type=18b4aac2,component=Loggers,name=
2019-11-27 13:41:15,058 main DEBUG Registering MBean org.apache.logging.log4j2:type=18b4aac2,component=Appenders,name=STDOUT
2019-11-27 13:41:15,058 main TRACE Using DummyNanoClock for nanosecond timestamps.
2019-11-27 13:41:15,059 main DEBUG Reconfiguration complete for context[name=Default] at URI D:\proy\junit5Log4j\target\classes\log4j2.xml (org.apache.logging.log4j.core.LoggerContext@3590fc5b) with optional ClassLoader: null
2019-11-27 13:41:15,059 main DEBUG Shutdown hook enabled. Registering a new one.
2019-11-27 13:41:15,059 main DEBUG LoggerContext[name=Default, org.apache.logging.log4j.core.LoggerContext@3590fc5b] started OK.
logger.getName(), getLevel() = com.bext.Scheduler, TRACE
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
13:41:15.061 |TRACE | Scheduler | Scheduler [...
13:41:15.063 |DEBUG | Scheduler | Scheduler logging debug
13:41:15.063 |INFO | Scheduler | Scheduler logging info
13:41:15.063 |WARN | Scheduler | Scheduler logging warn
13:41:15.063 |ERROR | Scheduler | Scheduler logging error
13:41:15.063 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, TRACE
13:41:15.064 |TRACE | ServiceA | ServiceA.info() [...
13:41:15.064 |DEBUG | ServiceA | logging debug
13:41:15.064 |INFO | ServiceA | logging info
13:41:15.064 |WARN | ServiceA | logging warn
13:41:15.064 |ERROR | ServiceA | logging error
13:41:15.064 |FATAL | ServiceA | logging fatal
13:41:15.064 |TRACE | ServiceA | ServiceA.info() ...]
13:41:15.064 |TRACE | Scheduler | Scheduler ...]2019-11-27 13:41:15,065 pool-1-thread-1 DEBUG Stopping LoggerContext[name=18b4aac2, org.apache.logging.log4j.core.LoggerContext@689604d9]
2019-11-27 13:41:15,065 pool-1-thread-1 DEBUG Stopping LoggerContext[name=18b4aac2, org.apache.logging.log4j.core.LoggerContext@689604d9]...
2019-11-27 13:41:15,065 pool-1-thread-1 TRACE Unregistering 1 MBeans: [org.apache.logging.log4j2:type=18b4aac2]
2019-11-27 13:41:15,065 pool-1-thread-1 TRACE Unregistering 1 MBeans: [org.apache.logging.log4j2:type=18b4aac2,component=StatusLogger]
2019-11-27 13:41:15,066 pool-1-thread-1 TRACE Unregistering 1 MBeans: [org.apache.logging.log4j2:type=18b4aac2,component=ContextSelector]
2019-11-27 13:41:15,066 pool-1-thread-1 TRACE Unregistering 1 MBeans: [org.apache.logging.log4j2:type=18b4aac2,component=Loggers,name=]
2019-11-27 13:41:15,066 pool-1-thread-1 TRACE Unregistering 1 MBeans: [org.apache.logging.log4j2:type=18b4aac2,component=Appenders,name=STDOUT]
2019-11-27 13:41:15,067 pool-1-thread-1 TRACE Unregistering but no MBeans found matching 'org.apache.logging.log4j2:type=18b4aac2,component=AsyncAppenders,name=*'
2019-11-27 13:41:15,067 pool-1-thread-1 TRACE Unregistering but no MBeans found matching 'org.apache.logging.log4j2:type=18b4aac2,component=AsyncLoggerRingBuffer'
2019-11-27 13:41:15,067 pool-1-thread-1 TRACE Unregistering but no MBeans found matching 'org.apache.logging.log4j2:type=18b4aac2,component=Loggers,name=*,subtype=RingBuffer'
2019-11-27 13:41:15,067 pool-1-thread-1 TRACE Stopping XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]...
...
Setting the Configuration status ="FATAL" only get the log info of our interest. also lets filter the logger root to ALL.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="FATAL" strict="true" name="XMLConfigTest" packages="">
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%d{HH:mm:ss.SSS} |%-5p | %-15c{1} | %m%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="ALL">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
Now we just get
com.bext.Scheduler
logger.getName(), getLevel() = com.bext.Scheduler, ALL
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
13:53:16.840 |TRACE | Scheduler | Scheduler [...
13:53:16.843 |DEBUG | Scheduler | Scheduler logging debug
13:53:16.843 |INFO | Scheduler | Scheduler logging info
13:53:16.843 |WARN | Scheduler | Scheduler logging warn
13:53:16.843 |ERROR | Scheduler | Scheduler logging error
13:53:16.843 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, ALL
13:53:16.844 |TRACE | ServiceA | ServiceA.info() [...
13:53:16.844 |DEBUG | ServiceA | logging debug
13:53:16.844 |INFO | ServiceA | logging info
13:53:16.844 |WARN | ServiceA | logging warn
13:53:16.844 |ERROR | ServiceA | logging error
13:53:16.844 |FATAL | ServiceA | logging fatal
13:53:16.844 |TRACE | ServiceA | ServiceA.info() ...]
13:53:16.844 |TRACE | Scheduler | Scheduler ...]
Process finished with exit code 0
Lets Apply filter to logger root to ERROR, we just get the info from ERROR TO FATAL.
logger.getName(), getLevel() = com.bext.Scheduler, ERROR
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
Scheduler Trace is Disabled
Scheduler Info id Disabled
Scheduler Debug is Disabled
Scheduler Warn is Disabled
13:57:09.101 |ERROR | Scheduler | Scheduler logging error
13:57:09.103 |FATAL | Scheduler | Scheduler logging fatal logger.getName(), getLevel() = com.bext.ServiceA, ERROR
ServiceA Trace is Disabled
ServiceA Info id Disabled
ServiceA Debug is Disabled
ServiceA Warn is Disabled
13:57:09.104 |ERROR | ServiceA | logging error
13:57:09.104 |FATAL | ServiceA | logging fatal
Now Lets create Two loggers, One that capture the events of the Scheduler class and send it to STDOUT, and other Logger to capture the events of the ServiceA to a file.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="FATAL" strict="true" name="XMLConfigTest" packages="">
<Properties>
<Property name="filename">target/test.log</Property>
</Properties>
<!-- <Filter type="ThresholdFilter" level="ERROR"/> -->
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%d{HH:mm:ss.SSS} |%-5p | %-15c{1} | %m%n"/>
</Appender>
<Appender type="File" name="File" fileName="${filename}" append="false">
<Layout type="PatternLayout">
<Pattern>%d{HH:mm:ss.SSS}| %-5p | %-15c{1} | %m%n</Pattern>
</Layout>
</Appender>
</Appenders>
<Loggers>
<Logger name="com.bext.Scheduler" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" >
<AppenderRef ref="File"/>
</Logger> <Root level="ERROR">
<!-- <AppenderRef ref="STDOUT"/> -->
<!-- <AppenderRef ref="File"/> -->
</Root>
</Loggers>
</Configuration>
Observe the events are filtered at ERROR level by Logger Root over the others to loggers, so we get
STDOUT
logger.getName(), getLevel() = com.bext.Scheduler, ERROR
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
Scheduler Trace is Disabled
Scheduler Info id Disabled
Scheduler Debug is Disabled
Scheduler Warn is Disabled
14:07:53.900 |ERROR | Scheduler | Scheduler logging error
14:07:53.902 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, ERROR
ServiceA Trace is Disabled
ServiceA Info id Disabled
ServiceA Debug is Disabled
ServiceA Warn is Disabled
FILE log
14:07:53.903| ERROR | ServiceA | logging error 14:07:53.903| FATAL | ServiceA | logging fatal
We adjust the logger STDOUT to trace the events of com.bext.*, this will include Schedurer and ServiceA class.
<Loggers>
<Logger name="com.bext" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" >
<AppenderRef ref="File"/>
</Logger>
We get from ERROR .. FATAL
STDOUT
logger.getName(), getLevel() = com.bext.Scheduler, ERROR
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
Scheduler Trace is Disabled
Scheduler Info id Disabled
Scheduler Debug is Disabled
Scheduler Warn is Disabled
14:17:39.724 |ERROR | Scheduler | Scheduler logging error
14:17:39.726 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, ERROR
ServiceA Trace is Disabled
ServiceA Info id Disabled
ServiceA Debug is Disabled
ServiceA Warn is Disabled
14:17:39.727 |ERROR | ServiceA | logging error
14:17:39.727 |FATAL | ServiceA | logging fatal
Now override the filter ERROR on logger root, to specific lever on Schedure logger, and ServiceA logger.
<Loggers>
<Logger name="com.bext.Scheduler" level="TRACE" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" level="DEBUG" >
<AppenderRef ref="File"/>
</Logger> <Root level="ERROR">
<!-- <AppenderRef ref="STDOUT"/> -->
<!-- <AppenderRef ref="File"/> -->
</Root> </Loggers>
STDOUT We get from TRACE...FATAL
logger.getName(), getLevel() = com.bext.Scheduler, TRACE
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
14:21:52.145 |TRACE | Scheduler | Scheduler [...
14:21:52.148 |DEBUG | Scheduler | Scheduler logging debug
14:21:52.148 |INFO | Scheduler | Scheduler logging info
14:21:52.148 |WARN | Scheduler | Scheduler logging warn
14:21:52.148 |ERROR | Scheduler | Scheduler logging error
14:21:52.148 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, DEBUG
ServiceA Trace is Disabled
14:21:52.150 |TRACE | Scheduler | Scheduler ...]
Log FILE we get from DEBUG...FATAL
14:21:52.149| DEBUG | ServiceA | logging debug 14:21:52.149| INFO | ServiceA | logging info 14:21:52.150| WARN | ServiceA | logging warn 14:21:52.150| ERROR | ServiceA | logging error 14:21:52.150| FATAL | ServiceA | logging fatal
Now on the logger to STDOUT change name from com.bext.Scheduler to com.bext, we get
<Loggers> <Logger name="com.bext" level="TRACE" > <AppenderRef ref="STDOUT"/> </Logger> <Logger name="com.bext.ServiceA" level="DEBUG" > <AppenderRef ref="File"/> </Logger> <Root level="ERROR">
<!-- <AppenderRef ref="STDOUT"/> -->
<!-- <AppenderRef ref="File"/> -->
</Root>
</Loggers>
So we get on STDOUT all the classes down to com.bext, mean Scheduler, and ServiceA
13:15:27.508 |TRACE | Scheduler | Scheduler [...
13:15:27.510 |DEBUG | Scheduler | Scheduler logging debug
13:15:27.510 |INFO | Scheduler | Scheduler logging info
13:15:27.510 |WARN | Scheduler | Scheduler logging warn
13:15:27.510 |ERROR | Scheduler | Scheduler logging error
13:15:27.511 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, DEBUG
ServiceA Trace is Disabled
13:15:27.511 |DEBUG | ServiceA | logging debug
13:15:27.511 |INFO | ServiceA | logging info
13:15:27.511 |WARN | ServiceA | logging warn
13:15:27.511 |ERROR | ServiceA | logging error
13:15:27.512 |FATAL | ServiceA | logging fatal
13:15:27.512 |TRACE | Scheduler | Scheduler ...]
What happen when integrate the STDOUT logger to root logger
<Loggers>
<Logger name="com.bext.Scheduler" level="TRACE" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" level="DEBUG" >
<AppenderRef ref="File"/>
</Logger>
<Root level="ERROR">
<AppenderRef ref="STDOUT"/>
<!-- <AppenderRef ref="File"/> -->
} </Root>
</Loggers>
STDOUT Log
logger.getName(), getLevel() = com.bext.Scheduler, TRACE
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
13:26:57.014 |TRACE | Scheduler | Scheduler [...
13:26:57.014 |TRACE | Scheduler | Scheduler [...
13:26:57.016 |DEBUG | Scheduler | Scheduler logging debug
13:26:57.016 |DEBUG | Scheduler | Scheduler logging debug
13:26:57.016 |INFO | Scheduler | Scheduler logging info
13:26:57.016 |INFO | Scheduler | Scheduler logging info
13:26:57.016 |WARN | Scheduler | Scheduler logging warn
13:26:57.016 |WARN | Scheduler | Scheduler logging warn
13:26:57.016 |ERROR | Scheduler | Scheduler logging error
13:26:57.016 |ERROR | Scheduler | Scheduler logging error
13:26:57.016 |FATAL | Scheduler | Scheduler logging fatal
13:26:57.016 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, DEBUG
ServiceA Trace is Disabled
13:26:57.017 |DEBUG | ServiceA | logging debug
13:26:57.017 |INFO | ServiceA | logging info
13:26:57.017 |WARN | ServiceA | logging warn
13:26:57.017 |ERROR | ServiceA | logging error
13:26:57.017 |FATAL | ServiceA | logging fatal
13:26:57.018 |TRACE | Scheduler | Scheduler ...]
13:26:57.018 |TRACE | Scheduler | Scheduler ...]
By some reason also we get the ServiceA logs. and also is repeated the info of com.bext.Schedule logger, it can be corrected with additivity="false"
<Loggers>
<Logger name="com.bext.Scheduler" level="TRACE" additivity="false" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" level="DEBUG" >
<AppenderRef ref="File"/>
</Logger>
<Root level="ERROR">
<AppenderRef ref="STDOUT"/>
<!-- <AppenderRef ref="File"/> -->
</Root>
</Loggers>
STDOUT log, the repeated info of Scheduler has gone.
logger.getName(), getLevel() = com.bext.Scheduler, TRACE
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
13:31:12.049 |TRACE | Scheduler | Scheduler [...
13:31:12.052 |DEBUG | Scheduler | Scheduler logging debug
13:31:12.052 |INFO | Scheduler | Scheduler logging info
13:31:12.052 |WARN | Scheduler | Scheduler logging warn
13:31:12.052 |ERROR | Scheduler | Scheduler logging error
13:31:12.052 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, DEBUG
ServiceA Trace is Disabled
13:31:12.053 |DEBUG | ServiceA | logging debug
13:31:12.053 |INFO | ServiceA | logging info
13:31:12.054 |WARN | ServiceA | logging warn
13:31:12.054 |ERROR | ServiceA | logging error
13:31:12.054 |FATAL | ServiceA | logging fatal
13:31:12.054 |TRACE | Scheduler | Scheduler ...]
Adding File to root logger
<Loggers>
<Logger name="com.bext.Scheduler" level="TRACE" additivity="false" >
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.ServiceA" level="DEBUG" >
<AppenderRef ref="File"/>
</Logger>
<Root level="ERROR">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
STDOUT log, same
logger.getName(), getLevel() = com.bext.Scheduler, TRACE
loggerContext.getName(): Default
Congifuration.toString(): XmlConfiguration[location=D:\proy\junit5Log4j\target\classes\log4j2.xml]
13:33:05.933 |TRACE | Scheduler | Scheduler [...
13:33:05.935 |DEBUG | Scheduler | Scheduler logging debug
13:33:05.935 |INFO | Scheduler | Scheduler logging info
13:33:05.935 |WARN | Scheduler | Scheduler logging warn
13:33:05.935 |ERROR | Scheduler | Scheduler logging error
13:33:05.935 |FATAL | Scheduler | Scheduler logging fatal
logger.getName(), getLevel() = com.bext.ServiceA, DEBUG
ServiceA Trace is Disabled
13:33:05.936 |DEBUG | ServiceA | logging debug
13:33:05.936 |INFO | ServiceA | logging info
13:33:05.936 |WARN | ServiceA | logging warn
13:33:05.936 |ERROR | ServiceA | logging error
13:33:05.937 |FATAL | ServiceA | logging fatal
13:33:05.937 |TRACE | Scheduler | Scheduler ...]
FILE log, just ServiceA and repeated, could be corrected with additivity="false"
13:33:05.936| DEBUG | ServiceA | logging debug 13:33:05.936| DEBUG | ServiceA | logging debug 13:33:05.936| INFO | ServiceA | logging info 13:33:05.936| INFO | ServiceA | logging info 13:33:05.936| WARN | ServiceA | logging warn 13:33:05.936| WARN | ServiceA | logging warn 13:33:05.936| ERROR | ServiceA | logging error 13:33:05.936| ERROR | ServiceA | logging error 13:33:05.937| FATAL | ServiceA | logging fatal 13:33:05.937| FATAL | ServiceA | logging fatal
Create a Rolling File
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR" strict="true" name="XMLConfigTest"
packages="">
<Properties>
<Property name="filename">target/test.log</Property>
<Property name="rollingfilename">target/logs/app.log</Property>
</Properties>
<!-- <Filter type="ThresholdFilter" level="ERROR"/> -->
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%d{HH:mm:ss.SSS} |%-5p | %-15c{1} | %m%n"/>
</Appender>
<Appender type="File" name="File" fileName="${filename}" append="false">
<Layout type="PatternLayout">
<Pattern>%d{HH:mm:ss.SSS}| %-5p | %-15c{1} | %m%n</Pattern>
</Layout>
</Appender>
<RollingFile name="RollingFile" fileName="${rollingfilename}"
filePattern="target/logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<Policies>
<!-- <OnStartupTriggeringPolicy/> -->
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="1KB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.bext.Scheduler" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT"/>
</Logger>
<Logger name="com.bext.Scheduler" level="TRACE" additivity="false">
<AppenderRef ref="RollingFile"/>
</Logger>
<Logger name="com.bext.ServiceA" level="DEBUG" additivity="false">
<AppenderRef ref="File"/>
</Logger>
<Root level="ERROR">
<!-- <AppenderRef ref="STDOUT"/> -->
</Root>
</Loggers>
</Configuration>
File structure generated after tree runs.
eot
No hay comentarios:
Publicar un comentario