3

I'm getting a StackOverFlowError in my project, as soon as it launches. I've seen other similar questions where the answer was that the lg4j.xml was not specifyed or uncorrectly formatted, but it does not seem to be the case here. This is the code:

public static void main( String[] args )
{
    // Configure Logger
    DOMConfigurator.configure("config/log4j.xml");

    logger.info("Starting StudyImporter");
}

This is the log4j.xml file:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern"
               value="%d{yyyy-MM-dd HH:mm:ss,SSS} - [%t] %-5p %c %x - %m%n" />
    </layout>
</appender>

<!-- log all logs to a separate log file every day -->
<appender name="MAIN_FA" class="org.apache.log4j.DailyRollingFileAppender">
    <param name="File" value="C:/project/logs/main.log" />
    <param name="datePattern" value="'-'yyyy-MM-dd'.log'" />
    <param name="append" value="true" />
    <!-- <param name="Threshold" value="INFO" /> -->
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d [%t] %-5p %C{6} (%F:%L) - %m%n" />
    </layout>
</appender>


<logger name="org.importadorestudios">
    <level value="INFO" />
</logger>

<root>
    <level value="INFO" />
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="MAIN_FA" />
</root>

And this is the error:

java.lang.StackOverflowError
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:45)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:64)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:285)
at org.apache.log4j.Category.<init>(Category.java:57)
at org.apache.log4j.Logger.<init>(Logger.java:37)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:43)
at org.apache.log4j.LogManager.getLogger(LogManager.java:45)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:64)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:285)
at org.apache.log4j.Category.<init>(Category.java:57)
at org.apache.log4j.Logger.<init>(Logger.java:37)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:43)
at org.apache.log4j.LogManager.getLogger(LogManager.java:45)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:64)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:285)
at org.apache.log4j.Category.<init>(Category.java:57)

Any help is greatly appreciated

Gatocan
  • 77
  • 1
  • 2
  • 7
  • 1
    Show your classpath. It looks like you have two adapter in it which have conflict. I doubt that `DOMConfigurator.configure("config/log4j.xml");` is even executed so problem is definitely in something else. – talex Sep 12 '18 at 09:47

2 Answers2

3

To elaborate on my comment, SLF4J is a logging facade. This means that all it provides is some interfaces and a handful of helper classes to smooth things out behind the scenes. To actually use it you need to pick a logging implementation.

There are many implementations to choose from, but the most notable are:

When you pick an implementation, you typically also need a binding from SLF4J to that implementation and bridges from the other logging APIs to SLF4J. The existence of those bridges is the biggest reason to use SLF4J, as then you can route all of your app's own and its dependencies' logging into one implementation. There's even support for java.util.logging to get forwarded to SLF4J.

The key point though is that you cannot have the binding and the bridge for the same implementation on the classpath at the same time. Otherwise, you get what you see here: a stack overflow because the bridge is calling SLF4J which is calling the binding which is calling the bridge. Unfortunately, the ecosystem and the pitfalls are not always widely understood, and sometimes people do the wrong thing when distributing their software. For example, a published library should never pull in bindings or bridges. A library should only depend on the SLF4J API. It is only a finished application, or the test cases for a library, that should pick an implementation and thus pull in a binding (if necessary) and bridges for the other logging APIs.

These are bindings:

These are bridges:

There's no logback bridge because logback's "native" API overlaps with SLF4J.

When using SLF4J, you want to pick one of the implementations. Then you include all of the following:

  • slf4j-api
  • your chosen implementation's binding
  • all of the bridges except the one for your chosen implementation

And you want to exclude all of the following if any of your transitive dependencies try to pull them in:

  • the bridge for your chosen implementation
  • any bindings except the one for your chosen implementation

You can set up exclusions in both Maven and Gradle.

kbolino
  • 1,441
  • 2
  • 18
  • 24
1

The problem was that there was a conflict between some of the libraries used by the project.

Apparently, someone once used another loggin library (slf4j) wich we no longer use. We removed the library from the pom.xml, but it was already downloaded in our computers. That caused the conflict wich generated the StackOverflowError.

To solve it, simply delete the unnecesary loggin library.

Thanks to talex for pointing in the right direction

Gatocan
  • 77
  • 1
  • 2
  • 7
  • see https://stackoverflow.com/questions/32366586/using-log4j2-with-slf4j-java-lang-stackoverflowerror – Arnaud Mar 30 '20 at 08:48
  • 1
    SLF4J is not a logging implementation, it is a logging facade. Removing it is usually the *wrong* thing to do. – kbolino Sep 10 '20 at 21:20