Created
December 11, 2010 01:09
-
-
Save andymccurdy/737056 to your computer and use it in GitHub Desktop.
Crier: simple introspection for long-running Python processes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pprint | |
import os | |
import sys | |
import threading | |
import time | |
import traceback | |
_crier = None | |
def init_crier(temp_dir='/tmp'): | |
"Initialzies Crier, ensuring it's only created once in the process" | |
global _crier | |
if _crier is None: | |
_crier = Crier(threading.current_thread(), temp_dir=temp_dir) | |
class Crier(object): | |
""" | |
Crier spawns a thread watching for the existence of crier request files | |
in the temp directory. Upon finding a request file, Crier writes a | |
traceback file to the temp directory. Traceback files include a stack trace | |
and a snapshot of local variables for each thread in the process. | |
""" | |
def __init__(self, app_thread, temp_dir='/tmp'): | |
self.app_thread = app_thread | |
self.watch_file = os.path.join(temp_dir, 'crier-%d' % os.getpid()) | |
self.traceback_file = os.path.join(temp_dir, 'dump-%d' % os.getpid()) | |
self.watch_thread = threading.Thread(target=self.watch_thread) | |
self.watch_thread.start() | |
def watch_thread(self): | |
""" | |
Check for dump requests while the thread that initialized | |
Crier is still alive | |
""" | |
while self.app_thread.isAlive(): | |
if self.check_request(): | |
self.write_traceback() | |
time.sleep(1) | |
def check_request(self): | |
""" | |
Checks the temp directory for the existence for a file named | |
'crier-{pid}', where {pid} is the ID of this process. | |
""" | |
if os.path.exists(self.watch_file): | |
os.unlink(self.watch_file) | |
return True | |
return False | |
def write_traceback(self): | |
""" | |
Writes a traceback file to the temp directory named 'traceback-{pid}, | |
where {pid} is the ID of this process. | |
""" | |
tmap = {} | |
main_thread = None | |
# get a map of threads by their ID so we can print their names | |
# during the traceback dump | |
for t in threading.enumerate(): | |
if t.ident: | |
tmap[t.ident] = t | |
else: | |
main_thread = t | |
out = open(self.traceback_file, 'w') | |
# Loop over each thread's current frame, writing info about it | |
for tid, frame in sys._current_frames().iteritems(): | |
thread = tmap.get(tid, main_thread) | |
# no reason to write about Crier's thread. | |
if thread == self.watch_thread: | |
continue | |
out.write('%s\n' % thread.getName()) | |
out.write('========================================\n') | |
traceback.print_stack(frame, file=out) | |
out.write('========================================\n') | |
out.write('LOCAL VARIABLES:\n') | |
out.write('========================================\n') | |
pprint.pprint(frame.f_locals, stream=out) | |
out.write('\n\n') | |
out.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
from crier import init_crier | |
init_crier() | |
def main(): | |
i = 60 | |
while i: | |
time.sleep(1) | |
i -= 1 | |
if __name__ == '__main__': | |
main() | |
######################################################### | |
# assume example.py has a process id of 1234 | |
# | |
# $> touch /tmp/crier-1234 | |
# $> cat /tmp/dump-1234 | |
# MainThread | |
# ======================================== | |
# File "example.py", line 88, in <module> | |
# main() | |
# File "example.py", line 84, in main | |
# time.sleep(1) | |
# ======================================== | |
# LOCAL VARIABLES: | |
# ======================================== | |
# {'i': 34} | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
Can you tell me under what license this code is published?
Thanks!