How to use logback-classic inside plugin? Conflicts with clion jar containing log4j binding

已回答

In my plugin I need to output logging messages with line number, time and so on. So for that purpose I need some logging framework which output I would redirect to ui.

So I tried using logback-classic and providing custom appender, that would output messages to ui. To ininitialize the appender in my plugin I cast Logger returned from slf4j to logback-classic. But slf4j can be bound only to one logging framework at a time and when I run plugin, slf4j binds to log4j from clion jar.

I tried to exclude the log4j from the classpath but that didn't work. I also tried to use log4j that clion uses instead of logback-classic, but I was unable to get log4j logger because it is deprecated.

 Can I use some slf4j logging framework (like logback-classic) inside of a plugin? Or can I somehow remove log4j binding from the classpath?

评论操作 固定链接

Here are the conflicts with log4j binding: 

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/vol0ncar/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.clion/clion/2021.3.3/f8447b540fa4bc964c57e12e331280c55406aba4/clion-2021.3.3/lib/3rd-party-rt.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/vol0ncar/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.3/7c4f3c474fb2c041d8028740440937705ebb473a/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
0
评论操作 固定链接

Here is the code where I cast slf4j logger to logback-classic logger and because the log4j binding is used, the error is raised here: 

(newLogger.underlyingLogger as Logger).getAppender("ClientAppender").let {
(it as ClientLogAppender).outputWindow =
project.service<OutputWindowProvider>().outputs[OutputType.CLIENT_LOG]
}
0
评论操作 固定链接

Can you please share the dependencies section in your Gradle build script?

0
评论操作 固定链接

Yes, of course

val coroutinesVersion by extra("1.5.2")
val protobufVersion by extra("3.18.0")
val grpcVersion by extra("1.40.1")
val grpcKotlinVersion by extra("1.1.0")

dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")

// grpc and protobuf
implementation("com.google.protobuf:protobuf-java:$protobufVersion")
implementation("com.google.protobuf:protobuf-java-util:$protobufVersion")
implementation("io.grpc:grpc-netty-shaded:$grpcVersion")
implementation("io.grpc:grpc-protobuf:$grpcVersion")
implementation("io.grpc:grpc-stub:$grpcVersion")
implementation("io.grpc:grpc-kotlin-stub:$grpcKotlinVersion")
compileOnly("javax.annotation:javax.annotation-api:1.3.2")
implementation("com.google.protobuf:protobuf-kotlin:$protobufVersion")

implementation("ch.qos.logback:logback-core:1.2.3")
implementation("ch.qos.logback:logback-classic:1.2.3")
implementation("io.github.microutils:kotlin-logging-jvm:2.1.20")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.0")

implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.2")
}
0
评论操作 固定链接

Why don't you simply use slf4j in your plugin, without specifying any implementation? This will use the implementation provided by CLion, which is log4j in CLion 2021.3 and java.util.logging in CLion 2022.1.

0
评论操作 固定链接

The logger output is redirected to ui by Appender, so I need to access the Appender directly to specify ui component. For that I cast slf4j logger to concrete implementation of logback-classic, and then I grab appender and specify ui component (I added the code earlier in comments)

0
评论操作 固定链接

If you need to display logs coming from your code in your UI, the best solution is to implement an entirely separate mini-logging framework, not depending on SLF4J or anything else, and use that to keep track of your logs. Your framework can also forward logs to the SLF4J logger if you need to write your logs to idea.log too.

Any solution relying on casting a logger instance to a specific implementation class is very likely to break in CLion 2022.1, which will switch from log4j to java.util.logging.

0
评论操作 固定链接

I'll think about implementing a separate logging. I was wondering may be I could use java.util.logging or something like tinylog, which does not depend on SLF4J, is it reasonable idea? Or something can break? 

0
评论操作 固定链接

Tinylog should work, yes.

0

请先登录再写评论。