sapling/hgext3rd/sigtrace.py
Jun Wu 84143416ed sigtrace: new extension provides stack traces on signal
Summary:
Sometimes the hg process gets stuck, and we want to get the stack traces to
learn what it's doing. It's not a big issue if gdb can be used with python
debugging support [1]. However, that feature could not be easily set up on
OS X. This extension will make debugging on OS X easier by providing the
Python stack traces on SIGUSR1.

It's similar to OpenStack's "GuruMeditationReport" feature [2].

Unlike `contrib/showsstack.py`, this extension uses SIGUSR1 instead of SIGQUIT,
and writes to a file, instead of stderr, and prints all threads, instead of
just the current one. So it's more practically useful. We may want to
replace `showstack.py` eventually.

[1]: https://wiki.python.org/moin/DebuggingWithGdb
[2]: https://wiki.openstack.org/wiki/GuruMeditationReport

Test Plan: Added a new test

Reviewers: #sourcecontrol, rmcelroy

Reviewed By: rmcelroy

Subscribers: rmcelroy, mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D4660938

Signature: t1:4660938:1488927878:c751856681816a739160c361ed5cc10bab325000
2017-03-07 17:25:40 -08:00

43 lines
1.1 KiB
Python

# sigtrace.py
#
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""sigtrace - dump stack traces on signal
By default, SIGUSR1 will make hg dump stacks of all threads to /tmp.
Config::
[sigtrace]
signal = USR1
pathformat = /tmp/trace-%(pid)s-%(time)s.log
"""
import os
import signal
import sys
import time
import traceback
pathformat = '/tmp/trace-%(pid)s-%(time)s.log'
def printstacks(sig, currentframe):
content = ''
for tid, frame in sys._current_frames().iteritems():
content += ('Thread %s:\n%s\n'
% (tid, ''.join(traceback.format_stack(frame))))
with open(pathformat % {'time': time.time(), 'pid': os.getpid()}, 'w') as f:
f.write(content)
def uisetup(ui):
global pathformat
pathformat = ui.config('sigtrace', 'pathformat', pathformat)
signame = ui.config('sigtrace', 'signal', 'USR1')
sig = getattr(signal, 'SIG' + signame, None)
if sig is not None:
signal.signal(sig, printstacks)