diff --git a/README.rst b/README.rst index 687ec17..25431a9 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,27 @@ trio-monitor Welcome to `trio-monitor `__! -A monitor utility for Trio +A monitor utility for Trio. License: Your choice of MIT or Apache License 2.0 + + +Basic usage +=========== + +Monitor has a context manager interface: + +.. code:: python + + import trio_monitor + + async with trio.open_nursery() as nursery: + nursery.start_soon(trio_monitor.serve) + +Now from a separate terminal it is possible to connect to the application:: + + $ nc localhost 14761 + +or using the included python client:: + + $ python -m trio_monitor diff --git a/trio_monitor/__init__.py b/trio_monitor/__init__.py index 9a09720..69bd632 100644 --- a/trio_monitor/__init__.py +++ b/trio_monitor/__init__.py @@ -1,3 +1,6 @@ """Top-level package for trio-monitor.""" from ._version import __version__ + + +from .monitor import Monitor, serve \ No newline at end of file diff --git a/trio_monitor/__main__.py b/trio_monitor/__main__.py new file mode 100644 index 0000000..71dda48 --- /dev/null +++ b/trio_monitor/__main__.py @@ -0,0 +1,3 @@ +from .monitor import main + +main() \ No newline at end of file diff --git a/trio_monitor/monitor.py b/trio_monitor/monitor.py index d2a1a5d..32e9351 100644 --- a/trio_monitor/monitor.py +++ b/trio_monitor/monitor.py @@ -9,17 +9,20 @@ from async_generator._impl import ANextIter -from trio import Queue, WouldBlock, BrokenStreamError +from trio import Queue, WouldBlock, BrokenStreamError, serve_tcp from trio._highlevel_serve_listeners import _run_handler from ._version import __version__ from trio.abc import Instrument -from trio.hazmat import current_task, Task +from trio.hazmat import current_task, Task, add_instrument, remove_instrument # inspiration: https://github.com/python-trio/trio/blob/master/notes-to-self/print-task-tree.py # additional credit: python-trio/trio#429 (You are being ratelimited) +DEFAULT_PORT = 14761 + + def walk_coro_stack(coro): while coro is not None: if hasattr(coro, "cr_frame"): @@ -136,6 +139,13 @@ async def listen_on_stream(self, stream): """ return await self.main_loop(stream) + async def serve(self, port=None): + """Serve the monitor over a TCP socket. + """ + await serve_tcp( + self.listen_on_stream, + DEFAULT_PORT if port is None else port) + async def main_loop(self, stream): """Runs the main loop of the monitor. """ @@ -354,6 +364,18 @@ def magic(self, *args): del _patch_monitor +async def serve(port=None): + """Will create a monitor, register it as an instrument with trio, and serve + the monitor on `port`. + """ + monitor = Monitor() + remove_instrument(monitor) + try: + await monitor.serve(port=port) + finally: + remove_instrument(monitor) + + def main(): import argparse import telnetlib @@ -366,7 +388,7 @@ def main(): help="The address to connect to" ) parser.add_argument( - "-p", "--port", default=14761, help="The port to connect to" + "-p", "--port", default=DEFAULT_PORT, help="The port to connect to" ) args = parser.parse_args()