![](/img/trans.png)
[英]ClassCastException: org.slf4j.impl.Log4jLoggerAdapter cannot be cast to ch.qos.logback.classic.Logger
[英]Sbt test: class org.apache.logging.slf4j.Log4jLogger cannot be cast to class ch.qos.logback.classic.Logger (org.apache.logging.slf4j.Log4jLogger
我是 Scala 和 JVM 的新手,我想为记录器编写单元测试,但是当我从终端运行sbt test
时出现此错误。
java.lang.ClassCastException: class org.apache.logging.slf4j.Log4jLogger cannot be cast to class ch.qos.logback.classic.Logger (org.apache.logging.slf4j.Log4jLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app')
和此警告
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.16.0/log4j-slf4j-impl-2.16.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.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.apache.logging.slf4j.Log4jLoggerFactory]
但是当我从 IntelliJ 运行测试时,它通过了。
我的测试代码如下
import org.scalatest._
import flatspec._
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.read.ListAppender
import org.slf4j.LoggerFactory
class MyAppSuite extends AnyFlatSpec {
it should "Log message" in {
object MyApp {
val LOGGER = LoggerFactory.getLogger(classOf[ILoggingEvent])
}
class MyApp {
def hello(word: String): Unit = {
MyApp.LOGGER.info(s"Word is ${word}")
}
}
val appender = new ListAppender[ILoggingEvent]
appender.start()
val logger = MyApp.LOGGER.asInstanceOf[Logger]
logger.addAppender(appender)
val myApp = new MyApp
myApp.hello("wow")
val logsList = appender.list
assert(logsList.size() === 1)
val logEvent = logsList.get(0)
assert(logEvent.getLevel.levelStr === "INFO")
assert(logEvent.getMessage === "Word is wow")
}
}
我在build.sbt
中的依赖项
...
scalaVersion := "2.12.14"
val log4jVersion = "2.16.0"
val loggingDependencies = Seq(
"org.slf4j" % "slf4j-api" % "1.7.36",
"org.apache.logging.log4j" % "log4j-api" % log4jVersion,
"org.apache.logging.log4j" % "log4j-core" % log4jVersion,
"org.apache.logging.log4j" % "log4j-slf4j-impl" % log4jVersion
)
val testingDependencies = Seq(
"org.scalamock" %% "scalamock" % "5.2.0" % Test,
"org.scalatest" %% "scalatest" % "3.2.12" % Test,
"ch.qos.logback" % "logback-classic" % "1.2.11" % Test,
)
libraryDependencies ++= loggingDependencies ++ testingDependencies
excludeDependencies ++= Seq(
"org.slf4j" % "slf4j-log4j12"
)
当我从 IntelliJ 运行测试时,我看到了这个警告
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.16.0/log4j-slf4j-impl-2.16.0.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 [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
我在 Java 中发现了类似的日志记录测试
所以我认为它应该在 Scala 中工作,但不确定为什么铸造不起作用。 使用其他库测试日志记录的任何建议或其他方法?
SLF4J 的警告信息真的很有帮助。 在这两种情况下,它都说在类路径中加载了几个日志库,这可能会导致麻烦。
在查看详细信息时,它甚至会说明选择哪个库作为 SLF4J 实现:
Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
这解释了您希望日志库为 Logback 的代码在 IntelliJ 测试中有效,但在 SBT 运行时无效。
当类路径中有多个日志记录实现时,无法确定 SLF4J 将使用哪一个。
现在,让我们澄清一下构建定义中的依赖关系:
slf4j-api
: SlF4J API,log4j-api
:log4j 2 API,log4j-core
:log4j 2 实现log4j-slf4j-impl
:使用 log4j 2 实现使 SLF4J 写入日志的绑定logback-core
和logback-classic
:Logback 实现(Logback 带有一个绑定,可以使 SLF4J 自动使用 Logback 写入日志)并且您已经排除slf4j-log4j12
,它是使 SLF4J 使用 log4j 1.2 实现写入日志的绑定。解决方案
如果您不需要多个日志库(99% 的情况下),只需选择您要使用的实现,它似乎是 Logback,因为您有 Logback 特定代码。 然后删除其他库实现和绑定依赖项。
这意味着在您的情况下删除log4j-core
和log4j-slf4j-impl
。
但是你可能仍然有依赖 log4j 2 API 来记录内容的代码(例如其他依赖项)。 因此,您可能需要添加绑定库以使 log4j 2 日志通过 SlF4J 写入。 为此,请添加log4j-to-slf4j-2.x
依赖项。
注意:如果出于某种奇怪的原因您需要多个日志记录实现,那么不要在您的代码中假设它是其中之一,或者通过处理强制转换异常来处理它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.