[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:
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user