log-captor icon indicating copy to clipboard operation
log-captor copied to clipboard

Not compatible with log4j2 2.17.2

Open lvm-5 opened this issue 1 year ago • 4 comments

Describe the bug It's not compatible with log4j2 2.17.2. It happen after log4j2 broke compatibility with slf4j binding.

To Reproduce

  1. Migrate to log4j2 2.17.2
  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.

lvm-5 avatar Jul 04 '22 17:07 lvm-5

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?

Hakky54 avatar Jul 06 '22 10:07 Hakky54

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: image

lvm-5 avatar Jul 07 '22 07:07 lvm-5

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.

Hakky54 avatar Jul 07 '22 08:07 Hakky54

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:

  1. 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>
  1. 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!");
    }

}
  1. 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?

Hakky54 avatar Jul 26 '22 16:07 Hakky54

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.

stale[bot] avatar Aug 12 '22 18:08 stale[bot]