phusion / passenger

A fast and robust web server and application server for Ruby, Python and Node.js
https://www.phusionpassenger.com/
MIT License
4.99k stars 548 forks source link

Display an error page if a WSGI app raises an exception during request handling #970

Open FooBarWidget opened 10 years ago

FooBarWidget commented 10 years ago

From j.dembicki on April 10, 2013 19:33:26

If wsgi app did not return Content-Type passenger/apache will return only internal server error page. I've been using python module paste to walk around it but it is no longer under active development and incomatibile with python 3.3. Can you make passenger force Content-Type text/html in none is present (for wsgi) so passenger can actualy display error?

Original issue: http://code.google.com/p/phusion-passenger/issues/detail?id=871

FooBarWidget commented 10 years ago

From honglilai on April 10, 2013 14:41:33

Everything seems fine when I don't set Content-Type. I don't get an Internal Server Error on both Apache and Nginx. Although Apache automatically sets the Content-Type to httpd/unix-directory which is rather strange.

Are you on Nginx or Apache? Can you increase its log level and inspect the log files? Maybe it will tell you why it returns Internal Server Error.

FooBarWidget commented 10 years ago

From j.dembicki on April 10, 2013 15:14:05

passenger_wsgi.py:

import site,os site.addsitedir('/home/naox/site-packages') site.addsitedir('/home/naox/rails/djj13') os.environ['LD_LIBRARY_PATH'] = '/usr/local/lib'

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djj13.settings!TYPO_HERE!") import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

I've put !TYPO_HERE! to simulate user typo (syntax error). Passenger/apache only returns "internal server error" page which does not tell ANYTHING to app programer...

Apache error_log has full error, however app programer does not have access to it. Passenger should display this error on webpage (like it does with ruby errors)

