Comments (9)
Hi Olaf,
That error is indeed the classic error and pretty annoying, but it should be resolvable. LogCaptor is still using SLF4J v1.7.x but I am planning to bump it to v2.x.x However LogCaptor is compatible with Log4J2 and currently also tested with the latest version 2.19.0
Looking at your issue you have log4j-slf4j-impl
on your classpath. That dependency relies on SLF4J v1.7.x and is compatible with LogCaptor. Excluding log4j-slf4j-impl
from your classpath during the test phase should work as I have a working example here: https://github.com/Hakky54/java-tutorials/blob/main/log-captor-examples/log-captor-with-slf4j-log4j/pom.xml
So I have the feeling that another dependency in your project might be causing this issue. If another dependency has a transitive dependency on SLF4J v2.x.x than it will fail to captor the logs and give you indeed those warnings. Can you validate that by running a dependency tree and check which SLF4J version iss being used?
from log-captor.
Yes, and the move to SLF4J 2.x.x is deliberate... :-( I cannot get this out as my main logging library is io.github.microutils:kotlin-logging-jvm:3.0.0
They moved from API 1.7 to API 2.x - and thus I get into problems. Formerly I used uk.org.lidalia:slf4j-test:1.2.0 to test my logs in unit tests, but that one is very, very old and also cannot work with API 2.x.
To be honest, this whole world of Log4J 1, 2, API versions, implementations, bindings, etc is completely frustrating me. :-/
from log-captor.
No worries, I understand your frustration. It is awfull that there are so many logging frameworks and you are getting this issue because other dependencies which are using different versions.
My overall suggestion for your project would be to make sure you use 1 logging framework. Either SLF4J or Log4J2 and redirect all logs to that logging framework. For this you need to analyse your dependency tree. And next to that make sure you are using one specific version by excluding the transitive dependencies and by specifiying it in the dependency management section (if you are using maven). But that is something which can take some time to refactor and not needed to just get LogCaptor working.
The main reason why I didn't upgraded SLF4J for LogCaptor to version v2.x.x is because Log4j2 maintainers didn't released an adapter for it yet. They have one for SLF4J v1.7.x which I am using, see here for the dependency: https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-to-slf4j/2.19.0
There are couple of things what you can do. Either one of the options alone should work:
- Exclude SLF4J from
kotlin-logging-jvm
during the test phase. In that way LogCaptor will use SLF4J version 1.7.x I tried this in the past, but could not get it working. So I am unfortunately not able to provide you examples... - Add
ch.qos.logback:logback-classic:1.4.3
andorg.apache.logging.log4j:log4j-to-jul:2.19.0
as a test dependency. Logback is being used by LogCaptor as the engine to capture logs. This version of Logback is compatible with SLF4J v2.x.x and the log4j-to-jul will forward your own logs to java util logging which LogCaptor is able to capture regardless of the SLF4J version. In that way you don't need an adapter for Log4J2 for SLF4J v2.x.x and it should just work with the java util logging adapter.
Can you give it a try and share your results here? I am also curious which option you would prefer 😄
from log-captor.
Oh gosh... I don't even know the differences between slf4j and log4j2... this is all so, so confusing. Sorry to bother you with this...
I do use Gradle, not Maven. All I did to start my logging is to rely on kotlin-logging-jvm, which adds this transitive dependency: slf4j-api:2.0.1
When you start the application with this single dependency, you get this warning:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
Sounds reasonable, as you need to also add logging implementations, aka providers.
So I add: org.apache.logging.log4j:log4j-slf4j2-impl:2.19.0 to my dependencies.
This leads to:
ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
Ok, I do as instructed - adding org.apache.logging.log4j:log4j-core:2.19.0 to my dependencies.
We are now at:
implementation("io.github.microutils:kotlin-logging-jvm:3.0.0")
implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.19.0")
implementation("org.apache.logging.log4j:log4j-core:2.19.0")
This is the first working solution. I do not really know how I would name this. Am I using Log4J2 now? Or SLF4J? API 1.7 or 2.0.x? Of what. Here the confusion is already happening...
Now - I want to write a unit test, making sure some code part logs an error.
I now add
testImplementation("io.github.hakky54:logcaptor:2.7.10")
And now my code crashes with this:
org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
Okay, we now have a conflicting dependency, right? I have NO clue what log4j-slf4j-impl vs log4j-to-slf4j are. We do people come up with such confusing names... grrrr And where the hack is my second "2" as in log4j-slf4j2-impl??
I try to exclude one dependency at test runtime using
configurations.testRuntimeOnly {
// don't allow two log4j implementations to be present at test time
exclude(module = "log4j-slf4j-impl")
}
This does not change anything.
So I try your second approach, adding:
testImplementation("io.github.hakky54:logcaptor:2.7.10")
testImplementation("ch.qos.logback:logback-classic:1.4.3")
testImplementation("org.apache.logging.log4j:log4j-to-jul:2.19.0")
Which changes behaviour to this problem:
SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [org.apache.logging.slf4j.SLF4JServiceProvider@7fc95ed5]
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@1771617f]
SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [org.apache.logging.slf4j.SLF4JServiceProvider@7fc95ed5]
It feels I am getting closer, but still I am not there... now that there are TWO implementations and the "wrong" one gets picked, testing the logging still does not work.
Why on earth is logging such an overly complex thing? Working through Stack Overflow is a nightmare with all those wrong and outdated answers... :-(
Thanks a lot for trying to help!
from log-captor.
Yes, you are definitely getting closer but we still need to do some minor changes. Thank you by the way for explaining all the stepds you did, it gives me a better unstanding of what you did and what went wrong. I think it is pretty easy to solve as it is now clear for me that you don't need Log4J2. It seems like you added it by accident because the warning message of SLF4J was not clear enough. I would suggest the following changes to your project:
Can you remove these parts in your gradle build:
implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.19.0")
implementation("org.apache.logging.log4j:log4j-core:2.19.0")
testImplementation("org.apache.logging.log4j:log4j-to-jul:2.19.0")
configurations.testRuntimeOnly {
// don't allow two log4j implementations to be present at test time
exclude(module = "log4j-slf4j-impl")
}
You can keep the following dependency:
testImplementation("ch.qos.logback:logback-classic:1.4.3")
Can you adjust the logcaptor dependency declaration:
testImplementation("io.github.hakky54:logcaptor:2.7.10"){
exclude("ch.qos.logback", "logback-classic")
exclude("org.apache.logging.log4j", "log4j-to-slf4j")
}
So your resulting gradle build configuration should have the following dependencies:
implementation("io.github.microutils:kotlin-logging-jvm:3.0.0")
testImplementation("ch.qos.logback:logback-classic:1.4.3")
testImplementation("io.github.hakky54:logcaptor:2.7.10"){
exclude("ch.qos.logback", "logback-classic")
exclude("org.apache.logging.log4j", "log4j-to-slf4j")
}
Can you retry and share your results?
from log-captor.
Hi again! Thanks for all your time and effort, I really appreciate this!
So. Your last configuration does the job, but only for test side. Everything runs smooth there and LogCaptor can do its job.
But... on the production side, when I run my product, it complains again about no providers for logging:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
This is exactly where I started: using the main logging util dependency kotlin-logging which does not include any providers.
If I only knew now which provider/dependency I can add to the implementation dependencies without disturbing the test side again...
from log-captor.
So kotlin-logging-jvm
provides slf4j-api
and it is up to you which slf4j implementation you want to add to your project. For hobby projects I prefer to use org.slf4j:slf4j-simple
which just prints the logs to the console, hoewever for bigger projects or enterprise projects I prefer to use Logback which is capable of doing more advanced stuff like appending the logs to a file and also to the console and other features, see here for the documentation: https://logback.qos.ch/manual/index.html
If you want to use org.slf4j:slf4j-simple
than your configuration would be:
implementation("io.github.microutils:kotlin-logging-jvm:3.0.0")
implementation("org.slf4j:slf4j-simple:2.0.3")
testImplementation("ch.qos.logback:logback-classic:1.4.3")
testImplementation("io.github.hakky54:logcaptor:2.7.10"){
exclude("ch.qos.logback", "logback-classic")
exclude("org.apache.logging.log4j", "log4j-to-slf4j")
}
configurations.testRuntimeOnly {
exclude(module = "slf4j-simple")
}
If you want to use logback, than your configuration would be:
implementation("io.github.microutils:kotlin-logging-jvm:3.0.0")
implementation("ch.qos.logback:logback-classic:1.4.3")
testImplementation("io.github.hakky54:logcaptor:2.7.10"){
exclude("ch.qos.logback", "logback-classic")
exclude("org.apache.logging.log4j", "log4j-to-slf4j")
}
This should do the trick for you and resolve the last issue.
from log-captor.
@Zordid Any updates from your side, did it work?
from log-captor.
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.
from log-captor.
Related Issues (20)
- Expose MDC logback property map in LogEvent HOT 4
- Add existing contributors HOT 11
- ConcurrentModificationException in getLogs() HOT 7
- Logcaptor error logs do not contain expected content when reusing instance HOT 7
- log4j HOT 1
- Running the unit test directly from IDEA gives error HOT 7
- Not working with org.jacoco:jacoco-maven-plugin HOT 6
- There appears to be a classloading problem when using LogCaptor with `@QuarkusTest` test classes HOT 2
- LogEvent should implement toString() HOT 4
- Not compatible with log4j2 2.17.2 HOT 5
- Allow to retrieve logs for custom log levels HOT 2
- consoleCaptor.getStandardOutput() doesn't work HOT 6
- spring-boot-starter + log-captor: log4j-slf4j-impl cannot be present with log4j-to-slf4j HOT 5
- Upgrade to 2.8.0 HOT 18
- Suppressing Console Output HOT 3
- Are we supposed to close LogCaptor at the end of a test? HOT 3
- Issue with custom levels HOT 3
- Seeing DEBUG level logs after adding logcaptor dependency HOT 2
- disableConsoleOutput() is throwing NPE HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from log-captor.