Giter VIP home page Giter VIP logo

Comments (15)

dereknheiley avatar dereknheiley commented on May 31, 2024 3

Aha #2, removing the exclusion we tried adding for one of the above problems finally fixed it.
So in summary, import the library before other log4j dependencies.

image

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024 1

Hi Derek,

Thank you for this detailed issue report! This is a typical SLF4J error message that is preventing to have more than one slf4j binding to be present at the classpath.

The log4j-to-slf4j dependency within this library makes it possible to capture logs from apache when the end user is using apache log4j-core while not using slf4j api/slf4j bridge/slf4j binder at all. This makes it convenient for those end-users to start without the need for additional configuration. Even if this library didn't included log4j-to-slf4j you would still have a similar error. You can try it by excluding the specific library with the following snippet:

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>logcaptor</artifactId>
    <version>2.3.2</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

The main reason why this is happening is that your classpath already has a slf4j implementation and LogCaptor too. This is also mentioned here LogCaptor - Using Log Captor alongside with other logging libraries. So what you need to do is just exclude your slf4j implementation during the test phase. If you are using maven surefire or failsafe plugin you can add the following snippet to your pom:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>

This configuration is excluding your log4j-slf4j-impl during the test-phase only. Can you give it a try and share your results here? I think excluding log4j-to-slf4j from LogCaptor would not be needed.

I'm not sure if i'm applying the pom exclusions properly, but it seems like it might be easier to make a version that is compatible with org.apache.logging.log4j instead

I need to think about it. Thank you for the suggestion!

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024 1

Amazing, you found the solution. Interesting to see that the order of declaring the dependency in this specific use-case worked for you! I will note this solution down. Good luck asserting your log messages!

By the way I published here Java tutorials - LogCaptor isolated examples with different logging frameworks include this example and the adjustments to the pom which are included to get it working.

Update 14-07-2021
I noticed that you are using spring-boot-starter-log4j2. This library has some transitive dependencies which indeed requires adjustments to your pom. I have added an example for this use case, see the example project here: https://github.com/Hakky54/java-tutorials/tree/main/log-captor-examples/log-captor-with-spring-boot-starter-log4j2

So you basically need to add the following configuration to your pom:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <configuration>
                <classpathDependencyExcludes>
                    <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
                </classpathDependencyExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>

This will exclude org.apache.logging.log4j:log4j-slf4j-impl from the classpath only during the test phase
I mentioned this solution also at the beginning of our conversation, see here: #6 (comment)

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

The maven plugin changes don't seem to have any effect so far.

But changing to exclude log4j-to-slf4j on your dependency gets me past the first error i was running into and gets me a little further to a casting exception:

