Log4j2 Define 2 root loggers with different levels - java

I have 2 appenders I'm using - Console and custom appender called MyAppender which should ignore all messages with levels lower than ERROR (meaning - it should only support ERROR and FATAL). The Console should be able to support all levels.
I've tried several ways to define it but it seems that the filter doesn't work for the root level appenders. How can this be achieved? My current log4j2 definition:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.mysample.logging.appenders" status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<MyAppender name="MyAppender">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
</MyAppender>
</Appenders>
<Loggers>
<Root level="ALL">
<AppenderRef ref="Console"/>
<AppenderRef ref="MyAppender" />
</Root>
</Loggers>
</Configuration>

The loggers are one hierarchy starting with the root logger.
There are no two root loggers within one working setup of Log4j.
What you want to achieve is to have different thresholds on the appenders. Check the link that Piotr suggested:
Using log4j2, is it possible to assign a specific level to a appender?

Related

log4j2 logger config level does not override root logger level

According to log4j documentation, if I define a logger config for package com.a.b.c with level ERROR with root logger level set to DEBUG, only ERROR logs should come from classes in com.a.b.c while other classes should print DEBUG logs. Therefore I have the below log4j2-test.xml.
However, in my case INFO level logs from classes in com.a.b.c are still being printed. Did I misunderstand anything? What should I do to make classes in com.a.b.c print ERROR logs while all other classes print INFO logs?
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" name="PropertiesConfig" packages="org.apache.logging.log4j.test">
<Properties>
<Property name="basePath">target/</Property>
</Properties>
<ThresholdFilter level="trace"/>
<Appenders>
<Console name="consoleLogger" target="SYSTEM_OUT">
<PatternLayout pattern="%d{dd-MM-yyyy HH:mm:ss.SSS} %style{[%t]}{magenta} %highlight{%-5level}{TRACE=cyan, DEBUG=green, INFO=yellow, WARN=blue, ERROR=red} [%-60.60c] : %m%n" />
</Console>
<File name="fileLogger" fileName="${basePath}app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] [%c] [%M] [%l] : %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="INFO" >
<AppenderRef ref="consoleLogger" />
<AppenderRef ref="fileLogger" />
</Root>
<Logger name="com.a.b.c" level="ERROR" additivity="false">
<AppenderRef ref="consoleLogger" />
<AppenderRef ref="fileLogger" />
</Logger>
</Loggers>
</Configuration>
I figured this out. The class in question is (weirdly) not using its own class name when getting the logger. Typically it is LoggerFactory.getLogger(com.a.b.c) but in my case the class is doing LoggerFactory.getLogger(java.io.Console), thus our logger config <Logger name="com.a.b.c" level="ERROR" additivity="false"> will not apply to logs coming from this class. I had to add a logger config for the class java.io.Console.

In Log4j2, how to append same class logs of different priority levels in different files?

These are my appender files-
<Appenders>
<File name="FirstLogToFile" fileName="logs/first.log">
<PatternLayout>
<Pattern>%r %d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<File name="SecondLogToFile" fileName="logs/second.log">
<PatternLayout>
<Pattern>%r %d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
</Appenders>
And these are my logger files-
<Logger name="com.company.gaurav.Log" level="Fatal" additivity="true">
<AppenderRef ref="FirstLogToFile"/>
</Logger>
<Logger name="com.company.gaurav.Log" level="trace" additivity="true">
<AppenderRef ref="SecondLogToFile"/>
</Logger>
I can't append to FirstLogToFile, only SecondLogToFile.
The other workaround is to create a Root parent logger without any individual child logger, and that works. Can anyone please explain why this is not working.
You cannot have two Loggers with the same name. D.B.'s answer is correct although a bit complicated for your question. I would only use the RoutingAppender if you need dynamic flexibility. If you know your appenders ahead of time it is preferable to configure them.
Also, you can put filters at various levels. D.B.'s linked answer filters at the appender, which is appropriate if you want specific output regardless of the logger. The way you worded your question though I would add the LevelRangeFilter to the Appender reference like this
<Logger name="com.company.gaurav.Log" level="trace" additivity="true">
<AppenderRef ref="FirstLogToFile">
<LevelRangeFilter minLevel="FATAL" maxLevel="FATAL" onMatch="ACCEPT" onMismatch="DENY"/>
</AppenderRef>
<AppenderRef ref="SecondLogToFile"/>
</Logger>
I should also point out that I am not sure this will do what you really want. With this configuration the FirstLogToFile appender will get only fatal error messages while SecondLogToFile will get all log events. But that configuration seems to match what you showed in your example.

In Log4j2, Is it possible to filter out certain key value pairs from the logger based on the key?

