Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

configurations in log4j2.xml not being applied after installing logcaptor #8

Closed
mhammadkassem opened this issue May 20, 2021 · 12 comments

Comments

@mhammadkassem
Copy link

In my log4j2.xml file I configured log messages to be printed without any log info, only the message itself () amd it was working fine. Once I added logcaptor dependency in my POM file, the log messages appear as if there is a default configuration, so my configuration won't be applied.

@Hakky54
Copy link
Owner

Hakky54 commented May 20, 2021

Hey,

To help you out and to understand the root cause of the issue I need a bit more information. Did you added the dependency as a test scoped dependency? Could you share pom or other project configuration?

@Hakky54
Copy link
Owner

Hakky54 commented May 22, 2021

Hi mate @mhammadkassem any news from your side, looking forward to see your project configuration

@Edhilion
Copy link

Hello,

I also have this issue with both slf4j and log4j2, and when I apply the exclusions in the maven config.
My production logs are fine, but no configuration is applied to my test logs.

I'll try to make a sample Github project for you to understand.

And one more point, SLF4J say the following about librairies (maybe it can help) :
"Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose. When you come across an embedded component declaring a compile-time dependency on any SLF4J binding, please take the time to contact the authors of said component/library and kindly ask them to mend their ways."
http://www.slf4j.org/codes.html#multiple_bindings

@Edhilion
Copy link

Hello again.

You can find a well known code of yours here : https://github.com/Edhilion/java-tutorials 😉

You will find two new "tutorials" :

  • log-captor-with-slf4j-log4j-with-configuration
  • slf4j-log4j-with-configuration-without-logcaptor

How to see the issue ?

You will see that each log4j2.xml contains a "with-config" or "with-config-without-logcaptor" in the appended pattern layout.
Launch each module test.

  • The slf4j-log4j-with-configuration-without-logcaptor displays with-config-without-logcaptor in the log. 👍
  • The log-captor-with-slf4j-log4j-with-configuration doesn't display with-config in the log. 👎

Happy bug hunting. 🙂

@Hakky54
Copy link
Owner

Hakky54 commented May 26, 2021

Amazing @Edhilion thank you for the detailed description and the examples of the issues on the forked repo. I have now a clear understanding what the issue is you are facing, this is helpful. I will ping you when I have any updates from my side.

@Hakky54
Copy link
Owner

Hakky54 commented May 28, 2021

Hi @Edhilion and @mhammadkassem

I have analysed the issue and came to a conclusion that sadly this option is not possible with LogCaptor. Let me first try to explain how I came to this conclusion...

The log configuration xml file contains a list of appenders, which can be configured to have a different kind of formatting or other configuration such as log level. While LogCaptor uses a custom appender, to be very specific the ListAppender of Logback which is an in-memory list for collecting log events. So when LogCaptor is being used (during the tests) it will use a different appender than configured in your log4j2.xml and that is the reason why your logs look different than how you have configured in your log4j2.xml.

So would it be possible to use the ListAppender of Logback, which LogCapture is using, and also use the log4j2.xml file? Unfortunately not and the main reason is that LogCaptor relies on SLF4J api and it uses Logback under the covers to capture the logs which is a SLF4J implementation. SLF4J won't allow to have multiple implementations during runtime. The log4j-slf4j-impl is able to process the log4j2.xml file because it is an SLF4J implementation which developers can use to forward their log4j2 logs to slf4j without the need of changing their code base. But log4j-slf4j-impl cannot be present when using LogCaptor because SLF4J won't allow multiple implementation as LogCaptor is already using Logback

What will happen to my production logs when using LogCaptor?
If LogCaptor is configured as a test scoped dependency it won't be available when you run your application on production. It won't be available on the classpath for example if you generate an executable jar. So in your case it will just use your default log dependency and also log configuration. So please add it as a test scoped dependency and not as a compile time dependency.

What is the alternative?
Well LogCaptor will capture the log4j2 logs and you can easily assert it. But I can understand that you also want to test your logs with the log4j2.xml configuration file. You could convert it to a Logback configuration file, but that would not be a nice alternative... A good alternative would be I think not using LogCaptor and add a console listener within your unit tests to capture the console logs or a file listener/reader to read and extract the the content of a log file and to test it during the unit test. An alternative could be something like this mentioned at stackoverflow: Java, Junit - Capture the standard input / Output for use in a unit test

You also mentioned the following:

And one more point, SLF4J say the following about librairies (maybe it can help) :
"Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose. When you come across an embedded component declaring a compile-time dependency on any SLF4J binding, please take the time to contact the authors of said component/library and kindly ask them to mend their ways."
http://www.slf4j.org/codes.html#multiple_bindings

