首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Sbt测试:无法将org.apache.logging.slf4j.Log4jLogger类转换为ch.qos.logback.classic.Logger类(org.apache.logging.slf4j.Log4jLogger )

Sbt测试:无法将org.apache.logging.slf4j.Log4jLogger类转换为ch.qos.logback.classic.Logger类(org.apache.logging.slf4j.Log4jLogger )
EN

Stack Overflow用户
提问于 2022-08-01 20:08:59
回答 1查看 408关注 0票数 0

我是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')与此警告

代码语言:javascript
运行
复制
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运行测试时,它通过了。

我的测试代码如下

代码语言:javascript
运行
复制
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中的依赖性

代码语言:javascript
运行
复制
...

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运行测试时,我看到了以下警告

代码语言:javascript
运行
复制
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中工作,但不确定为什么强制转换不起作用。使用其他库测试日志记录有任何建议或其他方法吗?

EN

Stack Overflow用户

发布于 2022-08-02 05:43:54

来自SLF4J的警告消息非常有用。在这两种情况下,它都说在类路径中加载了几个日志库,这可能会给带来麻烦。

在查看详细信息时,它甚至会指出选择哪个库作为SLF4J实现:

在您的SBT测试中,它选择了Logback:Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

  • but,在SBT运行中,它选择了Log4j:Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]

这解释了期望日志库是Logback的代码在IntelliJ测试中工作,而不是在SBT运行时工作。

当类路径中有几个日志实现时,无法确定哪个SLF4J将使用.

现在,让我们澄清您在构建定义中的依赖关系:

  • slf4j-api:the SLF4J API、
  • log4j-api:log4j 2 API、
  • log4j-core:log4j 2 implementation
  • log4j-slf4j-impl:绑定以使SLF4J写入日志与log4j 2 implementation
  • logback-corelogback-classic:Logback实现(Logback附带一个绑定以使SLF4J写日志与Logback自动),并且您已经排除了slf4j-log4j12,它是用log4j 1.2 implementation.

制作SlF4J写日志的绑定

溶液

如果您不需要多个日志库(这是情况下99%的日志库),那么只要选择要使用的实现,它似乎就是Logback,因为您有特定于Logback的代码。然后删除其他库实现和绑定依赖项

这意味着在您的情况下删除log4j-corelog4j-slf4j-impl

但是,您可能仍然有依赖于log4j 2 API来记录内容的代码(例如,其他依赖项)。因此,您可能需要添加绑定库,以使log4j 2日志通过SlF4J编写。为此,添加log4j-to-slf4j-2.x依赖项。

注意:如果出于某种奇怪的原因,您需要几个日志实现,那么不要在代码中假设它是其中之一,也不要通过处理强制转换异常来处理它。

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73199070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档