I would like to print all INFO logs to my console, but only send ERROR logs to my Airbrake appender.
My log4j2 has a root logger that adds the ConsoleAppender and is set to log level INFO.
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleAppender"/>
</Root>
</Loggers>
I then create a logger by the name of my application com.acme.app
Logger logger = LogManager.getLogger("com.acme.app");
logger.info("This is an info log");
logger.error("This is an error log");
With this configuration, when I run my application I will get the output
2019-06-10 12:20:48 [main] INFO ... - This is an info log
2019-06-10 12:20:48 [main] ERROR ... - This is an error log
I now want to add the airbrake appender and only send ERROR logs to airbrake, but I want to continue printing both INFO and ERROR logs.
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleAppender"/>
</Root>
<Logger name="com.acme.app" level="ERROR">
<AppenderRef ref="Airbrake"/>
</Logger>
</Loggers>
This will start sending ERROR logs to my airbrake, but now I will only see ERROR logs in the console.
If I set the level to INFO or move the appender to the root, I will see both INFO and ERROR logs, but I will also be sending INFO logs to airbrake- which is undesirable.
I've also tried adding multiple levels for the same logger name and explicitly point INFO back to the console-
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleAppender"/>
</Root>
<Logger name="com.acme.app" level="ERROR">
<AppenderRef ref="Airbrake"/>
</Logger>
<Logger name="com.acme.app" level="INFO">
<AppenderRef ref="ConsoleAppender"/>
</Logger>
</Loggers>
I tried both ERROR first and INFO first and it appears whichever is the last defined is what's used. If INFO comes last it will print all of the logs but not sending any errors, if ERROR comes last it will send the error but not print any of the INFO logs.
How can I have Airbrake capture all of the ERROR logs, but allow other logs to fallback to the root logger without sending all logs to the Airbrake appender?
Related
I have a method foo which is called inside a loop over a list of objects.
class Bar{
private static final Logger logger = LoggerFactory.getLogger(Bar.class);
void foo(A obj){
//bunch of debug logs
logger.debug("A");
logger.debug("B");
//..and so on
//processing functionality
}
}
Now, whenever the object is processed successfully, the debug logs are printed in the log file. But if an object throws an error while processing, the debug logs are not getting printed.
I am using log4j2 and my log4j.xml file is below:
<Configuration monitorInterval="60" status="WARN">
<Loggers>
<Logger name="com.abc" level="INFO"/>
</Loggers>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console"/>
<AppenderRef ref="asyncFileLogger"/>
</Root>
</Loggers>
</Configuration>
What could be the issue behind this?
This question already has answers here:
Spring Boot Unit Test ignores logging.level
(6 answers)
Closed 5 years ago.
My Spring Boot testing stack is Maven + Surefire + JUnit4. I am annotating the tests with #RunWith(SpringJUnit4ClassRunner.class).
I have application.properties in my project root with this line:
logging.level.root=INFO
This controls the logging when running the Spring boot app and it works on normal runs.
However, whenever I run any JUnit4 tests, I am spammed by pages of DEBUG output like this:
....
17:43:20.500 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'autoConfigurationReport'
17:43:20.500 [main] DEBUG org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader - Registered bean definition for imported class 'org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration'
17:43:20.501 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.boot.autoconfigure.condition.BeanTypeRegistry'
17:43:20.502 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'autoConfigurationReport'
....
All this spam makes it almost impossible to see the actually relevant parts. How can I apply the logging levels to test output?
I haven't set any logging explicitly, and according to the docs Logback is used by default.
From a general perspective, you can provide a seperate logback-test.xml-file at the test-resource level. In this file you can add settings regarding the log-level targeted at the output you'd like such as:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</layout>
</appender>
<logger name="com.your.package" level="DEBUG">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.springframework" level="WARN">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.hibernate" level="WARN">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.eclipse" level="WARN">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="jndi" level="WARN">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.apache.http.wire" level="WARN">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Hope this helps you somewhat on the path to decreasing the log output. More is documented at logback's own page:
https://logback.qos.ch/manual/configuration.html
Its mentioned in the top section:
Let us begin by discussing the initialization steps that logback follows to try to configure itself:
1.Logback tries to find a file called logback-test.xml in the classpath.
2.If no such file is found, logback tries to find a file called logback.groovy in the classpath.
3.If no such file is found, it checks for the file logback.xml in the classpath..
4.If no such file is found, service-provider loading facility (introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Configurator interface by looking up the file META-INF\services\ch.qos.logback.classic.spi.Configurator in the class path. Its contents should specify the fully qualified class name of the desired Configurator implementation.
5.If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.
I'm trying to configure logback to print:
- everything (level trace or debug) to the screen
- everything (level trace or debug) to the debugfile
- warnings and above to an error file
My logback.xml config is like this:
...
<logger name="be" level="TRACE">
<appender-ref ref="FILE-AUDIT" />
<appender-ref ref="STDOUT" />
</logger>
<root level="WARN">
<appender-ref ref="FILE-ERROR" />
</root>
However, the error and debug file contain exactly the same, being ALL logging (debug and error). I've already tried to play with the additivity option, but that's apparently not what I need.
The second question is that I use name "be" to have all classes under be.* but actually I want to capture everything there (com.* as well).
Found a solution by adding a filter to the appender:
<appender name="FILE-ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- deny all events with a level below WARNING -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
In simple terms what is the result of making additivity="true" or additivity="false" when adding a Log4j configuration for a specific class like this?
<Logger name="com.mypage.glass.TryWindow" level="INFO" additivity="true">
<AppenderRef ref="console"/>
<AppenderRef ref="file"/>
</Logger>
By default, a logger inherits the appenders from its ancestors. By setting additivity="false", you prevent this behaviour.
In your example, there may be appenders associated with com.mypage.glass or com.mypage or even the root logger that would be inherited if you don't set that property to false.
I recognized some problems with the SMTPAppender in log4j2. Whenever log events with the level error or fatal are created without having an event with the level info before no mail is sent and the fatal event disappears.
Here is my log4j2 configuration file (log4j2.xml) and a small program (LogTest.java) to reproduce the problem:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="warn">
<!-- mail server configuration -->
<properties>
<property name="receipients">me#example.com</property>
<property name="from">me#example.com</property>
<property name="smtpHost">smtp.example.com</property>
<property name="smtpPort">25</property>
<property name="smtpProtocol">smtp</property>
<property name="smtpUser">me</property>
<property name="smtpPassword">secret</property>
</properties>
<appenders>
<!-- appender to write all info events to stdout -->
<Console name="Console" target="SYSTEM_OUT">
<ThresholdFilter level="info" onMatch="NEUTRAL" onMismatch="DENY"/>
</Console>
<!-- appender to send mails (default: error and fatal events)-->
<SMTP name="Mailer" suppressExceptions="false"
subject="Error log" to="${receipients}" from="${from}"
smtpHost="${smtpHost}" smtpPort="${smtpPort}"
smtpProtocol="${smtpProtocol}" smtpUsername="${smtpUser}"
smtpPassword="${smtpPassword}" smtpDebug="false" bufferSize="2">
</SMTP>
<!-- appender to send mails asynchronously -->
<Async name="AsyncMailer" >
<appender-ref ref="Mailer"/>
</Async>
</appenders>
<loggers>
<!-- logger to send mail on (at least) info level events -->
<logger name="LogTest" level="info" additivity="true">
<appender-ref ref="AsyncMailer"/>
</logger>
<!-- root logger to see what happens (info level and "above") -->
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
I used this small program to reproduce the problem (LogTest.java):
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
class LogTest
{
private static Logger logger=LogManager.getLogger("LogTest");
public void testlogger()
{
/* --> uncomment to enable first mail
logger.info("test info 1");
*/
logger.fatal("test fatal 1");
/* --> uncomment to enable second mail
logger.info("test info 2");
*/
logger.fatal("test fatal 2");
}
public static void main(String[] args)
{
LogTest app=new LogTest();
app.testlogger();
}
}
If you uncomment the two marked positions everything work like intended: two mails are sent - each containing the fatal-event and the prior info event. Additionally the 4 events are printed to stdout:
test info 1
test fatal 1
test info 2
test fatal 2
Now, if you only activate/uncomment the second position - the second mail (fatal2) is sent as intended (again with the prior info2 event), but even though the first fatal event is printed to stdout the mail is eaten up. The output looks as follows:
test fatal 1
test info 2
test fatal 2
Personally, for me it seems like I got something wrong and mis-configured log4j2 or it might be a bug.
Thanks for your help in advance.
*Jost
Note:
For the tests I used log4j2-beta7 downloaded from the project's website.
The documentation can be found here.
At first glance this looks like a bug. Does it still happen if you remove the LogTest logger and configure your root logger like this?
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="AsyncMailer"/>
</root>
FYI, if later you need different log levels on the different appenders you can achieve that like this (no need for a separate logger):
<root level="trace">
<appender-ref ref="A" level="info" />
<appender-ref ref="B" level="debug" />
</root>