【问题标题】:NullpointerException for console appender for Log4j2用于 Log4j2 的控制台附加程序的 NullpointerException
【发布时间】:2017-11-23 14:23:26
【问题描述】:

我的应用程序日志记录在测试中的 maven 构建期间崩溃。这是我在 src/test/resources 中的 log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="MyApp: %d{yyyy-MM-dd HH:mm:ss,SSS} %5p [%t] %c{1.} - %m%n" />
        </Console>
    </Appenders>

    <Loggers>
        <Logger name="com.my.app" level="info" additivity="false">
            <Appender-ref ref="stdout"/>
        </Logger>
        <Root level="error">
            <Appender-ref ref="stdout"/>
        </Root>
    </Loggers>
</Configuration>

我在构建期间的测试期间遇到了这个异常:

2017-11-23 15:12:28,371 main ERROR An exception occurred processing Appender stdout java.lang.NullPointerException
    at org.apache.logging.log4j.core.impl.ThrowableProxy.toExtendedStackTrace(ThrowableProxy.java:671)
    at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:138)
    at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:122)
    at org.apache.logging.log4j.core.impl.Log4jLogEvent.getThrownProxy(Log4jLogEvent.java:566)
    at org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter.format(ExtendedThrowablePatternConverter.java:64)
    at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:38)
    at org.apache.logging.log4j.core.layout.PatternLayout$PatternSerializer.toSerializable(PatternLayout.java:333)
    at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:232)
    at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:217)
    at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:57)
    at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:177)
    at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:170)
    at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:161)
    at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
    at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
    at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
    at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
    at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:448)
    at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:433)
    at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
    at org.apache.logging.log4j.core.config.LoggerConfig.logParent(LoggerConfig.java:439)
    at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:434)
    at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
    at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:403)
    at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:63)
    at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:146)
    at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2116)
    at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2100)
    at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1994)
    at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1966)
    at org.apache.logging.slf4j.Log4jLogger.error(Log4jLogger.java:319)
    at com.my.app.MyTest.testingMyApp(MyTest.java:89)
    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:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

这是我的 pom:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jul</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jcl</artifactId>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
    <groupId>org.dblock.log4jna</groupId>
    <artifactId>log4jna-api</artifactId>
</dependency>

log4j的版本是2.9.1

有趣的是,它会记录到控制台,例如当 spring 应用程序启动时,我可以看到来自 MyApplication.java 的日志,其中有 @SpringBootApplication 注释。

而 MyTest.java:89 是:

logger.error("error occured",e);

记录器来自:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

所以看起来它在错误日志期间崩溃了,但如果我记录正常信息就没有问题。

那么这个空指针是什么?

【问题讨论】:

  • 你能发布你的类 com.my.app.MyTest 的代码吗?
  • 没什么特别的,这是我有一个错误记录代码的地方:logger.error("error occurred", e)

标签: java maven log4j2 appender consoleappender


【解决方案1】:

好的,我想通了:这是因为在测试类中我有一个模拟异常。如果我将其更改为从异常中创建新对象,则可以正常工作。

我猜这是报告错误的好选择。

【讨论】:

  • 如何生成这个模拟异常?即使是“模拟”异常也应该有堆栈跟踪
  • org.mockito.Mockito.mock 例如:IncorrectResultSizeDataAccessException exc = mock(IncorrectResultSizeDataAccessException.class);
【解决方案2】:

您作为logger.error("error occured", e); 的参数传递的ExceptionThrowable 没有任何堆栈跟踪(其堆栈跟踪为null),但是您使用的Log4j2 实现尝试访问所述堆栈跟踪并引发此错误。

看源码,the line throwing your error is:

stackLength = stackTrace.length;

意味着stackTrace 变量是null。它是通过throwable.getStackTrace() 从您作为参数传递给的Throwable (Exception) 获得的

logger.error("error occured", e);

至于为什么您的堆栈跟踪为空,这将取决于您使用的 JVM 以及您如何获得所说的异常。它可能会发生,但这绝对不是标准行为。你可以看看this postthis post

【讨论】:

  • 那么它看起来像是 log4j2 中的一个错误
  • 可能。但我认为异常具有空堆栈跟踪不是正常行为。来自文档:a virtual machine that has no stack trace information concerning this thread is permitted to return a zero-length array from this method 所以在最坏的情况下它会返回一个空数组。您仍然可以报告错误,但我会对实际抛出 Throwable 的代码更感兴趣!可以提供吗?
  • Sun JVM 似乎有时会这样做:stackoverflow.com/questions/2411487/…。如果您使用的是 Sun JVM,也许使用标志 -XX:-OmitStackTraceInFastThrow 可以解决您的问题
  • 我在 catch 部分中记录的 try 部分中抛出以下异常:throw new IncorrectResultSizeDataAccessException(EXPECTED_RESULT_SIZE, result);
  • 这个答案应该被接受,而不是 OP 自己的答案。
【解决方案3】:

如果您需要使用 Mockito 创建一个模拟异常,您可以设置 getStackTrace 方法以返回一个空数组 StackTraceElements:

private Throwable logSafeExceptionMock(Class<? extends Throwable> exceptionType) {
  Throwable t = mock(exceptionType);
  when(t.getStackTrace()).thenReturn(new StackTraceElement[0]);
  return t;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-08
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 2013-07-30
    • 2017-08-22
    相关资源
    最近更新 更多