debug.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. """
  2. Extensions for debugging Scrapy
  3. See documentation in docs/topics/extensions.rst
  4. """
  5. import sys
  6. import signal
  7. import logging
  8. import traceback
  9. import threading
  10. from pdb import Pdb
  11. from scrapy.utils.engine import format_engine_status
  12. from scrapy.utils.trackref import format_live_refs
  13. logger = logging.getLogger(__name__)
  14. class StackTraceDump(object):
  15. def __init__(self, crawler=None):
  16. self.crawler = crawler
  17. try:
  18. signal.signal(signal.SIGUSR2, self.dump_stacktrace)
  19. signal.signal(signal.SIGQUIT, self.dump_stacktrace)
  20. except AttributeError:
  21. # win32 platforms don't support SIGUSR signals
  22. pass
  23. @classmethod
  24. def from_crawler(cls, crawler):
  25. return cls(crawler)
  26. def dump_stacktrace(self, signum, frame):
  27. log_args = {
  28. 'stackdumps': self._thread_stacks(),
  29. 'enginestatus': format_engine_status(self.crawler.engine),
  30. 'liverefs': format_live_refs(),
  31. }
  32. logger.info("Dumping stack trace and engine status\n"
  33. "%(enginestatus)s\n%(liverefs)s\n%(stackdumps)s",
  34. log_args, extra={'crawler': self.crawler})
  35. def _thread_stacks(self):
  36. id2name = dict((th.ident, th.name) for th in threading.enumerate())
  37. dumps = ''
  38. for id_, frame in sys._current_frames().items():
  39. name = id2name.get(id_, '')
  40. dump = ''.join(traceback.format_stack(frame))
  41. dumps += "# Thread: {0}({1})\n{2}\n".format(name, id_, dump)
  42. return dumps
  43. class Debugger(object):
  44. def __init__(self):
  45. try:
  46. signal.signal(signal.SIGUSR2, self._enter_debugger)
  47. except AttributeError:
  48. # win32 platforms don't support SIGUSR signals
  49. pass
  50. def _enter_debugger(self, signum, frame):
  51. Pdb().set_trace(frame.f_back)