Извлечение информации о стеке вызовов при ошибках в Python

Раздел: Ошибки -> Обработка исключений

Основные методы получения трассировки стека

Как получить текст трассировки стека для записи в лог или вывода на экран?

Наиболее эффективным способом является использование функции traceback.format_exc() из модуля traceback. Она возвращает отформатированную строку с полной информацией о стеке вызовов на момент исключения. Этот метод предпочтителен, когда требуется сохранить трассировку в переменную, отправить по сети или обработать программно без немедленного вывода в поток.


import traceback

try:
    result = 1 / 0
except ZeroDivisionError:
    tb_string = traceback.format_exc()
    print("Трассировка получена:")
    print(tb_string)

Python ignore error (игнорирование ошибок python)

Пояснение шагов: В блоке try выполняется опасный код. При возникновении исключения блок except перехватывает его. Функция traceback.format_exc() без аргументов берёт текущее исключение из контекста (sys.exc_info()) и возвращает строку, аналогичную выводу print_exc(). После этого строку можно использовать для логирования, записи в файл или вывода в интерфейс.

Типичная ошибка: вызов format_exc() вне блока except или после того, как исключение было обработано. В этом случае возвращается None. Решение: всегда вызывать функцию внутри обработчика исключения или сразу после перехвата.

Цели использования: формирование отчётов об ошибках, запись в лог-файл, отображение в GUI, передача в сторонние сервисы мониторинга.

Как напечатать трассировку в стандартный поток ошибок?

Функция traceback.print_exc() выводит отформатированную трассировку непосредственно в stderr. Это простейший способ для быстрой отладки в консольных приложениях.


import traceback

try:
    with open('missing.txt', 'r') as f:
        pass
except FileNotFoundError:
    traceback.print_exc()

Python exception (исключения в python)

Пояснение: У функции необязательные параметры: limit (количество фреймов), file (поток вывода). По умолчанию вывод идёт в sys.stderr.

Проблема: если поток stderr перенаправлен или скрыт, вывод не будет виден. Решение: использовать format_exc() с явной записью в нужный поток.

Случаи использования: скрипты командной строки, где достаточно вывода ошибок в консоль.

Как получить текущий стек вызовов без исключения?

Для отладки в произвольном месте программы применяется traceback.print_stack(). Она выводит стек вызовов на момент вызова, не требуя исключения.


import traceback

def a():
    b()

def b():
    traceback.print_stack()

a()

исключения в python инструкция try except (обработка исключений try except в python)

Пояснение: Полезна для понимания пути выполнения, отслеживания неожиданных вызовов.

Типичная ошибка: вывод может быть очень длинным в рекурсивных функциях. Решение: используйте параметр limit для ограничения глубины.

Как извлечь структурированную информацию о стеке (файл, строка, имя функции)?

Модуль traceback предоставляет функции extract_tb() и extract_stack(), возвращающие список объектов FrameSummary с атрибутами filename, lineno, name, line. Это удобно для программного анализа.


import traceback
import sys

try:
    x = 1/0
except ZeroDivisionError:
    exc_type, exc_value, exc_tb = sys.exc_info()
    frames = traceback.extract_tb(exc_tb)
    for frame in frames:
        print(f"Файл: {frame.filename}, строка: {frame.lineno}, функция: {frame.name}")

Python errno (обработка ошибки errno в python)

Проблема: если exc_tb равен None (нет стека), extract_tb вернёт пустой список. Решение: проверять наличие traceback.

Как автоматически добавить трассировку в лог-сообщение?

Метод logging.exception() из стандартного модуля logging автоматически включает текущую трассировку стека в лог-сообщение уровня ERROR.


import logging

logging.basicConfig(level=logging.ERROR)
try:
    int('abc')
except ValueError:
    logging.exception('Произошла ошибка преобразования')

Python get traceback (получение трассировки стека в python)

Пояснение: Функция принимает строку сообщения и добавляет форматированную трассировку. Подходит для интеграции с системами логирования.

Ошибка: вызов logging.exception() вне блока except не добавит стек. Решение: применять только при обработке исключения.

Как получить трассировку в многопоточном или асинхронном приложении?

В потоках стандартные функции traceback работают корректно, но для получения стеков всех потоков можно использовать sys._current_frames(). В asyncio исключения в задачах обрабатываются через loop.call_exception_handler() или сбор результатов через task.exception().