java.lang.ClassCastException: class org.apache.logging.slf4j.Log4jLogger cannot be cast to class ch.qos.logback.classic.Logger (org.apache.logging.slf4j.Log4jLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app')
	at nl.altindag.log.LogCaptor.<init>(LogCaptor.java:49)
	at nl.altindag.log.LogCaptor.forClass(LogCaptor.java:69)
	at ....AddressTest.testAddressValidation(AddressTest.java:20)

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024

That is strange. It should have worked. Could you create a basic sample project on your GitHub repo so I can analyse your setup? In that way it would be much easier to reproduce it on my environment.

By the way I just tried it with a fresh new project to reproduce the same behaviour as wat you had. See here for the example project: GitHub - LogCaptor With Apache Log4j

This project contains:

  • log4j-slf4j-impl
  • LogCaptor
  • JUnit
  • AssertJ

And has the following plugin configuration:

  • maven-compiler-plugin with java 11
  • maven-surefire-plugin with classpath dependency exclusion during the test phase for org.apache.logging.log4j:log4j-slf4j-impl

With this setup it works as expected. The logs will be captured and I can assert those messages. It is also not needed to exclude log4j-to-slf4j from logcaptor. Can you compare this setup with yours and share any difference or create a sample project which has the errors which you mentioned? That would make it much easier to analyse the root cause.

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

Thanks for your help, the conflict must be some where in the larger project. I just don't understand how that would manifest inside LogCaptor. I'll try and trim down something i can share.

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

since i'm still seeing this warning in the terminal, i'm guessing my issue is that something is still trying to use
org.apache.logging.slf4j.Log4jLogger instead of ch.qos.logback.classic.Logger. The stack trace message (org.apache.logging.slf4j.Log4jLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app') just doesn't help narrow that down at all.

SLF4J: Found binding in [jar:file:/home/derek/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.13.3/log4j-slf4j-impl-2.13.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/derek/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

This change to the existing POM file in the project seems to have yielded a passing test, pending further integration testing.
image

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024

Thank you for sharing the details, I think the log4j-slf4j-impl is a transitive dependency so it could be indeed getting it from somewhere from any other dependency. You can track it down with the following command: mvn dependency:tree

Your issue with the logcaptor library is that log4j-slf4j-impl dependency is somehow still present at the classpath during the test phase. I still think you don't need to exclude log4j-to-slf4j and logback-classic from logcaptor. We can also do some remote session through Ringcentral, Teamviewer, Discord or something else. In that way I might be able to help you a bit more. Let me know if your ok with that to go through it together

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

My thinking was that excluding them from a test dependency in favour of an explicit dependency to replace the explicit dependency of log4j2 that was removed.

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024

Thats sounds reasonable but your application is still using org.apache.logging.log4j.LogManager class in your code base. So excluding the apache logger library will prevent your project from compiling. So you are forced to add the library log4j-slf4j-impl but if you also include logback-classic library as you have shown in one of your previous messages you will get the same error which you got in your test when you will try to start your application.

I think your initial setup was good. I am assuming you only had log4j-slf4j-impl and I think it should stay like that.

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024

Can you by the way share your pom configuration of the part which is running the unit tests? What are you using as a maven plugin to execute the unit tests?

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

Thank you for sharing the details, I think the log4j-slf4j-impl is a transitive dependency so it could be indeed getting it from somewhere from any other dependency. You can track it down with the following command: mvn dependency:tree

Your issue with the logcaptor library is that log4j-slf4j-impl dependency is somehow still present at the classpath during the test phase.

[INFO] +- org.springframework.boot:spring-boot-starter-log4j2:jar:2.3.1.RELEASE:compile
[INFO] |  +- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.13.3:compile
[INFO] |  |  \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile

Well the existing spring-boot-starter-log4j2 is where log4j-slf4j-impl is coming from. I can't seem to balance keeping that import so the production app isn't changed, and preventing further errors like i posted above with

java.lang.ClassCastException: class org.apache.logging.slf4j.Log4jLogger cannot be cast to class ch.qos.logback.classic.Logger (org.apache.logging.slf4j.Log4jLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app')
	at nl.altindag.log.LogCaptor.<init>(LogCaptor.java:49)
	at nl.altindag.log.LogCaptor.forClass(LogCaptor.java:69)
	at ....AddressTest.testAddressValidation(AddressTest.java:20)

from log-captor.

Hakky54 avatar Hakky54 commented on May 31, 2024

Aha, good to know which dependency is including log4j-slf4j-impl. So in the end it is still similar to the example project which I have created last week.

By the way. I am assuming you are using junit or any other framework for your tests. Do you know which maven plugin you are using to execute those tests? Most of the time surefire and failsafe maven plugins are used, so I am curious what you are using in your project.

from log-captor.

dereknheiley avatar dereknheiley commented on May 31, 2024

Running tests from Eclipse JUnit test runner plugin, and from the command line using maven surefire.

Good news, moving the LogCaptor dependency before spring-boot-starter-log4j2 seems to fix the error where org/slf4j/impl/StaticLoggerBinder.class was being selected instead of org/slf4j/impl/StaticLoggerBinder.class

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/derek/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/derek/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.13.3/log4j-slf4j-impl-2.13.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
�[1;31mERROR�[m 2021-02-04 18:55:42 ..dat.mod.Address            --- Address is malformed.

But LogCaptor doesn't show any results now. I almost have a pruned down project to upload.

org.opentest4j.AssertionFailedError: Could not find expected error message in LogCapture ==> expected: <false> but was: <true>
	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
	at org.junit.jupiter.api.AssertFalse.assertFalse(AssertFalse.java:40)
	at org.junit.jupiter.api.Assertions.assertFalse(Assertions.java:218)
	at test.providius.datahub.AddressTest.testAddressValidation(AddressTest.java:30)

from log-captor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.