2009-06-23 2 views
26

Я пытаюсь вывести список всех активных потоков, включая текущий стек каждого. Я могу получить список всех потоков, используя threading.enumerate(), но я не могу найти способ добраться до стека оттуда.Dump stacktraces всех активных потоков

Справочная информация. Приложение Zope/Plone изредка израсходует время от времени, потребляя 100% от процессора и его необходимо перезапустить. У меня такое чувство, что это цикл, который не заканчивается должным образом, но я не могу воспроизвести его в тестовой среде для проверки. Мне удалось зарегистрировать обработчик сигналов, который может запускаться извне, поэтому я могу запустить некоторый код, как только ситуация повторится. Если бы я мог сбросить стек для всех активных потоков, это дало бы мне понять, что происходит не так. Отверстие вещь работает на Python 2.4 ...

Любые идеи о том, как отслеживать вниз ситуации, как они оценили :)

Приветствия, Chriss

ответ

8

При использовании Zope, вы хотите установить Products.signalstack или mr.freeze; они были предназначены именно для этой цели!

Отправьте сигнал USR1 на ваш сервер Zope и немедленно удалите трассировки стека для всех потоков на консоль. Он сделает это, даже если все потоки Zope заблокированы.

Под капотом эти пакеты косвенно используют threadframes; для версий 2.5 и выше для Python, когда не с использованием Zope, вы можете создать ту же функциональность, используя функцию sys._current_frames() для доступа к кадрам стека в потоке.

Начиная с Zope 2.12.5 эта функциональность интегрирована в Zope, и больше нет необходимости устанавливать дополнительные пакеты.

+0

Большое спасибо, это именно то, что мне нужно! – Chriss

+0

В настоящее время в Plone «никаких специальных пакетов не требуется» http: // stackoverflow.com/a/36633215/3046069 – Danimal

+0

@ Даниал: спасибо, добавлен в сообщение. 2.12.5 был выпущен через год после того, как я написал этот ответ. –

0

Существует применимый рецепт на ASPN. Вы можете использовать threading.enumerate() для получения всех тидов, а затем просто вызовите _async_raise() с некоторым подходящим исключением, чтобы заставить трассировку стека.

35

Как указано в более раннем ответе, sys._current_frames() дает вам то, что вам нужно для v2.5 +. Для ленивых следующий фрагмент кода работал для меня, и может помочь вам:

print >> sys.stderr, "\n*** STACKTRACE - START ***\n" 
code = [] 
for threadId, stack in sys._current_frames().items(): 
    code.append("\n# ThreadID: %s" % threadId) 
    for filename, lineno, name, line in traceback.extract_stack(stack): 
     code.append('File: "%s", line %d, in %s' % (filename, 
                lineno, name)) 
     if line: 
      code.append(" %s" % (line.strip())) 

for line in code: 
    print >> sys.stderr, line 
print >> sys.stderr, "\n*** STACKTRACE - END ***\n" 
13

Для Python 3.3 и более поздних версиях есть faulthandler.dump_traceback().

Приведенный ниже код дает аналогичный результат, но включает имя потока и может быть расширен для печати дополнительной информации.

for th in threading.enumerate(): 
    print(th) 
    traceback.print_stack(sys._current_frames()[th.ident]) 
    print() 
1

Просто для полноты, Products.LongRequestLogger супер полезно для выявления узких мест, и сделать так отвалов stacktraces через определенные промежутки времени.

Смежные вопросы