LogCaptor forwards all type of logs (Log4j, Log4j2, Java Util Logging etc) to SLF4J and afterwords it uses Logback as SLF4J implementation to capture those logs. So to have a functional LogCaptor I need to ship it with a SLF4J binding or else it won't be able to capture the logs and I think it is pretty essential as the sole purpose of the library is to capture logs... But I agree with your statement. I have another library, see here: GitHub - SSLContext Kickstart which only depends on slf4j-api and does not include a compile-time dependency on a SLF4J binding. So I agree with the statement of the SLF4J team and I am following their advice for my other libraries. I appreciate that you went through their documentation and mentioned their advice to me! ❤️

I hope this makes sense. If you have any other questions or concerns please drop it here. And if you think it is possible to use LogCaptor while also applying the Log4j2 configuration during the test phase please share it 😊 or feel free to contribute to the project if you can add this capability to the library.

@Edhilion
Copy link

Edhilion commented Jun 1, 2021

Hi @Hakky54.
Thank you so much for all this long description.

I'll try to test it on my side and, if I can, I'll be proud to contribute to your project.

@Edhilion
Copy link

Edhilion commented Jun 1, 2021

Hi again,

If I want to make it work with both Logback and Log4j2, do you mind I propose two implementations of your LogCaptor, one for each framework, with a switch based on slf4jLogger instanceof Logger ?

@Edhilion
Copy link

Edhilion commented Jun 1, 2021

Never mind. After some deep analyzis in SLF4J code, it seems this is really not possible.
And I think it won't be possible in their next version either...

When I say "it is not possible", I mean "I can write production code that will work, but I can't test it inside the very same project", so it is a no go for me.

So I guess I'll make my own version based on log4j2 instead of logback.
I still don't know if I'll put it on GitHub, because I am not a frequent Open Source contributor, and don't want people to rely on a work I will not really maintain. 😕

@Hakky54
Copy link
Owner

Hakky54 commented Jun 1, 2021

Never mind. After some deep analyzis in SLF4J code, it seems this is really not possible.
And I think it won't be possible in their next version either...
When I say "it is not possible", I mean "I can write production code that will work, but I can't test it inside the very same project", so it is a no go for me.

Ah thats sad to hear, but I can understand it. I was still hoping this was somehow possible and it would be nice to add it to this library. Having a logcaptor for two different logging api's in this case 1 for SLF4J and 1 for Log4J2 would be more powerful and more customisable, but I choose to redirect all non SLF4J based logs to SLF4J and just use Logback to capture it and for the basic assertions this is sufficient. (for the most developers i think...)

So I guess I'll make my own version based on log4j2 instead of logback.
I still don't know if I'll put it on GitHub, because I am not a frequent Open Source contributor, and don't want people to rely on a work I will not really maintain. 😕

Sounds as a great idea, please let me know if you start on it. I would love to contribute!

I will close this issue as it is not-fixable (for now...). But I will reopen it when I find a solution, or feel free to reopen when you or someone else has a solution.

@Hakky54 Hakky54 closed this as completed Jun 1, 2021
@Hakky54 Hakky54 added the wontfix This will not be worked on label Jun 1, 2021
@Hakky54
Copy link
Owner

Hakky54 commented Jul 15, 2021

Hey @Edhilion and @mhammadkassem!

I have some update regarding this issue/limitation.
I have created a new library to support specifically this use-case and it works for all logging api and implementations. It just captures all the output generated on the console. Either by a logging api or just System.out. You can also easily capture the prefix or suffix or assert the logging format etc.

You can view it here: GitHub - ConsoleCaptor

I would love to hear your opinion.

@Hakky54 Hakky54 reopened this Jul 15, 2021
@stale
Copy link

stale bot commented Aug 14, 2021

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 stale bot added the no-activity label Aug 14, 2021
@Hakky54 Hakky54 removed the wontfix This will not be worked on label Aug 14, 2021
@stale stale bot removed the no-activity label Aug 14, 2021
@Hakky54 Hakky54 closed this as completed Aug 14, 2021
joc-a added a commit to JetBrains/Exposed that referenced this issue Aug 30, 2023
Adding the LogCaptor dependency caused the logging level to be DEBUG instead of INFO, even though it is configured to be INFO in log4j2.xml. This is a known issue (Hakky54/log-captor#8) because LogCaptor uses a different appender than the one configured in log4j2.xml. More details in this comment: Hakky54/log-captor#8 (comment).

The solution is to remove the dependency and create a custom appender which is used to test the logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants