diff --git a/NOTICE b/NOTICE index 08f183ab..5c75f0ce 100644 --- a/NOTICE +++ b/NOTICE @@ -4,4 +4,35 @@ Gunicorn 2009,2010 (c) Paul J. Davis Gunicorn is released under the MIT license. See the LICENSE -file for the complete license. \ No newline at end of file +file for the complete license. + + +gunicorn.debug +-------------- + +Based on eventlet.debug module under MIT license: + +Unless otherwise noted, the files in Eventlet are under the following MIT license: + +Copyright (c) 2005-2006, Bob Ippolito +Copyright (c) 2007-2010, Linden Research, Inc. +Copyright (c) 2008-2010, Eventlet Contributors (see Eventlet AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/gunicorn/config.py b/gunicorn/config.py index 8a7171de..e09f8cda 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -27,6 +27,7 @@ class Config(object): loglevel='info', pidfile=None, proc_name = None, + spew=False, timeout=30, tmp_upload_dir=None, umask="0", diff --git a/gunicorn/debug.py b/gunicorn/debug.py new file mode 100644 index 00000000..0d923d28 --- /dev/null +++ b/gunicorn/debug.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 - +# +# This file is part of gunicorn released under the MIT license. +# See the NOTICE for more information. + +"""The debug module contains utilities and functions for better +debugging Gunicorn.""" + +import os +import sys +import linecache +import re +import inspect + +__all__ = ['spew', 'unspew'] + +_token_spliter = re.compile('\W+') + + + +class Spew(object): + """ + """ + def __init__(self, trace_names=None, show_values=True): + self.trace_names = trace_names + self.show_values = show_values + + def __call__(self, frame, event, arg): + if event == 'line': + lineno = frame.f_lineno + if '__file__' in frame.f_globals: + filename = frame.f_globals['__file__'] + if (filename.endswith('.pyc') or + filename.endswith('.pyo')): + filename = filename[:-1] + name = frame.f_globals['__name__'] + line = linecache.getline(filename, lineno) + else: + name = '[unknown]' + try: + src = inspect.getsourcelines(frame) + line = src[lineno] + except IOError: + line = 'Unknown code named [%s]. VM instruction #%d' % ( + frame.f_code.co_name, frame.f_lasti) + if self.trace_names is None or name in self.trace_names: + print '%s:%s: %s' % (name, lineno, line.rstrip()) + if not self.show_values: + return self + details = [] + tokens = _token_spliter.split(line) + for tok in tokens: + if tok in frame.f_globals: + details.append('%s=%r' % (tok, frame.f_globals[tok])) + if tok in frame.f_locals: + details.append('%s=%r' % (tok, frame.f_locals[tok])) + if details: + print "\t%s" % ' '.join(details) + return self + + +def spew(trace_names=None, show_values=False): + """Install a trace hook which writes incredibly detailed logs + about what code is being executed to stdout. + """ + sys.settrace(Spew(trace_names, show_values)) + + +def unspew(): + """Remove the trace hook installed by spew. + """ + sys.settrace(None) + + diff --git a/gunicorn/main.py b/gunicorn/main.py index a55ac750..7afada6d 100644 --- a/gunicorn/main.py +++ b/gunicorn/main.py @@ -10,6 +10,7 @@ import pkg_resources import sys from gunicorn.config import Config +from gunicorn.debug import spew from gunicorn import util, __version__ LOG_LEVELS = { @@ -51,7 +52,9 @@ def options(): op.make_option('--log-file', dest='logfile', help='Log to a file. - equals stdout. [-]'), op.make_option('-d', '--debug', dest='debug', action="store_true", - default=False, help='Debug mode. only 1 worker.') + default=False, help='Debug mode. only 1 worker.'), + op.make_option('--spew', dest='spew', action="store_true", + default=False, help="Install a trace hook") ] def configure_logging(opts): @@ -114,6 +117,8 @@ def main(usage, get_app): app = get_app(parser, opts, args) conf = Config(opts.__dict__, opts.config) + if conf['spew']: + spew() arbiter = conf.arbiter(conf.address, conf.workers, app, config=conf, debug=conf['debug'], pidfile=conf['pidfile']) if conf['daemon']: @@ -149,6 +154,8 @@ def paste_server(app, global_conf=None, host="127.0.0.1", port=None, options['default_proc_name'] = options['__file__'] conf = Config(options) + if conf['spew']: + spew() arbiter = conf.arbiter(conf.address, conf.workers, app, debug=conf["debug"], pidfile=conf["pidfile"], config=conf) if conf["daemon"] :