java 如何让 Jersey 使用 SLF4J 而不是 JUL?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4121722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:52:09  来源:igfitidea点击:

How to make Jersey to use SLF4J instead of JUL?

javalogginglog4jjerseyslf4j

提问by yegor256

I've found a useful articlethat explains how to make Jersey to use SLF4J instead of JUL. Now my unit test looks like (and it works perfectly):

我找到了一篇有用的文章,解释了如何让 Jersey 使用 SLF4J 而不是 JUL。现在我的单元测试看起来像(并且它完美地工作):

public class FooTest extends JerseyTest {
  @BeforeClass
  public static void initLogger() {
    java.util.logging.Logger rootLogger =
      java.util.logging.LogManager.getLogManager().getLogger("");
    java.util.logging.Handler[] handlers = rootLogger.getHandlers();
    for (int i = 0; i < handlers.length; i++) {
      rootLogger.removeHandler(handlers[i]);
    }
    org.slf4j.bridge.SLF4JBridgeHandler.install();
  }
  public FooTest() {
    super("com.XXX");
  }
  @Test
  public void testSomething() throws Exception {
    // ...
  }
}

My pom.xmlincludes these dependencies:

我的pom.xml包括这些依赖项:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.1</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.1</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jul-to-slf4j</artifactId>
  <version>1.6.1</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.16</version>
</dependency>

It works perfectly, but I don't want to make the same configuration in every unit test. It's an obvious code duplication, which I would like to avoid. How can I do this more effectively?

它运行良好,但我不想在每个单元测试中都进行相同的配置。这是一个明显的代码重复,我想避免。我怎样才能更有效地做到这一点?

ps. Maybe it's not possible to optimize the code above and I'm doing the best I can?

附:也许无法优化上面的代码,而我正在尽我所能?

采纳答案by yegor256

The best way to do it is through a custom Listener. Being initialized before JSF servlet it should configure jul-to-slf4j bridge in contextInitialized(ServletContextEvent).

最好的方法是通过自定义Listener。在 JSF servlet 之前初始化它应该在contextInitialized(ServletContextEvent).

回答by assylias

If you are using the client API you can manually redirect the logs to slf4j (note that it may break in future versions although it seems unlikely):

如果您正在使用客户端 API,您可以手动将日志重定向到 slf4j(请注意,它可能会在未来版本中中断,但似乎不太可能):

Logger LOG = LoggerFactory.getLogger(MyClass.class); //slf4j logger

WebTarget ws = ClientBuilder.newClient(config)
                  .register(new LoggingFilter(new JulFacade(), true));

private static class JulFacade extends java.util.logging.Logger {
  JulFacade() { super("Jersey", null); }
  @Override public void info(String msg) { LOG.info(msg); }
}

回答by L42

This worked for me:

这对我有用:

public abstract class JerseyTestSFL4J extends JerseyTest {

  static {
    // Get JerseyTest to use SLF4J instead of JUL
    SLF4JBridgeHandler.removeHandlersForRootLogger();
    SLF4JBridgeHandler.install();
  }
}

and then having my tests extend JerseyTestSFL4J.

然后让我的测试扩展JerseyTestSFL4J

回答by Jure Skelin

Slf4jLoggerfrom org.apache.cxf:cxf-corepackage is another option. It implements java.util.logging.Loggerand delegate cals to slf4J.

Slf4jLoggerorg.apache.cxf:cxf-core包是另一种选择。它实现java.util.logging.Loggercals 并将其委托给 slf4J。

Jersey server:

泽西服务器:

ResourceConfig config = new ResourceConfig(HelloWorldResource.class);
config.register(
    new Slf4jLogger(this.getClass().getName(), null));

Jersey client:

泽西岛客户:

ClientBuilder
    .newClient()
    .register(
        new LoggingFeature(
                new Slf4jLogger(this.getClass().getName(), null)));

回答by Grigory Kislin

In my app Jersey logging (with proper pom.xmland logback.xml) works fine only with

在我的应用程序中, Jersey 日志记录(使用适当的pom.xmllogback.xml)仅适用于

    SLF4JBridgeHandler.install(); 

For tests you can make base abstracttest with common configuration and extends other JUnit from it:

对于测试,您可以使用通用配置进行基本抽象测试,并从中扩展其他 JUnit:

public abstract class AbstractTest {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class);

    static {
        SLF4JBridgeHandler.install();
    }

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Rule
    // http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev
    public Stopwatch stopwatch = new Stopwatch() {
        @Override
        protected void finished(long nanos, Description description) {
           ...

回答by TJR

What it sounds like is you'd want the JUL/SLF4J configuration handle before JUnit starts testing so it could be covered for all tests? Here's a way you could do that.

听起来像是在 JUnit 开始测试之前您想要 JUL/SLF4J 配置句柄,以便它可以覆盖所有测试?这是您可以做到的一种方法。

Output

输出

MySuite.init()
MySuite()
getSuiteTests()
MyTest.init()
MyTest()
test()

Code

代码

@RunWith(AbstractTestSuite.TestSuiteRunner.class)
public abstract class AbstractTestSuite {
   public static class TestSuiteRunner extends Suite {
      public TestSuiteRunner(Class<?> klass) throws Exception {
         super(klass, ((Class<? extends AbstractTestSuite>) klass).newInstance().getSuiteClasses());
      }
   }

   public Class<?>[] getSuiteClasses() {
      List<Class<?>> all = new ArrayList<Class<?>>();
      for (Class<?> testClass : getSuiteTests()) {
         all.add(testClass);
      }
      return all.toArray(new Class<?>[0]);
   }

   protected abstract Iterable<Class<?>> getSuiteTests();
}

public class MySuite extends AbstractTestSuite {
   public static class MyTest {
      static {
         System.out.println("MyTest.init()");
      }

      public MyTest() {
         System.out.println("MyTest()");
      }

      @Test
      public void test() {
         System.out.println("test()");
         assertTrue(true);
      }
   }

   static {
      System.out.println("MySuite.init()");
   }

   public MySuite() {
      System.out.println("MySuite()");
   }

   @Override
   protected Iterable<Class<?>> getSuiteTests() {
      System.out.println("getSuiteTests()");
      return Arrays.asList(new Class<?>[] {MyTest.class});
   }
}