Can Log4j2 be configured in such a way that the filters or some other components can filter out certain values from getting printed in the log? (but should allow other fields in the same line to pass through)
Say the following lines appear in the log
[operation=DONE, userName=junitUser, tenant=Tenant [tenantID=default], needDetails=1, message=BaseMsg [version=1.0, sdk=AppSDK [version=1.3, protocols=[4aac81ca, 393ae7a0]], device=Device [id=12345, type=Pompom, info=Dot's Device]]], channel=null
[operation=DONE, userName=junitUser224, tenant=Tenant [tenantID=default], needDetails=1, message=BaseMsg [version=1.0, sdk=AppSDK [version=1.3, protocols=[4aac81ca,393ae7a0]], device=Device [id=123456, type=Mamamia, info=tom's Device]]], channel=null
Now can I filter out the "userName" field in such a way that the log lines now do not contain it as shown below?
[operation=DONE, tenant=Tenant [tenantID=default], needDetails=1, message=BaseMsg [version=1.0, sdk=AppSDK [version=1.3, protocols=[4aac81ca, 393ae7a0]], device=Device [id=12345, type=Pompom, info=Dot's Device]]], channel=null
[operation=DONE, tenant=Tenant [tenantID=default], needDetails=1, message=BaseMsg [version=1.0, sdk=AppSDK [version=1.3, protocols=[4aac81ca,393ae7a0]], device=Device [id=123456, type=Mamamia, info=tom's Device]]], channel=null
Here is my log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingFile name="RollingFile" fileName="/Users/dunston/logs/app.log"
filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
<RegexFilter regex=".* zinger_log .*" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
This can be accomplished with a RewriteAppender.
You may need to write a custom RewritePolicy that inspects the LogEvent's Message and replaces the Message with another instance if the formatted message contains a regular expression that you want to filter out.
Your custom RewitePolicy can be configured in the configuration like any other standard Log4j2 plugin.

log4j 2: log file being created, but not being written to

I am using log4j 2. I am trying to determine why my log file is not being written to, but my console is. This is the output I have to the console:
2016-04-25 12:26:07,142 INFO [main] helperCode.LogPlus (LogPlus.java:50) -
----------------------------------------------------------------------------
------------ The test is starting now at 2016-04-25-12-26-07-135 -----------
----------------------------------------------------------------------------
2016-04-25 12:26:07,151 INFO [main] helperCode.LogPlus (LogPlus.java:50) -
--------------------------------------------------------------------------
------------ METHOD loginBadPasswordGoodUsername_3 starting: ------------
--------------------------------------------------------------------------
The issues I've considered already:
The output is not repeating itself, so the log output being redirected is not an issue.
I am NOT using java.util.logging.Logger anywhere in my project;
The output of the log file is formatted in log4j style rather than JUL style, so I know that JUL is not overriding it;
Here is my XML config file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="FileLogger" fileName="${sys:logFilePath}" append="false">
<PatternLayout pattern="%d %t %-5p %c{2} - %m%n" />
</File>
<Async name="Async">
<AppenderRef ref="FileLogger" />
</Async>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="automationFramework" level="trace">
<AppenderRef ref="FileLogger" />
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
I am directing the output to the file located at the system variable "logFilePath".
I am not sure what is going on, and the config files shown on answers for similar questions are not in XML format, so I am not sure how to commute the config file code to XML.
In your case as mentioned in the comment you do not have the package called applicatiionFramework. So change the name attribute by the package name of the classes where you want to record log events.
<Logger name="your package" level="trace">
<AppenderRef ref="FileLogger" />
<Root level="trace">
<AppenderRef ref="STDOUT" />
</Root>
</Logger>
For more information visit log4j-manual-configuration
Glad the other answer helped. Do you need the named logger though? Why not just have the root logger? Also, you declared an Async Appender but are not using it. Is that on purpose? This is what I would suggest:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="FileLogger" fileName="${sys:logFilePath}" append="false">
<PatternLayout pattern="%d %t %-5p %c{2} - %m%n" />
</File>
<Async name="Async">
<AppenderRef ref="FileLogger" />
</Async>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="STDOUT" level="info" />
<AppenderRef ref="Async" />
</Root>
</Loggers>
</Configuration>
Note that you can also specify a level on the AppenderRef. I made the Console Appender level INFO to illustrate this point.
If you want the log to show location information and use Async loggers or appenders then you need to specify includeLocation="true" on the Async Appender.
For the complete noob, like myself, this line in Unknown's answer above:
<Logger name="your package" level="trace">
is the key. When it says "your package" it really means the "package foo.bar" you declared at the top of the .java file where you created the Logger, not the class name you passed to create the Logger, like:
LOGGER = LogManager.getLogger(MyClass.class.getName());
It took me a ridiculous amount of time today to get my log4j2 output going to a file, playing with various "name" values until the light bulb went on.

Disabling Log4J Output in Java

How can one quickly turn off all Log4J output using a log4j.properties file?
Set level to OFF
(instead of DEBUG, INFO, ....)
If you want to turn off logging programmatically then use
List<Logger> loggers = Collections.<Logger>list(LogManager.getCurrentLoggers());
loggers.add(LogManager.getRootLogger());
for ( Logger logger : loggers ) {
logger.setLevel(Level.OFF);
}
log4j.rootLogger=OFF
You can change the level to OFF which should get rid of all logging. According to the log4j website, valid levels in order of importance are TRACE, DEBUG, INFO, WARN, ERROR, FATAL. There is one undocumented level called OFF which is a higher level than FATAL, and turns off all logging.
You can also create an extra root logger to log nothing (level OFF), so that you can switch root loggers easily. Here's a post to get you started on that.
You might also want to read the Log4J FAQ, because I think turning off all logging may not help. It will certainly not speed up your app that much, because logging code is executed anyway, up to the point where log4j decides that it doesn't need to log this entry.
In addition, it is also possible to turn logging off programmatically:
Logger.getRootLogger().setLevel(Level.OFF);
Or
Logger.getRootLogger().removeAllAppenders();
Logger.getRootLogger().addAppender(new NullAppender());
These use imports:
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.NullAppender;
Change level to what you want. (I am using Log4j2, version 2.6.2). This is simplest way, change to <Root level="off">
For example: File log4j2.xml
Development environment
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<Console name="SimpleConsole" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
<Loggers>
<Root level="info">
<AppenderRef ref="SimpleConsole"/>
</Root>
</Loggers>
</Configuration>
Production environment
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<Console name="SimpleConsole" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="off">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
<Loggers>
<Root level="off">
<AppenderRef ref="SimpleConsole"/>
</Root>
</Loggers>
</Configuration>

Categories