Skip to content

Commit

Permalink
Added the "stacktrace" command (#120)
Browse files Browse the repository at this point in the history
* Added the "stacktrace" command

This will be useful for debugging when the event loop thread is stuck.

* Fixed mypy errors
  • Loading branch information
agronholm authored and jettify committed Jul 1, 2018
1 parent b68205d commit e73036c
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Now you can type commands, for instance ``help``::
where taskid : Show stack frames for a task
cancel taskid : Cancel an indicated task
signal signame : Send a Unix signal
stacktrace : Print a stack trace from the event loop thread
console : Switch to async Python REPL
quit : Leave the monitor

Expand Down
13 changes: 13 additions & 0 deletions aiomonitor/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import os
import signal
import socket
import sys
import threading
import traceback
from textwrap import wrap
from typing import IO, Dict, Any, Optional # noqa
from concurrent.futures import Future # noqa
Expand Down Expand Up @@ -38,6 +40,8 @@ def start_monitor(loop: Loop, *,


class Monitor:
_event_loop_thread_id = None # type: int

def __init__(self,
loop: asyncio.AbstractEventLoop, *,
host: str=MONITOR_HOST,
Expand Down Expand Up @@ -72,6 +76,7 @@ def start(self) -> None:

self._started = True
h, p = self._host, self._port
self._event_loop_thread_id = threading.get_ident()
self._ui_thread.start()
if self._console_enabled:
log.info('Starting console at %s:%d', h, p)
Expand Down Expand Up @@ -138,6 +143,9 @@ def _monitor_commans(self, sin: IO[str], sout: IO[str], resp: str) -> None:
_, signame = resp.split()
self._command_signal(sout, signame)

elif resp.startswith('stacktrace'):
self._command_stacktrace(sout)

elif resp.startswith('w'):
_, taskid_s = resp.split()
self._command_where(sout, int(taskid_s))
Expand Down Expand Up @@ -174,6 +182,7 @@ def _command_help(self, sout: IO[str]):
where taskid : Show stack frames for a task
cancel taskid : Cancel an indicated task
signal signame : Send a Unix signal
stacktrace : Print a stack trace from the event loop thread
console : Switch to async Python REPL
quit : Leave the monitor
""")
Expand Down Expand Up @@ -206,6 +215,10 @@ def _command_signal(self, sout: IO[str], signame: str) -> None:
else:
sout.write('Unknown signal %s\n' % signame)

def _command_stacktrace(self, sout: IO[str]) -> None:
frame = sys._current_frames()[self._event_loop_thread_id]
traceback.print_stack(frame, file=sout)

def _command_cancel(self, sout: IO[str], taskid) -> None:
task = task_by_id(taskid, self._loop)
if task:
Expand Down
3 changes: 3 additions & 0 deletions tests/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ def test_basic_monitor(monitor, tn_client, loop):
resp = execute(tn, 'signal name\n')
assert 'Unknown signal name' in resp

resp = execute(tn, 'stacktrace\n')
assert 'loop.run_forever()' in resp

resp = execute(tn, 'wehere 123\n')
assert 'No task 123' in resp

Expand Down

0 comments on commit e73036c

Please sign in to comment.