2

I'm making plugin for Minecraft - 'Paper' exactly. And it uses JDA for Discord bot function.

The problem is, Minecraft(Paper) uses log4j as its logging library. JDA uses slf4j as its logging library. I want JDA to use log4j so that error message of JDA would be shown in console as plugin's error message. (See EDIT2 for actual logs)

No System.out.println() because Minecraft(Paper) will complain about using it.
No Logback because I think it is another logging library, thus it cannot work well with Minecraft(Paper)'s logging system (no JDA logs in Minecraft log etc.). I don't want to implement another logging library when there is already logging system provided by Minecraft, which is log4j.

JDA wiki only describes about Logback so I have to find my own way for making JDA with Minecraft's logging system, but it was no success.

For example:

// Something went wrong in JDA and shows stacktrace
[05:20:26] [Server thread/ERROR]: [MyPlugin] [JDA] 'JDA Error Message'
(prints stacktrace of the error)

// Show debug message of WebSocketClient (Since it is debug message, this can be turned off)
[05:20:26] [Server thread/DEBUG]: [MyPlugin] [JDA] WebSocketClient - Connected to WebSocket

// Show JDA message when JDA bot is loaded
[05:20:26] [Server thread/DEBUG]: [MyPlugin] [JDA] JDA - Finished Loading!

These all messages should be part of the Minecraft(Paper)'s logging system, not mimicing it. This means, it should use JavaPlugin#getLogger().info() or something like this in somewhere of the code.

How to make JDA to be like this?
Just implementing log4j-slf4j18-impl doesn't work. I think I should do something about JDA's logging stuff.


EDIT: Here is current build.gradle file content. LINK

Currently, my plugin implements log4j-slf4j-impl for JDA.

Elikill58
  • 4,050
  • 24
  • 23
  • 45
tetratheta
  • 177
  • 1
  • 13

2 Answers2

2

Log4j 2 SLF4J Binding exists for that purpose. It is an SLF4J logger implementation (like slf4j-simple) that logs everything to log4j. In other words, everything logged with SLF4J will be forwarded to log4j.

In order to use it, just add the following to your pom.xml (see this):

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-slf4j18-impl</artifactId>
  <version>2.17.2</version>
</dependency>

If you use Gradle, it would look like this:

compile 'org.apache.logging.log4j:log4j-slf4j18-impl:2.17.2'

Adding this dependency includes and automatically registers the logger.

dan1st
  • 12,568
  • 8
  • 34
  • 67
  • Thanks! Now I get `java.lang.NoSuchMethodError: org.apache.logging.slf4j.Log4jLoggerFactory: method 'void ()' not found` error, but no gibberish messages like NOP, so this is progress. I guess JDA's logging stuff are attached to log4j, but don't know how to configure it. Maybe I should try that after sleep. Thanks again! I really didn't know that it would be almost gone in one line. – tetratheta Feb 26 '22 at 21:11
  • I fixed it. It was an incompatibility between SLF4J versions. See [this](https://stackoverflow.com/a/70661446/10871900). – dan1st Feb 27 '22 at 07:58
  • How does `log4j-slf4j18-impl` 'automatically registers' the logger? I think I should do something to set logger but don't know how. Even after implementing `log4j-slf4j18-impl`, I still get error `SLF4J: No SLF4J providers were found.` and all logs are printed as STDERR. Maybe that's because it's printing its logs to STDOUT. Sorry for this basic question, but I've never used this kind of bridging library. – tetratheta Feb 28 '22 at 06:40
  • What SLF4J version do you use? Loggers are registered by a file present in `META-INF/services` and `log4j-slf4j18-impl` contains such a file. – dan1st Feb 28 '22 at 07:05
  • I added more information on question article. it contains information about dependencies and `META-INF/services` – tetratheta Feb 28 '22 at 07:41
1

You need to add a "bridge" from slf4j to log4j. The appropriate dependency needs to fit both the slf4j version and the log4j version.

To find the correct version I checked the build.gradle.kts of JDA JDA uses the 1.7.25 version of slf4j and your module uses the 2.17.2 version of the log4j.

So you need to add log4j-slf4j-impl.
The log4j-slf4j18-impl is for sl4j from 18 and newer version.

Maven Version

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-slf4j-impl</artifactId>
  <version>2.17.2</version>
</dependency>

Gradle Version

compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.2'

Also, making the assumption that your build depends on the JDA, it might be helpful to completely omit importing the SL4J since depending on JDA will make the SL4J available to your plugin. JDA dependency on SLF4J is declared as an API and therefore is available.

This was also derived from the build.gradle.kts of JDA

So most likely you can safely remove org.slf4j:slf4j-api:1.8.0-beta4 from your dependencies.

Update: for the gradle.build file.

  • Shadowjar-ing/shading sl4j and log4j might interfere with the initialization process. I could find an occurrence to support this. You could remove all related relocations and try again.
  • Replace compileOnly('org.slf4j:slf4j-api:1.7.36') with compileOnly('org.slf4j:slf4j-api:1.7.25') to match the version that JDA declares. Most probably this has nothing to do with the error faced.
Spyros K
  • 2,480
  • 1
  • 20
  • 37
  • 1
    slf4j 1.8.0 beta4 is from Paper API, so I can't remove it. To use slf4j 1.7, I have to relocate slf4j 1.7 in my plugin jar to not conflict with slf4j provided by Paper API. Also, when I do that, I still get strange warning saying `ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...` but even if I implement and relocate it, I still get that warning. – tetratheta Mar 10 '22 at 11:19
  • Perhaps having the whole gradle file would help. Does the final runtime classpath contain both slf4j 1.8.0 beta4 and slf4j 1.7 or only slf4j 1.8.0 beta4 ? – Spyros K Mar 10 '22 at 12:09
  • I've edited question article for `build.gradle`. I'm not sure if my plugin has both `slf4j` 1.8 and 1.7 but I think it only has 1.7. – tetratheta Mar 11 '22 at 13:20
  • I updated my answer, I think that the shadowing might be interfering with the initialization process of slf4j - log4j. – Spyros K Mar 11 '22 at 16:06
  • 1
    I only relocated `org.apache.logging.slf4j`, not `org.apache.logging.log4j`. It works - even though final fat jar looks ugly because `org` directory present in root directory of jar. No error message presents. I think the issue is solved. Thanks a lot! – tetratheta Mar 12 '22 at 17:11