[Fixed]-How to get coverage data from a django app when running in gunicorn

16đź‘Ť

âś…

coverage gunicorn <params> does not work, because gunicorn creates worker processes, and the coverage module can’t work across forks (basically, creation of new processes). You can use the coverage API, though, for example in the python module that contains your WSGI application:

# wsgi_with_coverage.py
import atexit
import sys
import coverage
cov = coverage.coverage()
cov.start()

from wsgi import application  # adjust to python module containing your wsgi application


def save_coverage():
    print >> sys.stderr, "saving coverage"
    cov.stop()
    cov.save()

atexit.register(save_coverage)

Then run gunicorn -w 1 wsgi_with_coverage:application <other params>.

The problem is, the atexit functions are not called if you kill the gunicorn process, for example via CTRL+C. But they are called on SIGHUP, so if you do kill -HUP $(cat <gunicorn_pidfile_here>), the coverage data should be saved (by default to “.coverage” in the current directory).

A possible caveat is that this won’t work with more than one gunicorn worker, because they would all overwrite the “.coverage” file. If you absolutely need more than one worker, you could write to ".coverage-%d" % os.getpid() (set the file name via the data_file parameter to the coverage constructor) and use the combine() method to merge the individual measurements.

This should work on other WSGI servers, too, depending on whether they allow their worker processes to clean up via the atexit method.

👤sk1p

Leave a comment