1

Background

I have a Django site served by Apache, set up in its own virtualhost and using mod_wsgi.

I want all of the errors associated with this virtualhost to be logged to a single file.

Currently, some errors are being sent to Apache's default error log and others are being sent to the one I defined in the virtualhost.

I'm pretty sure I have Django set up to stream WARN, ERROR and CRITICAL errors to sys.stderr via an instance of logging.StreamHandler configured in my Django settings. I think mod_wsgi passes that along to Apache, which then logs it according to whichever ErrorLog, ErrorLogFormat and LogLevel directives apply.

Questions

  1. What settings/situations cause errors to go to one log over another?
  2. Is it possible to unify the kinds of errors I give examples of?
  3. Are there any limitations on which errors can be logged where?

Error log examples

/var/log/apache2/mysite_error.log :

(Caused by purposefully setting an invalid log level "foo" for the default Django logger in the Django settings files.)

[Wed Aug 09 19:48:31.049028 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828] mod_wsgi (pid=30894): Target WSGI script '/home/myuser/mysite/mysite/mysite.wsgi' cannot be loaded as Python module.
[Wed Aug 09 19:48:31.049050 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828] mod_wsgi (pid=30894): Exception occurred processing WSGI script '/home/myuser/mysite/mysite/mysite.wsgi'.
[Wed Aug 09 19:48:31.049063 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828] Traceback (most recent call last):
[Wed Aug 09 19:48:31.049075 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/home/myuser/mysite/mysite/mysite.wsgi", line 18, in <module>
[Wed Aug 09 19:48:31.049112 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     application = get_wsgi_application()
[Wed Aug 09 19:48:31.049119 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/core/wsgi.py", line 14, in get_wsgi_application
[Wed Aug 09 19:48:31.049140 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     django.setup()
[Wed Aug 09 19:48:31.049153 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/__init__.py", line 17, in setup
[Wed Aug 09 19:48:31.049172 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
[Wed Aug 09 19:48:31.049177 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/utils/log.py", line 86, in configure_logging
[Wed Aug 09 19:48:31.049212 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     logging_config_func(logging_settings)
[Wed Aug 09 19:48:31.049217 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/usr/lib/python2.7/logging/config.py", line 794, in dictConfig
[Wed Aug 09 19:48:31.049339 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     dictConfigClass(config).configure()
[Wed Aug 09 19:48:31.049344 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]   File "/usr/lib/python2.7/logging/config.py", line 627, in configure
[Wed Aug 09 19:48:31.049392 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828]     '%r: %s' % (name, e))
[Wed Aug 09 19:48:31.049416 2017] [:error] [pid 30894:tid 140490808121088] [client 129.112.115.40:32828] ValueError: Unable to configure logger 'django': Unknown level: 'foo'

/var/log/apache2/error.log :

(Caused by making an GET request that queries for a record that does not exist in the database.)

[Wed Aug 09 19:45:56.500731 2017] [:error] [pid 30718:tid 140490808121088] ERROR 2017-08-09 19:45:56,500 base:256 handle_uncaught_exception 30718 140490808121088 Internal Server Error: /fooview
[Wed Aug 09 19:45:56.500744 2017] [:error] [pid 30718:tid 140490808121088] Traceback (most recent call last):
[Wed Aug 09 19:45:56.500746 2017] [:error] [pid 30718:tid 140490808121088]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
[Wed Aug 09 19:45:56.500748 2017] [:error] [pid 30718:tid 140490808121088]     response = wrapped_callback(request, *callback_args, **callback_kwargs)
[Wed Aug 09 19:45:56.500749 2017] [:error] [pid 30718:tid 140490808121088]   File "/home/myuser/mysite/rtls/views.py", line 55, in fooview
[Wed Aug 09 19:45:56.500751 2017] [:error] [pid 30718:tid 140490808121088]     Node.objects.get(pk=-1)
[Wed Aug 09 19:45:56.500752 2017] [:error] [pid 30718:tid 140490808121088]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
[Wed Aug 09 19:45:56.500754 2017] [:error] [pid 30718:tid 140490808121088]     return getattr(self.get_queryset(), name)(*args, **kwargs)
[Wed Aug 09 19:45:56.500755 2017] [:error] [pid 30718:tid 140490808121088]   File "/home/myuser/mysite/venv/lib/python2.7/site-packages/django/db/models/query.py", line 334, in get
[Wed Aug 09 19:45:56.500756 2017] [:error] [pid 30718:tid 140490808121088]     self.model._meta.object_name
[Wed Aug 09 19:45:56.500758 2017] [:error] [pid 30718:tid 140490808121088] DoesNotExist: Node matching query does not exist.

Also, if I manually make a logging call using logger.error('some error message'), it shows up here as well - not in the virtualhost's error log like I would expect.

Program version info

  • Apache/2.4.7 (Ubuntu) using mpm_worker (apache2ctl -V)
  • Django/1.8.14 (pip freeze)
  • mod_wsgi/3.4 (the last method of this)
  • Python/2.7.6 (from startup logs in main Apache error.log)

Related sections of configs and code

Apache

/etc/apache2/apache2.conf :

ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel error

# ... stuff ...

WSGIRestrictStdout On

/etc/apache2/sites-available/mysite.conf :

<VirtualHost *:80>
    # ... stuff ...

    ErrorLog ${APACHE_LOG_DIR}/mysite_error.log
    LogLevel warn

    #serving wsgi script
    WSGIScriptAlias / /home/myuser/mysite/mysite/mysite.wsgi
    <Directory /home/myuser/mysite/mysite>
        <Files mysite.wsgi>
            Require all granted
        </Files>
    </Directory>

    # ... stuff ...
</VirtualHost>

Django

/home/myuser/mysite/mysite/initial_settings.py :

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s:%(lineno)s %(funcName)s %(process)d %(thread)d %(message)s'
        },
        # ... other formatters ...
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
        # ... other handlers ...
    }
}

/home/myuser/mysite/mysite/deployment.py :

from initial_settings import LOGGING

LOGGING['loggers']['django'] = {
    'handlers': ['console'],
    'level': 'WARN',
    'propagate': True,
}

/home/myuser/mysite/mysite/settings.py :

from deployment import LOGGING

/home/myuser/mysite/mysite/mysite.wsgi :

(mod_wsgi daemon mode and python-home directives are just around the corner but not merged yet, sorry to trigger Graham)

import os
import sys
activate_this_file = "/home/myuser/mysite/venv/bin/activate_this.py"
execfile(activate_this_file, dict(__file__=activate_this_file))

path = '/home/myuser/mysite'
if path not in sys.path:
    sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

# needed for upgrade django >=1.7
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Peter Henry
  • 443
  • 4
  • 13
  • What version of mod_wsgi are you using? How are you using ``WSGIDaemonProcess``, ``WSGIScriptAlias`` and ``WSGIImportScript``? If the configuration results in pre-loading of the WSGI script, any errors on loading it may be going to wrong log. I can't remember what happens in that case or whether anything special was done to ensure went to the correct log when know it could only be used in a specific virtual host. – Graham Dumpleton Aug 10 '17 at 02:38
  • @GrahamDumpleton I've added program version info and Apache wsgi directives into the question (it's `mod_wsgi/3.4` and I'm not using `WSGIDaemonProcess` and `WSGIImportScript`.) I don't think the WSGI script is being preloaded atm; I have a branch of this project where I've switched to daemon mode and am preloading the app, but I haven't tuned it enough to deploy it yet. (Btw, I've learned a _lot_ from your PyCon talks/SO answers/blog posts - I really respect how much you give the community!) – Peter Henry Aug 10 '17 at 17:02
  • 1
    I can only suggest you upgrade to the latest version of mod_wsgi. Version 3.4 is over 5 years old. Don't use the operating system packages they are out of date and have never been supported as I don't create those packages, use ``pip install mod_wsgi`` and then ``mod_wsgi-express module-config`` to generate snippet to put into Apache configuration to load the module. See https://pypi.python.org/pypi/mod_wsgi and my recent talk https://www.youtube.com/watch?v=H6Q3l11fjU0&index=81&list=PLs4CJRBY5F1KsK4AbFaPsUT8X8iXc7X84 – Graham Dumpleton Aug 10 '17 at 21:23
  • @GrahamDumpleton that did it! I'm running `mod_wsgi/4.5.17` from PyPi and all three examples of errors from my question are now going to the virtualhost's errorlog as expected. Do you want to put that in an answer for me to accept? That's an excellent video too, gives me some things to try, but now I have a tangential question - having trouble using `runmodwsgi` because my wsgi script is named `mysite.wsgi` (the mod_wsgi blessed way?) instead of `wsgi.py` (the django way). Might ask that in a new question unless you can clarify in a couple lines. – Peter Henry Aug 11 '17 at 19:50
  • When using ``runmodwsgi`` the original ``wsgi.py`` file should work fine unless you had added customisations on top of adjusting ``sys.path``. – Graham Dumpleton Aug 11 '17 at 21:14

0 Answers0