SLF4j 与 Log4j2 错误无法调用元素 RollingFile 的类 ...RollingFileAppender 中的工厂方法

2024-03-31

我在 TestNG 中并行运行一些 WebDriver 测试。我希望能够将在目录结构中运行的每个测试的日志记录到单独的文件中,如下所示:

target\logs\TestNGSuiteName(SuiteStartTime)
    Test1ClassName.TestMethod1 (TestStartTime).log
    Test1ClassName.TestMethod2 (TestStartTime).log

etc.

使用 Log4j 和 SLF4j 是否可以为每个单独的 TestNG 测试创建单独的日志文件?

我尝试使用 RollingFileAppender,但它看起来不像是为单独的日志文件运行单独的实例而设计的,就像我在这里尝试做的那样。

我收到了错误

ERROR Unable to invoke factory method in class class org.apache.logging.log4j.core.appender.RollingFileAppender for element RollingFile.
Unable to create Appender of type RollingFile.

Log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
        <Routing name="Routing">
            <Routes pattern="$${ctx:ROUTINGKEY}">
                <Route>
                    <RollingFile name="Rolling-${ctx:ROUTINGKEY}"
                                 fileName="target/logs/${ctx:suiteTimestamp}/${ctx:testName} (${ctx:testStartTime}).log"
                                 filePattern="target/logs/${ctx:testname} ${ctx:testStartTime}_%i.log.gz">
                        <PatternLayout>
                            <pattern>%d{HH:mm:ss.SSS} [%t] %p %c{3} - %m%n</pattern>
                        </PatternLayout>
                        <Policies> <!-- 6 hour rollover-->
                            <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
                            <SizeBasedTriggeringPolicy size="10 MB"/>
                        </Policies>
                    </RollingFile>
                </Route>
            </Routes>
        </Routing>
    </Appenders>
    <Loggers>
        <Logger name="james.log" level="debug" additivity="false">
            <AppenderRef ref="Routing"/>
        </Logger>
    </Loggers>
</Configuration>

伐木工人.java

package james.log;

import james.util.ConcurrentDateFormatAccess;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.ITestContext;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.lang.reflect.Method;

/**
 * @author james.affleck
 */
public class LumberjackTest {
    private static final Logger logger = LoggerFactory.getLogger(LumberjackTest.class);
    private static ThreadLocal<String> methodLogName = new ThreadLocal<>();
    private static String suiteName = "";

    @BeforeMethod
    public void loggerDoTheThings(ITestContext context, Method method) {
        if(suiteName.isEmpty()) {
            String suite = context.getSuite().getName() + "(";
            String suiteTime = new ConcurrentDateFormatAccess().getCurrentDateSPrecision();
            suite += suiteTime + ")";
            suiteName = suite;
        }

        // Test filename = testClass.testMethodname
        String classname = this.getClass().getName();
        classname = classname.substring(classname.lastIndexOf(".") + 1); //get rid of package info we don't care about
        String testName = classname + "." + method.getName();

        // Using this to store logger instance for later
        String testStart = new ConcurrentDateFormatAccess().getCurrentDateMSPrecision();
        methodLogName.set(testName + testStart);

        ThreadContext.put("suiteTimestamp", suiteName);
        ThreadContext.put("testName", testName);
        ThreadContext.put("testStartTime", testStart);
    }

    @AfterMethod
    public void closeTheThings() {
        methodLogName.set(null);
    }
    @AfterSuite
    public void closeSuite() {
        suiteName = null;
    }

    @Test
    public void testLog1() {
        logThings();
    }

    @Test
    public void testLog2() {
        logThings();
    }

    public void logThings() {
        logger.info("info message");
        logger.debug("debug message");
        logger.warn("warn message");
    }
}

如果您已经使用滚动文件附加器免费获得 MDC 日志记录,那么 Log4j 2 似乎会更加强大。

无论如何,您的 log4j 片段看起来很奇怪。我们看到了结束附加程序元素标签,但没有看到其相应的开始附加程序标签。

您的滚动文件附加程序名称似乎在动态测试名称和测试开始时间之间有一个空格。

fileName="目标/日志/${ctx:suiteTimestamp}/${ctx:testName (${ctx:testStartTime}).log"

建议: 分而治之怎么样?

如果确实支持这种类型的动态配置。 为什么不尝试首先使用动态模式仅配置文件名?

