[IMP] dumpstack dumps greenlets when running in evented mode.

(forward port lost during previous commit)

bzr revid: chs@openerp.com-20131125155956-x92vq9w4r9ov4vcc
This commit is contained in:
Christophe Simonis
2013-11-25 16:59:56 +01:00
parent ab386c0f5f
commit d26e253edd
2 changed files with 49 additions and 27 deletions
+8 -26
View File
@@ -17,7 +17,6 @@ import subprocess
import sys
import threading
import time
import traceback
import werkzeug.serving
@@ -33,7 +32,7 @@ except ImportError:
import openerp
import openerp.tools.config as config
from openerp.release import nt_service_name
from openerp.tools.misc import stripped_sys_argv
from openerp.tools.misc import stripped_sys_argv, dumpstacks
import wsgi_server
@@ -183,25 +182,6 @@ class CommonServer(object):
# runtime
self.pid = os.getpid()
def dumpstacks(self):
""" Signal handler: dump a stack trace for each existing thread."""
# code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
# modified for python 2.5 compatibility
threads_info = dict([(th.ident, {'name': th.name,
'uid': getattr(th,'uid','n/a')})
for th in threading.enumerate()])
code = []
for threadId, stack in sys._current_frames().items():
thread_info = threads_info.get(threadId)
code.append("\n# Thread: %s (id:%s) (uid:%s)" % \
(thread_info and thread_info['name'] or 'n/a',
threadId,
thread_info and thread_info['uid'] or 'n/a'))
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()))
_logger.info("\n".join(code))
def close_socket(self, sock):
""" Closes a socket instance cleanly
@@ -243,9 +223,6 @@ class ThreadedServer(CommonServer):
# restart on kill -HUP
openerp.phoenix = True
self.quit_signals_received += 1
elif sig == signal.SIGQUIT:
# dump stacks on kill -3
self.dumpstacks()
def cron_thread(self, number):
while True:
@@ -295,7 +272,7 @@ class ThreadedServer(CommonServer):
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGCHLD, self.signal_handler)
signal.signal(signal.SIGHUP, self.signal_handler)
signal.signal(signal.SIGQUIT, self.signal_handler)
signal.signal(signal.SIGQUIT, dumpstacks)
elif os.name == 'nt':
import win32api
win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1)
@@ -372,6 +349,10 @@ class GeventServer(CommonServer):
def start(self):
import gevent
from gevent.wsgi import WSGIServer
if os.name == 'posix':
signal.signal(signal.SIGQUIT, dumpstacks)
gevent.spawn(self.watch_parent)
self.httpd = WSGIServer((self.interface, self.port), self.app)
_logger.info('Evented Service (longpolling) running on %s:%s', self.interface, self.port)
@@ -558,9 +539,10 @@ class PreforkServer(CommonServer):
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGHUP, self.signal_handler)
signal.signal(signal.SIGCHLD, self.signal_handler)
signal.signal(signal.SIGQUIT, self.signal_handler)
signal.signal(signal.SIGTTIN, self.signal_handler)
signal.signal(signal.SIGTTOU, self.signal_handler)
signal.signal(signal.SIGQUIT, dumpstacks)
# listen to socket
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+41 -1
View File
@@ -41,6 +41,7 @@ from itertools import islice, izip, groupby
from lxml import etree
from which import which
from threading import local
import traceback
try:
from html2text import html2text
@@ -50,9 +51,10 @@ except ImportError:
from config import config
from cache import *
import openerp
# get_encodings, ustr and exception_to_unicode were originally from tools.misc.
# There are moved to loglevels until we refactor tools.
from openerp.loglevels import get_encodings, ustr, exception_to_unicode
from openerp.loglevels import get_encodings, ustr, exception_to_unicode # noqa
_logger = logging.getLogger(__name__)
@@ -1067,4 +1069,42 @@ def stripped_sys_argv(*strip_args):
return [x for i, x in enumerate(args) if not strip(args, i)]
def dumpstacks(sig, frame):
""" Signal handler: dump a stack trace for each existing thread."""
code = []
def extract_stack(stack):
for filename, lineno, name, line in traceback.extract_stack(stack):
yield 'File: "%s", line %d, in %s' % (filename, lineno, name)
if line:
yield " %s" % (line.strip(),)
# code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
# modified for python 2.5 compatibility
threads_info = dict([(th.ident, {'name': th.name, 'uid': getattr(th, 'uid', 'n/a')})
for th in threading.enumerate()])
for threadId, stack in sys._current_frames().items():
thread_info = threads_info.get(threadId)
code.append("\n# Thread: %s (id:%s) (uid:%s)" %
(thread_info and thread_info['name'] or 'n/a',
threadId,
thread_info and thread_info['uid'] or 'n/a'))
for line in extract_stack(stack):
code.append(line)
if openerp.evented:
# code from http://stackoverflow.com/questions/12510648/in-gevent-how-can-i-dump-stack-traces-of-all-running-greenlets
import gc
from greenlet import greenlet
for ob in gc.get_objects():
if not isinstance(ob, greenlet) or not ob:
continue
code.append("\n# Greenlet: %r" % (ob,))
for line in extract_stack(ob.gr_frame):
code.append(line)
_logger.info("\n".join(code))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: