Как можно создать/выбросить исключение без трассировки стека?
Сегодня я пробирался через некоторые журналы и сталкивался с странной ошибкой.
Вот как он появляется в журнале:
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>
Я вручную отредактировал значения после идентификатора сеанса в журнале, чтобы удалить данные клиента.
Ответы
Ответ 1
Иногда, особенно когда речь заходит о NullPointers (по моему опыту), jvm может оптимизировать создание и отливку исключений, а трассировка стека теряется (или, вернее, никогда не создается). Я подозреваю, что ваша проблема не связана с некоторыми java-библиотеками, а скорее с jvm.
Если вы добавите этот аргумент при запуске jvm-процесса, вы вернете трассировки стека, если мое подозрение верное.
-XX:-OmitStackTraceInFastThrow
Это задано ранее, посмотрите здесь более подробную информацию:
Обратите внимание, что это относится к sun/oracle jvm
Ответ 2
- Возможно, журнал не регистрирует также трассировку стека?
-
Вот пример того, как исключение не имеет трассировки стека:
try {
throw new Exception() {
@Override
public synchronized Throwable fillInStackTrace() {
return null;
}
};
} catch (Exception e) {
e.printStackTrace();
}
Так что, возможно, это особое исключение является обычным с #fillInStackTrace()
переопределенным, но в любом случае это странно.
Ответ 3
Смотрите, что:
RuntimeException e = new RuntimeException();
e.setStackTrace(new StackTraceElement[0]);
...
e.printStackTrace();
или
RuntimeException e = new RuntimeException();
e.setStackTrace(new StackTraceElement[0]);
...
throw e;
Вы можете манипулировать с помощью stacktrace.
Ответ 4
В соответствии с этой ссылкой stacktrace не будет печататься в slf4j до 1.6. Если версия более 1,6 должна решить проблему.
Ответ 5
Как я вижу, есть три возможных виновника:
- SLF4J не всегда регистрирует исключения (раньше в некоторых случаях были ошибки). В зависимости от базовой структуры ведения журнала могут возникать другие проблемы с конфигурацией. Возможно, у исключения была трассировка стека, она просто не была зарегистрирована.
- Исключение было не реальным исключением NullPointerException, а скорее другим исключением, в котором переопределены методы
toString()
и fillInStackTrace()
(первый для печати NPE, а второй - пропускания заполнения трассировки стека).
- NPE был создан через Serialization (в отличие от обычного конструктора) и потерял трассировку стека на этом пути.