Що робить метод printStackTrace()?
printStackTrace() — метод Throwable, який виводить повну інформацію про виняток (тип, повідомлення, стек викликів) у System.err.
Junior Level
Визначення
printStackTrace() — метод Throwable, який виводить повну інформацію про виняток (тип, повідомлення, стек викликів) у System.err.
Приклад
try {
int x = 10 / 0;
} catch (ArithmeticException e) {
e.printStackTrace();
// Вивід: java.lang.ArithmeticException: / by zero
// at com.example.Main.main(Main.java:10)
}
Що він показує
- Тип винятку:
java.lang.ArithmeticException - Повідомлення:
/ by zero - Стек викликів: у якому файлі, методі та рядку сталася помилка
Коли використовувати
- Тільки при налагодженні та прототипуванні, коли вам потрібно швидко побачити стек у консолі без налаштування логера
- Не використовувати у продакшен-коді
ЧОМУ printStackTrace() поганий для production
printStackTrace() — це «сирий» вивід, який:
- Пише в
System.err, а не у ваш лог-файл. У production логи збираються централізовано (ELK, Splunk), аSystem.errможе бути перенаправлений у/dev/nullабо втрачений при перезапуску контейнера - Не додає контекст: немає timestamp, trace ID, імені класу — тільки голий стек. Спробуйте знайти потрібну помилку серед тисяч таких самих
- Розбиває стек на окремі рядки. У Kubernetes кожен рядок
printStackTrace()стає окремим JSON-записом в ElasticSearch — замість одного читабельного логу ви отримуєте 50 розрізнених - Блокує потік —
System.errсинхронізований. При високій навантаженості 100 потоків стоятимуть у черзі на запис
Коли НЕ використовувати printStackTrace()
- Продакшен-код — замінюйте на логер (
log.error("msg", e)) - Багатопоточні додатки —
System.errсинхронізований, створює contention - Веб-додатки — стек у HTTP-відповіді розкриває внутрішню структуру (Security)
- ELK/Splunk інфраструктури —
printStackTrace()розбиває один стек на 50+ окремих JSON-записів - Highload-системи — блокування на
System.errпри заповненому диску/pipe
Middle Level
Чому це працює повільно
1. Синхронізація:
System.err — об’єкт PrintStream. Усі його методи використовують синхронізацію. У багатопоточному додатку 100 потоків чекатимуть блокування.
2. Перетворення нативного стека:
Throwable ліниво перетворює нативний backtrace у масив StackTraceElement[] саме в момент звернення до стеку.
Вивід у рядок
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
Порівняння з логерами
// ПОГАНО — синхронізація, немає контексту, розбиває логи
e.printStackTrace();
// ДОБРЕ — асинхронно, з контекстом, JSON-friendly
log.error("Failed to process order id={}", id, e);
Логери вміють:
- Форматувати стек в один рядок або JSON
- Обрізати занадто довгі стеки
- Додавати інформацію про JAR-файл та версію
- Писати у файл, а не в консоль
Куди він пише насправді
В Kubernetes/Docker System.err перехоплюється і пишеться в JSON-логи. Але printStackTrace() виводить кожен рядок як окремий запис.
Результат: замість одного логу помилки — 50 розрізнених рядків в ElasticSearch.
Senior Level
Standard I/O blocking
Якщо диск переповнений або pipe консолі забитий, printStackTrace() заблокує потік виконання на невизначений час.
Senior Rule: у продакшен-коді printStackTrace() має бути заборонений правилами статичного аналізу (Checkstyle/Sonar).
Circular Causes
При циклічній залежності в cause (хоча initCause це перевіряє), printStackTrace має захист і друкує [CIRCULAR REFERENCE], не йдучи в нескінченну рекурсію.
Security
Стек-трейс у консолі розкриває версії бібліотек та структуру шляхів. У веб-додатках ніколи не віддавайте printStackTrace() у HTTP-відповіді — використовуйте @ControllerAdvice.
Альтернативи
// Програмово отримати стек як рядок
String stackTrace = ExceptionUtils.getStackTrace(e); // Apache Commons
// Логер
log.error("Context message", e); // Logback/Log4j2
// Thread Dumps — якщо додаток завис
// jstack <pid> або jcmd <pid> Thread.print
Діагностика
jstack <pid>— стан усіх моніторів та потоківjcmd <pid> Thread.print— альтернатива jstack- Статичний аналіз — Sonar блокує
printStackTrace()у продакшен-коді - JSON Layout — логи мають бути у форматі JSON для ELK/Splunk
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
printStackTrace()виводить тип, повідомлення та стек викликів винятку вSystem.err- НЕ використовувати в production: пише в
System.err, а не в лог-файл; немає timestamp/trace ID; блокує потік (синхронізація) - В Kubernetes/Docker кожен рядок
printStackTrace()стає окремим JSON-записом в ELK — один стек розбивається на 50+ записів System.err—PrintStreamз синхронізацією; при високій навантаженості потоки стають у чергу- У продакшені замінюйте на
log.error("context", e)— асинхронно, з контекстом, JSON-friendly printStackTrace()захищає від циклічних причин — друкує[CIRCULAR REFERENCE]
Часті уточнюючі запитання:
- Чому printStackTrace() поганий для production? — 4 причини: пише в System.err (не в лог), немає контексту, розбиває стек на рядки, блокує потік
- Як отримати стек як рядок програмово? —
StringWriter+PrintWriterабоExceptionUtils.getStackTrace(e)з Apache Commons - Що відбувається при переповненні диска? —
printStackTrace()заблокує потік на невизначений час, т.к.System.errсинхронізований - Як у Spring уникнути витоку стека в HTTP-відповідь? — Використовувати
@ControllerAdvice, ніколи не віддаватиprintStackTrace()клієнту
Червоні прапорці (НЕ говорити):
- “Використовую printStackTrace() у production — працює” — Втрачаєте логи, блокуєте потоки, розкриваєте структуру коду
- “Різниці між printStackTrace() та логером немає” — Логер додає контекст, форматує, пише у потрібне місце
- “Стек у HTTP-відповіді — нормальна практика” — Розкриває версії бібліотек та структуру шляхів (security vulnerability)
Пов’язані теми:
- [[16. Що таке stack trace]]
- [[18. Як правильно логовати винятки]]
- [[20. Чому не варто ковтати винятки (порожній catch)]]
- [[1. У чому різниця між checked та unchecked exceptions]]
- [[21. Що робить ключове слово throws]]