Как создать / выбросить исключение без трассировки стека?

Сегодня я просматривал некоторые журналы и натолкнулся на странную ошибку.

Вот как это выглядит в журнале:

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-дневный период и, похоже, не нанесло никакого вреда системе.

Среда: довольно загруженный веб-сервис, работающий под управлением Tomcat с Java 5.

Я не прошу советов по отладке системы - эти ошибки давно прошли и могут даже никогда не повториться. Меня просто ошарашило то, как можно создать любое исключение (особенно NPE) без трассировки стека?

добавленной

Используемый регистратор является slf4j управляемый Logback пример. Я верю warn метод здесь. Не уверен что 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>

Я вручную отредактировал значения после идентификатора сеанса в журнале, чтобы удалить данные клиента.

5 ответов

Решение

Иногда, особенно когда дело доходит до NullPointers (по моему опыту), jvm может оптимизировать создание и приведение исключений, и трассировка стека теряется (или, вернее, никогда не создается). Я подозреваю, что ваша проблема связана не с некоторыми Java-библиотеками, а с самой JVM.

Если вы добавите этот аргумент при запуске вашего jvm-процесса, вы получите трассировку стека, если мои подозрения верны.

-XX:-OmitStackTraceInFastThrow

Это было задано ранее, смотрите здесь для более подробной информации:

Обратите внимание, что это относится к Sun/ Oracle JVM

  1. Может логи не логи и трассировки стека?
  2. Вот пример того, как исключение не имеет трассировки стека:

    try {
      throw new Exception() {
        @Override
        public synchronized Throwable fillInStackTrace() {
          return null;
        }
      };
    } catch (Exception e) {
      e.printStackTrace();
    }
    

Так что, может быть, это конкретное исключение #fillInStackTrace() переопределено, но все равно странно.

Видеть, что:

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

или же:

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

Вы можете манипулировать с помощью stacktrace.

По этой ссылке трассировка стека не будет напечатана в slf4j до 1.6. Наличие версии выше 1.6 должно решить проблему.

На мой взгляд, существует три возможных виновника:

  1. SLF4J не всегда регистрирует исключения (в предыдущих версиях были ошибки). В зависимости от базовой структуры ведения журналов могут возникнуть другие проблемы с конфигурацией. Возможно, исключение в конце концов имело трассировку стека, просто оно не было зарегистрировано.
  2. Исключение было не настоящим NullPointerException, а скорее другим исключением, которое имело toString() а также fillInStackTrace() переопределенные методы (первый для печати NPE, а второй для пропуска заполнения трассировки стека).
  3. NPE был создан с помощью сериализации (в отличие от обычного конструктора) и по пути потерял трассировку стека.
Другие вопросы по тегам