在获得最简单的配置来解决您的问题之前,您似乎已经对 log4j 配置进行了全面的强化。

因此,抓住机会,专注于获得: fileName="target/logs/dummyTest_dynamicComponent_${ctx:testName}.log"

为你工作。

在 log4j 1.x 版本中,您将拥有 log4j.debug 系统属性来帮助您找出错误配置,并且输出非常有用。

最后,在 log4j 1.X 版本上,您想要使用的功能需要您显式地编写自己的 MDC 附加程序。 您的 MDC 附加程序通常会实例化 RollingFileAppenders 以登录文件,并且您将利用用户放置的 MDC 上下文 (keyxValue) 对。

但是您正在做的事情看起来很有希望,如果它不适合您,只需降低配置的复杂程度即可。

最后,如果您在出现以下错误时看到创建任何日志文件,我会感到非常惊讶:

错误无法调用类中的工厂方法 元素的 org.apache.logging.log4j.core.appender.RollingFileAppender 滚动文件。无法创建 RollingFile 类型的 Appender。

Log4j 告诉你: 嘿,你正在定义的那个附加程序。我的工厂尝试使用此配置无法处理它,并且我不会使用此配置实例化滚动文件附加程序。

所以你必须修复该配置。


添加到答案。

这里有一个可用的 Log4j 2 配置来执行您想要的操作:

第一个片段是 log4j 2 配置,您将看到根记录器有 3 个不同的附加程序可供使用。 您最关心的是附加程序 3,但其他两个附加程序更多是您的典型起点。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <!-- APPENDER 1: CONSOLE -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <!-- APPENDER 2: ROLLING FILE -->
        <RollingFile name="AppenderTwo" fileName="target/logs/test.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
        </RollingFile>

        <!-- APPENDER 3: ROUTING APPENDER -->
        <Routing name="AppenderThree">
            <Routes pattern="${ctx:stackOverFlow}">
                <!-- Route Nr.1 -->
                <Route>
                    <!-- Rolling file appender for route Nr.1 -->
                    <RollingFile name="NestedAppender-${ctx:stackOverFlow}" fileName="target/logs/test_threadContext_${ctx:stackOverFlow}.log"
                        filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
                        <PatternLayout>
                            <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                        </PatternLayout>
                        <Policies>
                            <TimeBasedTriggeringPolicy />
                            <SizeBasedTriggeringPolicy size="10 MB" />
                        </Policies>
                    </RollingFile>
                </Route>

                <!-- Route Nr.2 fallback -->
                <!-- By having this set to ${ctx:filename} it will match when filename is not set in the context -->
                <Route ref="Console" key="${ctx:stackOverFlow}" />
            </Routes>
        </Routing>


    </Appenders>
    <Loggers>
        <Root level="all">
            <AppenderRef ref="Console" />
            <AppenderRef ref="AppenderTwo" />
            <AppenderRef ref="AppenderThree" />
        </Root>

    </Loggers>
</Configuration>

最后一个附加程序是基于以下线程配置的:https://issues.apache.org/jira/browse/LOG4J2-129 https://issues.apache.org/jira/browse/LOG4J2-129

第二个片段是一个虚拟的 junit 测试,当您从基本原型创建一个新的 Maven 项目时,您可以从 Eclipse 中获得该测试。您将在测试片段中看到堆栈溢出上下文上下文被设置到线程上下文中,就像您在片段中所做的那样。

package stackoverflow.test.tutorial;

import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest extends TestCase {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestCase.class);

    /**
     * Create the test case
     *
     * @param testName
     *            name of the test case
     */
    public AppTest(String testName) {
        super(testName);
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite() {
        return new TestSuite(AppTest.class);
    }

    /**
     * Rigourous Test :-)
     */
    public void testApp() {
        ThreadContext.put("stackOverFlow", "dummyContextValue");
        LOGGER.info("LALAL LLA");
        assertTrue(true);
    }
}

最后一个片段是 Maven 依赖项:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>stackoverflow.test</groupId>
  <artifactId>tutorial</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>tutorial</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
   <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.12</version>    
  </dependency>  
    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.5</version>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.5</version>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.5</version>
</dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

我觉得 log4j 引入这个新的 Routing Appender 很有趣。如果您可以想象有多少人必须使用 MDC 上下文支持来实现自己的滚动文件追加器才能完成此类工作。 它在网络应用程序中非常有用。

