log-captor
log-captor copied to clipboard
Not compatible with log4j2 2.17.2
Describe the bug It's not compatible with log4j2 2.17.2. It happen after log4j2 broke compatibility with slf4j binding.
To Reproduce
- Migrate to log4j2 2.17.2
- Exception at Junit5 testing: java.lang.ExceptionInInitializerError Caused by: java.lang.ClassCastException: org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext
Expected behavior No exception
Screenshots If applicable, add screenshots to help explain your problem.
Environmental Data:
- Java Version: 8
- Maven Version
- OS (Windows/Linux/MacOS): wsl(Ubuntu)
Additional context Log4j2 supplied with new sfl4j adapter to fix compatibility issue: log4j-slf4j-impl and log4j-slf4j18-impl, but replacing log4j-to-slf4j adapter with them didn't work.
Hello @lvm-5
Thank you for reaching out to me with this issue and giving a detailed explanation. I was able to reproduce the same exception and the root cause is log4j-slf4j18-impl
uses an older version of SLF4J. It uses version 1.8.0-beta4, which was released in 2019. That version used a different way of setting up the logger and therefor it fails using LogCaptor. I would recommend to configure your pom differently by excluding slf4j-api from log4j-slf4j18-impl. In that way there will be only one transitive dependency from slf4j-api coming from logcaptor. Can you try the following setup:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
<version>${version.log4j-log4j-slf4j18}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
I also have an example project/demo for this use case here: Unit testing Log4J logs with LogCaptor while using log4j-slf4j18-impl
Can you please retry with these additional configuration and share your results?
Hello @Hakky54,
I've added dependency as you suggested, but it didn't solve the issue. Pay your attention logcaptor still use log4j-to-slf4j dependency:
It is strange that the same error is still occuring. In the reference project it is working, so i would be expecting the same for your case. But maybe i missed something.
Would it be possible for you to create a very minimalistic GitHub repo demonstrating the issue what you have. In that way i can easily debug your issue while having your setup.
Hi @lvm-5
Sorry for my late reply. I was at holiday and today I came back and got a better chance to analyse the situation.
In my earlier example I have used the log4j-slf4j18-impl
incorrectly so the solution which I gave was not good enough. Using LogCaptor alongside with log4j-slf4j18-impl
is troublesome as it redirects SLF4J logs to Log4J because of the SLF4J implementation which is shipped alongside with log4j-slf4j18-impl
. LogCaptor uses Logback to to capture the logs, however using LogCaptor with log4j-slf4j18-impl
will not work as it will have 2 SLF4J implementations on the classpath. Excluding one or the other will break the functionality of either logging or capturing logs. This issue cannot be resolved in my opinion with Logcaptor. For this special kind of use cases I have introduced some time ago ConsoleCaptor which has limited features compared to LogCaptor but you will be able to test your logs, log level etc. ConsoleCaptor can capture console output and it will return a list. You just need to make sure that your logs are appended to the console during your tests.
What you need to do is:
- Add ConsoleCaptor to your project:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>consolecaptor</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
2 Add log4j2.xml file to test resources:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
- Example FooService class
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FooService {
private static final Logger LOGGER = LoggerFactory.getLogger(FooService.class);
public void hello() {
LOGGER.info("Hello there friend!");
}
}
- Add your test class
import nl.altindag.console.ConsoleCaptor;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class FooServiceTest {
@Test
void sayHello() {
ConsoleCaptor consoleCaptor = new ConsoleCaptor();
FooService fooService = new FooService();
fooService.hello();
assertThat(consoleCaptor.getStandardOutput()).hasSize(1);
assertThat(consoleCaptor.getStandardOutput().get(0)).contains("Hello there friend!");
}
}
I have created an example project here which you can analyse: https://github.com/Hakky54/java-tutorials/tree/main/console-captor-examples/console-captor-with-log4j-slf4j18
Can you please give another try and share your results?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.