7. Debugging

There are a variety of features available to help with debugging in Shrapnel.

7.1. Backdoor

A very powerful feature of Shrapnel is the ability to access a running process via a backdoor. You can telnet to a socket (typically a unix-domain socket) and get a Python prompt. At this point, you can interact with anything in your Shrapnel process.

As an example of something you can do in the backdoor is call coro.where_all(). This will return a dictionary of every coroutine that is running with a string describing the call stack of where that coroutine is currently blocked.

To enable the backdoor, you typically start a backdoor coroutine before starting the event loop with the following code:

import coro.backdoor
coro.spawn(coro.backdoor.serve)

By default this will listen on all IP’s on the lowest port available from 8023 to 8033. This isn’t a very safe or secure thing to do. It’s best to specify a unix-domain socket with the unix_path parameter. See coro.backdoor.serve() for details.

By default, the globals available in a backdoor session is a copy of the globals from your applications __main__ module.

7.2. Stderr Output

Shrapnel provides some functions for printing debug information to stderr. The coro.print_stderr() function will print a string with a timestamp and the thread number. The coro.write_stderr() function writes the string verbatim with no newline.

Shrapnel keeps a reference to the “real” stderr (in saved_stderr) and the print_stderr and write_stderr functions always use the real stderr value. A particular reason for doing this is the backdoor module replaces sys.stderr and sys.stdout, but we do not want debug output to go to the interactive session.

7.3. Exceptions

7.3.1. Tracebacks

As a convenience, Shrapnel has a module for printing stack traces in a condensed format. The coro.tb module has the coro.tb.stack_string() function for printing the current stack, and coro.tb.traceback_string() for getting a traceback in an exception handler.

7.3.2. Exception Notifications

If an exception is raised in a coroutine and is never caught, then Shrapnel will by default display the exception to stderr. If you want to change this behavior, use coro.set_exception_notifier().

7.4. Latency

Shrapnel will keep track of how long a coroutine runs before it yields. This is helpful to track down coroutines which are running for too long, or are potentially calling blocking calls. Here is an example of the output that would be sent to stderr when this happens:

Sat Apr 14 20:55:39 2012 High Latency: (3.884s)
    for <coro #1 name='<function my_func at 0x800fd32a8>'
         dead=0 started=1 scheduled=0 at 0x801424720>

You can change the threshold that will trigger this warning with the coro.set_latency_warning() function. However, doing this to silence warnings isn’t a good idea. It is best to fix whatever code is causing the warnings. You can either call coro.yield_slice() periodically to let other coroutines run, or make sure you are not calling any blocking operations.

7.5. Functions

The coro module defines the following functions: