29 Sep 2016 by dryobates
Debugging code run in webservers like gunicorn is not very convenient. Even less convenient is debugging them running in docker. Pudb can give you comfort like GUI debugger but run in TUI remote environment.
Normally if you want to debug code you put`set_trace` in code (or use some more sophisticated methods like automatic post mortem debugging).
Now if you run gunicorn as a daemon with detached terminal then you have no possibility to see debugging console.
In cases like this you can use remote debuggers like rpdb or winpdb. They all work in the same manner - you start debugging like set_trace and they listen to incoming connections on some port. Then you can connect with telnet.
The best thing with that debuggers is that I can use them even on headless hosts. The bad part is that rpdb (or celery's rdb) has poor console support and winpdb doesn't work with python3.
Today I have tried pudb  and I really liked it. It's the missing chain in evolution between pure console debuggers and GUI debuggers. It's TUI debugger. Just the same like you can remember from the times of Turbo Pascal for DOS!
You can use pudb just like normal pdb using:
import pudb; pu.db
But for remote debugging will try it's other form:
from pudb.remote import set_trace; set_trace(term_size=(160, 40), host='0.0.0.0', port=6900)
Now if you start gunicorn with code that has above line it will stop at this line and listen for connections on given port. You can connect to that port with telnet:
telnet 127.0.0.1 6900
You should see TUI interface and code of your program. If you have started gunicorn with default timeout settings you can enjoy beautiful debugger interface only for 30 seconds ;)
To prevent this just pass longer time out (e.g. 5min.=120s):
gunicorn wsgi -D -b 0.0.0.0:8000 -t 120
So now we can debug code inside gunicorn process even if it's started as daemon. No it's time for adjusting docker-compose. The only thing you have to change is to map ports on which debugger will connect. In docker-compose.yml put:
ports: - "6900:6900"
in container definition.
Now docker-compose up will start your docker and if line with set_trace will execute then you could connect to debugger.