如何在没有堆栈跟踪的情况下创建/抛出异常?

时间:2014-09-15 08:33:35

标签: java nullpointerexception

我今天在浏览一些日志并遇到了一个奇怪的错误。

以下是它在日志中的显示方式:

2014/09/11 15:23:52.801 [CC3A5FDD16035540B87F1B8C5E806588:<removed>] WARN a.b.c.Ddd - Main failure 
java.lang.NullPointerException: null
2014/09/11 15:23:52.801 [CC3A5FDD16035540B87F1B8C5E806588:<removed>] ...

以及代码的样子:

} catch (Exception e) {
    Ddd.log.warn("Main failure ", e);
    throw e;
}

如果重要的话,代码在jsp中。在日志中再次重复相同的异常(正如您对throw e所期望的那样)。

我没有原因记录 - 日志中的前一行显示了查询的执行情况。这种情况在4天内发生了两次,似乎没有对系统造成任何伤害。

环境:使用Java 5在Tomcat下运行相当繁忙的Web服务。

我不是在询问有关调试系统的提示 - 这些错误已经很久了,甚至可能永远不会再发生。关于如何在没有堆栈跟踪的情况下创建任何异常(尤其是NPE),我感到非常难过?

正在使用的记录器是slf4j驱动的Logback实例。我相信warn方法是here。不确定解析的Logback方法,但我确信Throwable参数是专门处理的,如果有Throwable附加的堆栈跟踪,出现在日志中。

LogBack.xml - 根据要求:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <property name="log.package" value="Package" />
  <property name="log.pattern" value="%date{yyyy/MM/dd HH:mm:ss.SSS} [%X{session}:%X{device}] %level %logger{25} - %msg%n"/> 
  <property name="log.consolePattern" value="%highlight(%-5level) %white(%logger{25}) - %msg%n"/> 
  <if condition='isDefined("catalina.home")'>
    <then>
      <property name="log.dir" value="${catalina.home}/logs" />
    </then>
    <else>
      <property name="log.dir" value="." />
    </else>
  </if>

  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>DEBUG</level>
    </filter>
    <encoder>
      <Pattern>${log.consolePattern}</Pattern>
    </encoder>
  </appender>

  <appender name="rolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${log.dir}/${log.package}.log</file>
    <encoder>
      <Pattern>${log.pattern}</Pattern>
    </encoder>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${log.dir}/${log.package}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <!-- or whenever the file size reaches 16MB. -->
        <maxFileSize>16MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <!-- Keep no more than 3 months data. -->
      <maxHistory>90</maxHistory>
      <cleanHistoryOnStart>true</cleanHistoryOnStart>
    </rollingPolicy>
  </appender>

  <!-- Default logging levels. -->
  <root level="INFO">
    <appender-ref ref="console"/>
    <appender-ref ref="rolling"/>
  </root>
  <!-- Specific logging levels. -->
  <!-- Generally set to INFO or ERROR but if you need more details, set to DEBUG. -->
  <logger name="org.apache" level="INFO"/>
  <logger name="net.sf.ehcache" level="ERROR"/>
  <logger name="com.zaxxer" level="ERROR"/>
  <logger name="ch.qos" level="ERROR"/>
</configuration>

我手动编辑了日志中会话ID之后的值,以删除客户数据。

5 个答案:

答案 0 :(得分:14)

有时候,特别是在涉及NullPointers时(根据我的经验),jvm可以优化异常的创建和转换,并且堆栈跟踪会丢失(或者更准确,永远不会创建)。我怀疑你的问题与某些java库无关,而是与jvm本身有关。

如果你在启动你的jvm-process时添加这个参数,如果我的怀疑是正确的,你将得到你的堆栈跟踪。

-XX:-OmitStackTraceInFastThrow

之前已经询问过,请查看此处了解更多详情:

注意,这适用于sun / oracle jvm

答案 1 :(得分:2)

看到:

    RuntimeException e = new RuntimeException();
    e.setStackTrace(new StackTraceElement[0]);
    ...
    e.printStackTrace();

或:

    RuntimeException e = new RuntimeException();
    e.setStackTrace(new StackTraceElement[0]);
    ...
    throw e;

您可以使用stacktrace进行操作。

答案 2 :(得分:2)

  1. 也许日志不会记录堆栈跟踪?
  2. 以下是异常如何没有堆栈跟踪的示例:

    try {
      throw new Exception() {
        @Override
        public synchronized Throwable fillInStackTrace() {
          return null;
        }
      };
    } catch (Exception e) {
      e.printStackTrace();
    }
    
  3. 所以也许这个特殊的异常是一个被#fillInStackTrace()覆盖的自定义异常,但无论如何都是奇怪的。

答案 3 :(得分:1)

根据这个link,堆栈跟踪不会在1.6之前的slf4j中打印出来。版本大于1.6应该可以解决问题。

答案 4 :(得分:1)

我认为,有三种可能的罪魁祸首:

  1. SLF4J并不总是记录异常(在早期版本中曾经存在一些错误)。根据底层日志记录框架,可能存在其他配置问题。也许这个异常毕竟有一个堆栈跟踪,它只是没有被记录。
  2. 异常不是真正的NullPointerException,而是覆盖toString()fillInStackTrace()方法的不同异常(前者打印NPE,后者跳过填充堆栈跟踪)。
  3. NPE是通过序列化(而不是通常的构造函数)创建的,并且沿途丢失了堆栈跟踪。