漏洞?无法加载配置中指定的记录器 [akka.testkit.TestEventListener]?

Bug? Logger specified in config can't be loaded [akka.testkit.TestEventListener]?

根据 docs,在(预期日志消息)下,

Be sure to exchange the default logger with the TestEventListener in your application.conf to enable this function: akka.loggers = [akka.testkit.TestEventListener]

因此,当我将其放入 application.conf 时效果很好。我的测试很好

@Test
public void testActorForNonExistentLocation() throws Exception {
  final Map<String, String> configValues = Collections.singletonMap("tenant.assetsLocation",
                                                                    "/non/existentLocation");
  final Config config = mergeConfig(configValues);
  System.out.println(config.getList("akka.loggers"));

  new JavaTestKit(system) {{
    assertEquals("system", system.name());

    final Props props = TenantMonitorActor.props(config);
    final ActorRef supervisor = system.actorOf(props, "supervisor");
    new EventFilter<Void>(DiskException.class) {

      @Override
      protected Void run() {
        supervisor.tell(new TenantMonitorMessage(), supervisor);
        return null;
      }
    }.from("akka://system/user/supervisor/diskMonitor").occurrences(1).exec();

  }};
}

现在,当我尝试 运行 我的应用程序时

public class Main {
  private Main() {
  }

  public static void main(final String[] args) {
    final Config config = ConfigFactory.load();
    final ActorSystem actorSystem = ActorSystem.create(config.getString("ec.name"));
    setUpMonitoring(actorSystem, config);
  }

  private static void setUpMonitoring(final ActorSystem system, final Config config) {
    final ActorRef tenantMonitorRef = system.actorOf(TenantMonitorActor.props(config),
                                                     "tenantMonitor");
    tenantMonitorRef.tell(new TenantMonitorMessage(), tenantMonitorRef);
  }
}

我看到的错误是

error while starting up loggers
akka.ConfigurationException: Logger specified in config can't be loaded [akka.testkit.TestEventListener] due to [java.lang.ClassNotFoundException: akka.testkit.TestEventListener]
    at akka.event.LoggingBus$$anonfun$$anonfun$apply.applyOrElse(Logging.scala:116)
    at akka.event.LoggingBus$$anonfun$$anonfun$apply.applyOrElse(Logging.scala:115)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
    at scala.util.Failure$$anonfun$recover.apply(Try.scala:215)
    at scala.util.Try$.apply(Try.scala:191)
    at scala.util.Failure.recover(Try.scala:215)
    at akka.event.LoggingBus$$anonfun.apply(Logging.scala:115)
    at akka.event.LoggingBus$$anonfun.apply(Logging.scala:110)
    at scala.collection.TraversableLike$WithFilter$$anonfun$map.apply(TraversableLike.scala:728)
    at scala.collection.Iterator$class.foreach(Iterator.scala:750)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1202)
    at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
    at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:727)
    at akka.event.LoggingBus$class.startDefaultLoggers(Logging.scala:110)
    at akka.event.EventStream.startDefaultLoggers(EventStream.scala:26)
    at akka.actor.LocalActorRefProvider.init(ActorRefProvider.scala:622)
    at akka.actor.ActorSystemImpl.liftedTree2(ActorSystem.scala:619)
    at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:616)
    at akka.actor.ActorSystemImpl._start(ActorSystem.scala:616)
    at akka.actor.ActorSystemImpl.start(ActorSystem.scala:633)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:142)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:109)
    at akka.actor.ActorSystem$.create(ActorSystem.scala:57)
    at akka.actor.ActorSystem.create(ActorSystem.scala)
    at Main.main(Main.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ClassNotFoundException: akka.testkit.TestEventListener
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at akka.actor.ReflectiveDynamicAccess$$anonfun$getClassFor.apply(DynamicAccess.scala:67)
    at akka.actor.ReflectiveDynamicAccess$$anonfun$getClassFor.apply(DynamicAccess.scala:66)
    at scala.util.Try$.apply(Try.scala:191)
    at akka.actor.ReflectiveDynamicAccess.getClassFor(DynamicAccess.scala:66)
    at akka.event.LoggingBus$$anonfun.apply(Logging.scala:113)
    ... 24 more
Exception in thread "main" akka.ConfigurationException: Could not start logger due to [akka.ConfigurationException: Logger specified in config can't be loaded [akka.testkit.TestEventListener] due to [java.lang.ClassNotFoundException: akka.testkit.TestEventListener]]
    at akka.event.LoggingBus$class.startDefaultLoggers(Logging.scala:144)
    at akka.event.EventStream.startDefaultLoggers(EventStream.scala:26)
    at akka.actor.LocalActorRefProvider.init(ActorRefProvider.scala:622)
    at akka.actor.ActorSystemImpl.liftedTree2(ActorSystem.scala:619)
    at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:616)
    at akka.actor.ActorSystemImpl._start(ActorSystem.scala:616)
    at akka.actor.ActorSystemImpl.start(ActorSystem.scala:633)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:142)
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:109)
    at akka.actor.ActorSystem$.create(ActorSystem.scala:57)
    at akka.actor.ActorSystem.create(ActorSystem.scala)
    at Main.main(Main.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

我的application.conf长得像

akka {
  event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
  loglevel = "INFO"
  loggers = [akka.testkit.TestEventListener]
}

ec {
  name = "Connector"
}

tenant {
  assetsLocation: /Users
}

monitoring {
  tenant.disk.schedule.seconds: 2
  tenant.disk.threshold.percent: 80
}

我也安装了依赖项

<dependencies>
  <dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-actor_2.11</artifactId>
    <version>${akka-actor_2.11.version}</version>
  </dependency>
  <dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-testkit_2.11</artifactId>
    <version>${akka-testkit_2.11.version}</version>
  </dependency>
</dependencies>

和版本

<akka-actor_2.11.version>2.3.9</akka-actor_2.11.version>
<akka-testkit_2.11.version>2.3.10</akka-testkit_2.11.version>

bug/inconsistency在哪里?

可能根本不是错误和理解上的差异。

我们使用 maven scopes 来决定哪些依赖项应该可用以及何时可用。通常在测试中,我们使用 <scope>test</scope> 使依赖项仅在测试中可用,而不是在捆绑时在最终应用程序 jar 中可用。

现在如果我们使用这种测试(Expecting Log Messages),我们需要删除 <scope>test</scope> 让应用程序 运行 正确并同时通过测试。这意味着依赖 akka-testkit 也需要出现在最终的 jar 中,因为 application.conf 需要它来加载 akka.testkit.TestEventListener

如果一切听起来正确,这会将生产代码和测试代码结合在一起,并且在当前设置中是必需的。

同样,我可能在这里遗漏了一些非常基本的东西,但我可以 运行 应用程序并让测试通过的唯一方法是结合依赖项 akka-actorakka-testkit together .

你有什么想法?

在您的测试资源中添加一个 application.conf:

src/test/resources/application.conf

内容可能如下所示:

include "../../main/resources/application"

akka.loggers = [akka.testkit.TestEventListener]

此 application.conf 将仅在测试期间加载,因此您可以将 akka-testkit 依赖项的范围限定为仅测试。