import threading
import traceback

def worker():
    try:
        raise RuntimeError("Ошибка в потоке")
    except:
        traceback.print_exc()

thread = threading.Thread(target=worker)
thread.start()
thread.join()

Python except print (обработка исключений с выводом в python)

Для asyncio: исключения внутри корутин перехватываются при await, и можно использовать format_exc() внутри обработчика.


import asyncio
import traceback

async def risky():
    raise ValueError("Асинхронная ошибка")

async def main():
    try:
        await risky()
    except ValueError:
        print(traceback.format_exc())

asyncio.run(main())

Проблема: в asyncio исключения могут быть обёрнуты в Task или Future. Решение: использовать task.exception() и затем форматировать.

Расширенные примеры и нестандартные подходы

Пример 1. Кастомное форматирование с фильтрацией внутренних фреймов

При работе с библиотеками часто требуется исключить из трассировки вызовы самого модуля traceback или стандартных функций. Используем traceback.extract_tb() и создаём список только нужных фреймов.

Пример

import traceback
import sys

def custom_format(exc_info):
    tb = exc_info[2]
    frames = traceback.extract_tb(tb)
    # Оставляем фреймы, не содержащие слова "traceback"
    filtered = [f for f in frames if 'traceback' not in f.filename]
    return ''.join(traceback.format_list(filtered))

try:
    open('nonexistent')
except FileNotFoundError:
    exc_info = sys.exc_info()
    print("Отфильтрованная трассировка:")
    print(custom_format(exc_info))
Отфильтрованная трассировка:
  File "C:/test.py", line 15, in 
    open('nonexistent')

Пример 2. Извлечение трассировки из цепочки исключений (PEP 3134)

Когда исключение возникает в результате другого исключения, Python сохраняет связи через атрибуты __cause__ и __context__. Класс traceback.TracebackException позволяет получить полное дерево.

Пример

import traceback

try:
    try:
        1/0
    except ZeroDivisionError as e:
        raise ValueError("Вторая ошибка") from e
except ValueError as err:
    tbe = traceback.TracebackException.from_exception(err)
    print("Форматированное дерево:")
    print(''.join(tbe.format()))
Форматированное дерево:
Traceback (most recent call last):
  File "C:/test.py", line 4, in 
    1/0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:/test.py", line 6, in 
    raise ValueError("Вторая ошибка") from e
ValueError: Вторая ошибка

Пример 3. Получение стеков всех живых потоков при аварийном сбое

Для отладки зависаний полезно получить трассировку всех потоков. Используем sys._current_frames() и traceback.print_stack() для каждого.

Пример

import sys
import traceback
import threading
import time

def thread_func():
    time.sleep(10)

t = threading.Thread(target=thread_func, name="WorkerThread")
t.start()

# Через секунду получаем стеки всех потоков
time.sleep(1)
print("Текущие стеки вызовов:")
for thread_id, frame in sys._current_frames().items():
    print(f"\nПоток {thread_id}:")
    traceback.print_stack(frame, limit=3)
Текущие стеки вызовов:

Поток 123456:
  File "C:/test.py", line 8, in thread_func
    time.sleep(10)
  ...

Поток 789012:
  File "C:/test.py", line 14, in 
    time.sleep(1)

Пример 4. Анализ трассировки с локальными переменными

Используя inspect.trace() или непосредственное обращение к фрейму, можно получить значения переменных в каждом кадре стека.

Пример

import traceback
import sys
import inspect

def inner(x):
    y = x + 1
    return 1 / y  # будет исключение при y == 0

outer(0)

def outer(a):
    try:
        inner(a)
    except ZeroDivisionError:
        exc_type, exc_value, exc_tb = sys.exc_info()
        frames = inspect.trace()  # возвращает список кортежей (frame, filename, lineno, func, code_context, index)
        for frame_info in frames:
            frame, filename, lineno, func, context, idx = frame_info
            print(f"Функция {func}, строка {lineno}")
            print(f"Локальные переменные: {frame.f_locals}")
Функция inner, строка 5
Локальные переменные: {'x': 0, 'y': 1}
Функция outer, строка 10
Локальные переменные: {'a': 0}

Получение трассировки стека в Python - comments

En
Python get traceback (python)