Sponge and Bukkit version of the same plugin - using loggers in "common" code?

I want to create plugin that had Sponge version and Bukkit version. Huge parts of the code will be shared between tham, but I want to add some logging in this part. The problem is that Bukkit uses java.util.logging and Sponge uses slf4j.
How can I actually use loggers in this part of code without creating separate version of this part of code for Bukkit and Spigot?

Java.util.logging will still work fine but it wont be formatted perfectly

The thing is that these loggers are different classes. If I create a wrapper class something like this:

logger.info("Something {0} {1} ....", someObject, otherObject);

will work eighter with java.util.logging or with slf4l.

If I understand everything correctly slf4j can internally use java.util.logging, but is there any way to force it to use the specific logger from bukkit plugin? And I have no idea how to actually configure it.

I abstracted out a large amount of my CraftIRC code for this purpose (though with Bukkit dead, I didn’t bother writing that implementation). I created two separate projects: The abstracted main code, and the Sponge implementation.

Here is the Logger interface I wrote that is implemented in this class in my Sponge implementation. So, I just pass this implementation of Logger to the main code that handles pretty much everything.

I have some listening to Sponge events but for the most part everything is not dependent on Sponge itself.

This is what I wanted to do but I thought it’s a bit stupid idea since slf4j is already an abstraction for other logging frameworks.
And this way I won’t be able to do something like this:

logger.info("Something {} something else {} something else {}: {}", new Object[]{obj1, obj2, obj3, obj4});

If I won’t find any other way, I will use this method with String.format.

You can access whatever slf4j methods you want. I just only used those because I didn’t need more.

java.util.logging and slf4j use different format.
java.util.logging:

logger.log(INFO, "something {0}", new Object[]{obj1});

slf4j:

logger.log(INFO, "something {}", new Object[]{obj1});

so it’s not so easy.
And if I use String.format - the final string is created even if logging at this level is disabled. And I need to do it differently for different types.

slf4j is exactly the logging abstraction that you are trying to create.

Instead of writing yet another abstraction layer, I would use slf4j directly and bundle it and a binding for java.util.logging on Bukkit.

This is what I thought I should do, but I have no idea how to do it.
Configuring logging frameworks is magic for me…

First, please read the slf4j manual carefully to understand how slf4j works.

I assume that your project uses a build tool such as Gradle or Maven and your project is split in multiple modules:

  • core contains the plugin’s core that is used by all implementations,
  • sponge implements the core for Sponge.
  • bukkit implements the core for Bukkit,

You need to add a dependency to SLF4J API to the core and directly use slf4j for all logging purposes.
For sponge, you do not need to add additional dependencies since Sponge already bundles slf4j and a corresponding binding.
For bukkit, you need to add a dependency to slf4j-jdk14 whitch makes slf4j use `java.util.logging. Since Bukkit does not bundle either of these dependencies, you need to add them to your plugin’s JAR file (on Gradle you might want to use the shadow plugin, on Maven there is the shade plugin).

1 Like