Commit 8a55cb19 authored by Łukasz Nowak's avatar Łukasz Nowak

Include DeadlockDebugger by Florent Guillaume

Original version available at:
http://www.zope.org/Members/nuxeo/Products/DeadlockDebugger

Is not developed anymore. Produced replacements (z3c.deadlockdebugger)
are not working on enough low level and fail to work in on busy Zope
nodes.

This version will be capable of reading configuration from zope.conf.
parent d409eba6
This diff is collapsed.
================
DeadlockDebugger
================
*$Id: README.txt,v 1.1 2005/02/23 15:35:21 fguillaume Exp $*
This product adds a hook so that a deadlocked Zope process can be
debugged, by dumping a traceback of all running python processes. The
dump is sent to the event log (at the DEBUG level) and returned to the
browser (even though the Zope is deadlocked and doesn't answer any
other requests!).
DeadlockDebugger can of course also be used in non-deadlock situations,
when a Zope process is taking a long time and you wish to know what code
is being executed.
Installation
------------
This product requires the 'threadframe' python module
(http://www.majid.info/mylos/stories/2004/06/10/threadframe.html).
When DeadlockDebugger starts, it verifies that threadframe is available,
please check the event.log for ERROR message.
Configuration
-------------
You must edit the file custom.py for your needs. You have to change
ACTIVATED to True, and change SECRET. You may change the URL that's
intercepted by the hook to do the dump.
Usage
-----
The standard way to call it is to go to the URL::
http://yourzopesite:8080/manage_debug_threads?yoursecret
This will return a dump, and also send this dump to the event log.
A secret is needed because Zope doesn't do any access control on the URL
(it is intercepted too early), and the thread traceback dump may return
sensitive information about the requests being executed. If you know
your Zope will only be accessed by authorized persons anyway, you can
set SECRET to the empty string, and just call::
http://yourzopesite:8080/manage_debug_threads
In any case you should filter out 'manage_debug_threads' in your
front-end proxy.
Credits
-------
This product is sponsored by Nuxeo <http://nuxeo.com>.
Please contact Florent Guillaume <fg@nuxeo.com> for problems.
You can use the zope@zope.org mailing-list to discuss this product.
# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
# Author: Florent Guillaume <fg@nuxeo.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# $Id: __init__.py,v 1.1 2005/02/23 15:35:21 fguillaume Exp $
"""Debug running threads
This adds a ZServer hook so that if a special URL is called, a full dump
with tracebacks of the running python threads will be made.
You MUST configure the file custom.py before use.
"""
import custom
from zLOG import LOG, INFO, ERROR
try:
import threadframe
except ImportError:
LOG('DeadlockDebugger', ERROR, "Incorrectly installed threadframe module")
else:
if not custom.ACTIVATED:
LOG('DeadlockDebugger', INFO,
"Not activated, you must change ACTIVATED in custom.py")
elif custom.SECRET == 'secret':
LOG('DeadlockDebugger', ERROR,
"Not activated, you must change SECRET in custom.py")
else:
import dumper
LOG('DeadlockDebugger', INFO, "Installed")
# Customize this file for your specific configuration.
# You *must* change ACTIVATED and SECRET.
#
# The URL to use for the dump is DUMP_URL?SECRET
# If SECRET is empty, DUMP_URL is enough.
#
# *** NOTE ABOUT SECURITY ***
#
# No Zope access control is done on this URL, as it is interpreted
# before the Zope application server comes into play. That's why you
# should change the secret or filter this URL before it gets to Zope,
# for instance in Apache.
ACTIVATED = False
SECRET = 'secret' # you must change this
DUMP_URL = '/manage_debug_threads'
# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
# Author: Florent Guillaume <fg@nuxeo.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# $Id: dumper.py,v 1.1 2005/02/23 15:35:21 fguillaume Exp $
"""Debug running threads
ZServer hook to dump a traceback of the running python threads.
"""
import thread
import threadframe
import traceback
import time
from cStringIO import StringIO
from zLOG import LOG, DEBUG
import custom
def dump_threads():
"""Dump running threads
Returns a string with the tracebacks.
"""
frames = threadframe.dict()
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' and
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)
dump_url = custom.DUMP_URL
if custom.SECRET:
dump_url += '?'+custom.SECRET
def match(self, request):
uri = request.uri
# added hook
if uri == dump_url:
dump = dump_threads()
request.channel.push('HTTP/1.0 200 OK\nContent-Type: text/plain\n\n')
request.channel.push(dump)
request.channel.close_when_done()
LOG('DeadlockDebugger', DEBUG, dump)
return 0
# end hook
if self.uri_regex.match(uri):
return 1
else:
return 0
from ZServer.HTTPServer import zhttp_handler
zhttp_handler.match = match
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