[ 2013-04-11 00:09:26.2871 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ pid=18793, time=2013-04-11 00:09:26,286 ]: WSGI application raised an exception! [ 2013-04-11 00:09:26.2871 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] Traceback (most recent call last): [ 2013-04-11 00:09:26.2871 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 132, in init [ 2013-04-11 00:09:26.2871 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] mod = importlib.import_module(self.SETTINGS_MODULE) [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/utils/importlib.py", line 35, in import_module [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] import(name) [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] ImportError: No module named 'djj13.settingsTYPO' [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] During handling of the above exception, another exception occurred: [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ 2013-04-11 00:09:26.2872 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] Traceback (most recent call last): [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/usr/passenger-github-03-04-13/helper-scripts/wsgi-loader.py", line 116, in main_loop [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self.process_request(env, input_stream, client) [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/usr/passenger-github-03-04-13/helper-scripts/wsgi-loader.py", line 235, in process_request [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] result = self.app(env, start_response) [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/core/handlers/wsgi.py", line 236, in call [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self.load_middleware() [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/core/handlers/base.py", line 45, in load_middleware [ 2013-04-11 00:09:26.2873 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] for middleware_path in settings.MIDDLEWARE_CLASSES: [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 53, in getattr [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self._setup(name) [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 48, in _setup [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self._wrapped = Settings(settings_module) [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 134, in init [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)) [ 2013-04-11 00:09:26.2874 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] ImportError: Could not import settings 'djj13.settingsTYPO' (Is it on sys.path?): No module named 'djj13.settingsTYPO' [ 2013-04-11 00:09:26.3675 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ pid=18793, time=2013-04-11 00:09:26,367 ]: WSGI application raised an exception! [ 2013-04-11 00:09:26.3676 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] Traceback (most recent call last): [ 2013-04-11 00:09:26.3676 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 132, in init [ 2013-04-11 00:09:26.3676 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] mod = importlib.import_module(self.SETTINGS_MODULE) [ 2013-04-11 00:09:26.3676 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/utils/importlib.py", line 35, in import_module [ 2013-04-11 00:09:26.3676 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] import(name) [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] ImportError: No module named 'djj13.settingsTYPO' [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] During handling of the above exception, another exception occurred: [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] Traceback (most recent call last): [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/usr/passenger-github-03-04-13/helper-scripts/wsgi-loader.py", line 116, in main_loop [ 2013-04-11 00:09:26.3677 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self.process_request(env, input_stream, client) [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/usr/passenger-github-03-04-13/helper-scripts/wsgi-loader.py", line 235, in ...

FooBarWidget commented 10 years ago

From j.dembicki on April 10, 2013 15:14:05

...process_request [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] result = self.app(env, start_response) [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/core/handlers/wsgi.py", line 236, in call [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self.load_middleware() [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/core/handlers/base.py", line 45, in load_middleware [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] for middleware_path in settings.MIDDLEWARE_CLASSES: [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 53, in getattr [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self._setup(name) [ 2013-04-11 00:09:26.3678 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 48, in _setup [ 2013-04-11 00:09:26.3679 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] self._wrapped = Settings(settings_module) [ 2013-04-11 00:09:26.3679 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] File "/home/naox/site-packages/Django-1.5.1-py3.3.egg/django/conf/init.py", line 134, in init [ 2013-04-11 00:09:26.3679 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)) [ 2013-04-11 00:09:26.3679 9393/4012c940 Pool2/Implementation.cpp:1137 ]: [App 18793 stderr] ImportError: Could not import settings 'djj13.settingsTYPO' (Is it on sys.path?): No module named 'djj13.settingsTYPO'

FooBarWidget commented 10 years ago

From j.dembicki on April 10, 2013 15:24:07

"WSGI application raised an exception!" > send output to the passenger error webpage - not display internal server error. My experience with fastcgi+apache tells me it is probably because wsgi app did not return content-type (and crashed/terminated earlier) but I can be wrong...

FooBarWidget commented 10 years ago

From honglilai on April 11, 2013 02:38:37

Content-Type has got nothing to do with it. Here's how error handling in Phusion Passenger works: If passenger_wsgi.py crashes during evaluation, either with an exception or with sys.exit(), then Phusion Passenger will display all stdout and stderr output in the browser, just like with Ruby apps. To see it in action, try inserting "raise BaseException, 'hi'" at the beginning of the file.

However, what happens here is something different. The exception was not raised during evaluation of passenger_wsgi.py, but during normal request handling, as you can see in the backtrace. This is because the typo is not a Python syntax error: it registers the wrong module name in Django, causing the framework to fail during request handling.

Phusion Passenger expects the app, or the framework, or handle exceptions during request handling.

FooBarWidget commented 10 years ago

From j.dembicki on April 11, 2013 04:58:51

...okay, but I still think that there should be not a situation where passenger+apache just returns "internal server error". Firstly it is NOT a server error (but an app error), secondly it makes impossible to share apache for other people for developing their own app code... Passenger should catch such exception and still display error on webpage :( If passenger can't display such errors can you make separate log (like error_log) but for each passenger app and make apache display custom error? "internal server error" really suggests problem lies within the "server" not an app.

FooBarWidget commented 10 years ago

From j.dembicki on April 11, 2013 05:00:48

...I guess you can edit default apache 500 error so custom error here is not needed that much. But a displaying error or custom error_logs are really must have in my opinion.

FooBarWidget commented 10 years ago

From honglilai on April 11, 2013 05:07:14

Alright. Would you be interested in contributing support for displaying such an error page? It would involve modifying the WSGI loader to catch exceptions during request handling, and printing an error response if friendly error pages are turned on. Error pages are formatted according to the templates in resources/templates.

FooBarWidget commented 10 years ago

From j.dembicki on April 11, 2013 05:15:08

meaning money contribution? I'm too bad at c (or ruby and python for that matter) to contribute any usefull code.

FooBarWidget commented 10 years ago

From honglilai on April 11, 2013 05:21:35

I actually meant Python code contribution. :) Alright, I'll put this on my todo list, but it's fairly low priority, although I could give it more priority if you are or become a Phusion Passenger Enterprise customer.

FooBarWidget commented 10 years ago

From j.dembicki on April 11, 2013 05:34:01

Thanks. I'm just a php guy so yeah... :) no real idea about python. But I try to direct here some people that might know it enough. Can you edit title of this issue to " display wsgi errors" or whatever you think best represents this issue?

I can tell that I've been using paste module for python to do it in python 2.6 and 2.7 (it does not work in 3.3 however). So parts of the usefull code maybe can be found it this paste ...

application = django.core.handlers.wsgi.WSGIHandler()

from paste.exceptions.errormiddleware import ErrorMiddleware application = django.core.handlers.wsgi.WSGIHandler() application = ErrorMiddleware(application, debug=True)

FooBarWidget commented 10 years ago

From honglilai on April 11, 2013 06:01:33

Summary: Display an error page if a WSGI app raises an exception during request handling (was: display wsgi errors if aplication did not return Content-Type)