Commit 16796274 authored by Hanno Schlichting's avatar Hanno Schlichting

Integrated the Products.signalstack / z3c.deadlockdebugger packages. You can...

Integrated the Products.signalstack / z3c.deadlockdebugger packages. You can now send a SIGUSR1 signal to a Zope process and get a stack trace of all threads printed out on the console. This works even if all threads are stuck.
parent 1dd67c52
...@@ -83,6 +83,13 @@ Restructuring ...@@ -83,6 +83,13 @@ Restructuring
Features Added Features Added
++++++++++++++ ++++++++++++++
- Integrated the Products.signalstack / z3c.deadlockdebugger packages. You can
now send a SIGUSR1 signal to a Zope process and get a stack trace of all
threads printed out on the console. This works even if all threads are stuck.
- ZCTextIndex query parser treats fullwidth space characters defined
in Unicode as valid white space.
- Updated packages: - Updated packages:
- initgroups = 2.13.0 - initgroups = 2.13.0
...@@ -119,9 +126,6 @@ Features Added ...@@ -119,9 +126,6 @@ Features Added
- zope.traversing = 3.12.0 - zope.traversing = 3.12.0
- zope.viewlet = 3.7.0 - zope.viewlet = 3.7.0
- ZCTextIndex query parser treats fullwidth space characters defined
in Unicode as valid white space.
Bugs Fixed Bugs Fixed
++++++++++ ++++++++++
......
...@@ -18,10 +18,14 @@ $Id$ ...@@ -18,10 +18,14 @@ $Id$
__version__='$Revision: 1.3 $'[11:-2] __version__='$Revision: 1.3 $'[11:-2]
import logging import logging
import sys, os import os
import sys
import Lifetime import Lifetime
from .threads import dump_threads
logger = logging.getLogger("Z2") logger = logging.getLogger("Z2")
if os.name == 'nt': if os.name == 'nt':
...@@ -55,6 +59,13 @@ def restartHandler(): ...@@ -55,6 +59,13 @@ def restartHandler():
logger.info("Restarting") logger.info("Restarting")
Lifetime.shutdown(1) Lifetime.shutdown(1)
def showStacks():
"""Dump a stracktrace of all threads on the console."""
print dump_threads()
sys.stdout.flush()
class LogfileReopenHandler: class LogfileReopenHandler:
"""Reopen log files on SIGUSR2. """Reopen log files on SIGUSR2.
...@@ -104,6 +115,7 @@ def registerZopeSignals(loggers): ...@@ -104,6 +115,7 @@ def registerZopeSignals(loggers):
SignalHandler.registerHandler(SIGINT, shutdownHandler) SignalHandler.registerHandler(SIGINT, shutdownHandler)
if os.name != 'nt': if os.name != 'nt':
SignalHandler.registerHandler(SIGHUP, restartHandler) SignalHandler.registerHandler(SIGHUP, restartHandler)
SignalHandler.registerHandler(SIGUSR1, showStacks)
SignalHandler.registerHandler(SIGUSR2, LogfileReopenHandler(loggers)) SignalHandler.registerHandler(SIGUSR2, LogfileReopenHandler(loggers))
else: else:
# no restart handler on windows. # no restart handler on windows.
......
import sys
import thread
import traceback
import time
from cStringIO import StringIO
def dump_threads():
"""Dump running threads. Returns a string with the tracebacks."""
frames = sys._current_frames()
this_thread_id = thread.get_ident()
now = time.strftime("%Y-%m-%d %H:%M:%S")
res = ["Threads traceback dump at %s\n" % now]
for thread_id, frame in frames.iteritems():
if thread_id == this_thread_id:
continue
# Find request in frame
reqinfo = ''
f = frame
while f is not None:
co = f.f_code
if co.co_name == 'publish':
if co.co_filename.endswith('/ZPublisher/Publish.py'):
request = f.f_locals.get('request')
if request is not None:
reqinfo += (request.get('REQUEST_METHOD', '') + ' ' +
request.get('PATH_INFO', ''))
qs = request.get('QUERY_STRING')
if qs:
reqinfo += '?'+qs
break
f = f.f_back
if reqinfo:
reqinfo = " (%s)" % reqinfo
output = StringIO()
traceback.print_stack(frame, file=output)
res.append("Thread %s%s:\n%s" %
(thread_id, reqinfo, output.getvalue()))
frames = None
res.append("End of dump")
return '\n'.join(res)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment