changeset 674:b4a6bad53f91

Added thread monitor.
author Alexander Schremmer <alex AT alexanderweb DOT de>
date Sun, 21 May 2006 12:41:10 +0200
parents e3b84c7488e8
children 6248f0fbc583
files MoinMoin/action/tm.py MoinMoin/util/thread_monitor.py
diffstat 2 files changed, 113 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/action/tm.py	Sun May 21 12:41:10 2006 +0200
@@ -0,0 +1,32 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - Thread monitor action
+
+    Shows the current traceback of all threads.
+
+    @copyright: 2006 by MoinMoin:AlexanderSchremmer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from MoinMoin.wikiutil import escape
+from MoinMoin.util import thread_monitor
+from StringIO import StringIO
+from time import sleep
+
+def execute(pagename, request):
+    request.http_headers()
+
+    request.theme.send_title("Thread monitor")
+    request.write('<pre>')
+
+    if not thread_monitor.hook_enabled:
+        request.write("Hook is not enabled.")
+    else:
+        s = StringIO()
+        thread_monitor.trigger_dump(s)
+        sleep(5) # allow for all threads to dump to request
+        request.write(escape(s.getvalue()))
+        
+    request.write('</pre>')
+    request.theme.send_footer(pagename)
+    request.theme.send_closing_html()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/util/thread_monitor.py	Sun May 21 12:41:10 2006 +0200
@@ -0,0 +1,81 @@
+"""
+Thread monitor - Check the state of all threads.
+
+Just call activate_hook() as early as possible in program execution.
+Then you can trigger the output of tracebacks of all threads
+by calling trigger_dump().
+
+Copyright: 2006 Alexander Schremmer <alex AT alexanderweb DOT de>
+License: GNU GPL Version 2
+"""
+
+import sys
+import threading
+import traceback
+from time import sleep
+from StringIO import StringIO
+
+try:
+    set
+except:
+    from sets import Set as set
+
+# global state
+dumping = False
+dump_file = None
+dumped = set()
+to_dump = set()
+hook_enabled = False
+
+def dump(label):
+    df = dump_file or sys.stderr
+    s = StringIO()
+    print >>s, "\nDumping thread %s:" % (label, )
+    try:
+        raise ZeroDivisionError
+    except ZeroDivisionError:
+        f = sys.exc_info()[2].tb_frame.f_back.f_back
+    traceback.print_list(traceback.extract_stack(f, None), s)
+    df.write(s.getvalue())
+
+def dump_hook(a, b, c): # arguments are ignored
+    global dumping
+    
+    if dumping and sys.exc_info()[0] is None:
+        thread = threading.currentThread()
+        if thread in to_dump:
+            dump(repr(thread))
+            to_dump.discard(thread)
+            dumped.add(thread)
+            if not to_dump:
+                dumping = False
+
+def trigger_dump(dumpfile=None):
+    """ Triggers the dump of the tracebacks of all threads.
+        If dumpfile is specified, it is used as the output file. """
+    global dumping, dump_file, to_dump
+
+    to_dump = set(threading.enumerate())
+    if dumpfile is not None:
+        dump_file = dumpfile
+    dumping = True
+
+def activate_hook():
+    """ Activates the thread monitor hook. Note that this interferes
+    with any kind of profiler and some debugging extensions. """
+    global hook_enabled
+    
+    sys.setprofile(dump_hook)
+    threading.setprofile(dump_hook)
+    hook_enabled = True
+
+def dump_regularly(seconds):
+    """ Dumps the tracebacks every `seconds` seconds. """
+    activate_hook()
+
+    def background_dumper(seconds):
+        while 1:
+            sleep(seconds)
+            trigger_dump()
+    
+    threading.Thread(target=background_dumper, args=(seconds, )).start()