Cheers.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SLF4j 与 Log4j2 错误无法调用元素 RollingFile 的类 ...RollingFileAppender 中的工厂方法 的相关文章

  • Netbeans 8.1 Gnome 3 GTK+ UI 字体和选项卡高度

    我刚刚在运行 GNOME 3 桌面的 Ubuntu 16 04 上安装了 NetBeans 8 1 如果可能的话 我想继续使用 IDE 的 GTK 外观和感觉 但 UI 上的字体 尤其是选项卡中的字体 太小且重叠 我尝试添加 fontsiz
  • 带路径压缩算法的加权 Quick-Union

    有一种 带路径压缩的加权快速联合 算法 代码 public class WeightedQU private int id private int iz public WeightedQU int N id new int N iz new
  • java中监视目录变化

    我正在使用 WatchService 来监视目录中的更改 特别是目录中新文件的创建 下面是我的代码 package watcher import java nio file import static java nio file Stand
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • 如何在 Java 中向时间戳添加/减去时区偏移量?

    我正在使用 JDK 8 并且玩过ZonedDateTime and Timestamp很多 但我仍然无法解决我面临的问题 假设我得到了格式化的Timestamp在格林威治标准时间 UTC 我的服务器位于某处 假设它设置为Asia Calcu
  • 从 MATLAB 调用 Java?

    我想要Matlab程序调用java文件 最好有一个例子 需要考虑三种情况 Java 内置库 也就是说 任何描述的here http docs oracle com javase 6 docs api 这些项目可以直接调用 例如 map ja
  • 将巨大的模式编译成Java

    有两个主要工具提供了将 XSD 模式编译为 Java 的方法 xmlbeans 和 JAXB 问题是 XSD 模式确实很大 30MB 的 XML 文件 大部分模式在我的项目中没有使用 所以我可以注释掉大部分代码 但这不是一个好的解决方案 目
  • Runtime.exec 处理包含多个空格的参数

    我怎样才能进行以下运行 public class ExecTest public static void main String args try Notice the multiple spaces in the argument Str
  • Mockito 使用 @Mock 时将 Null 值注入到 Spring bean 中?

    由于我是 Spring Test MVC 的新手 我不明白这个问题 我从以下代码中获取了http markchensblog blogspot in search label Spring http markchensblog blogsp
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • 如何在字段值无效的情况下更改 Struts2 验证错误消息?

    我在 Web 表单上使用 Struts2 验证 如果字段假设为整数或日期 则
  • 如何使用 JMagick 转换色彩空间?

    如何使用 JMagick API 转换色彩空间 例如 CMYK gt RGB 和 RGB gt CMYK None
  • Jetty、websocket、java.lang.RuntimeException:无法加载平台配置器

    我尝试在 Endpoint 中获取 http 会话 我遵循了这个建议https stackoverflow com a 17994303 https stackoverflow com a 17994303 这就是我这样做的原因 publi
  • 如何将 HTML 链接放入电子邮件正文中?

    我有一个可以发送邮件的应用程序 用 Java 实现 我想在邮件中放置一个 HTML 链接 但该链接显示为普通字母 而不是 HTML 链接 我怎样才能将 HTML 链接放入字符串中 我需要特殊字符吗 太感谢了 Update 大家好你们好 感谢
  • Java Swing - 如何禁用 JPanel?

    我有一些JComponents on a JPanel我想在按下 开始 按钮时禁用所有这些组件 目前 我通过以下方式显式禁用所有组件 component1 setEnabled false 但是有什么办法可以一次性禁用所有组件吗 我尝试禁用
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • 手动设置Android Studio的JDK路径

    如何为 Android Studio 使用自定义 JDK 路径 我不想弄乱 PATH 因为我没有管理员权限 是否有某个配置设置文件允许我进行设置 如果您查看项目设置 您可以从那里访问 jdk 在标准 Windows 键盘映射上 您可以在项目
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • Java RMI - 客户端超时

    我正在使用 Java RMI 构建分布式系统 它必须支持服务器丢失 如果我的客户端使用 RMI 连接到服务器 如果该服务器出现故障 例如电缆问题 我的客户端应该会收到异常 以便它可以连接到其他服务器 但是当服务器出现故障时 我的客户端什么也
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp

随机推荐