diff options
-rw-r--r-- | README.rst | 12 | ||||
-rw-r--r-- | docs/release-notes/index.rst | 1 | ||||
-rw-r--r-- | docs/release-notes/version-4.4.11.rst | 61 | ||||
-rw-r--r-- | setup.py | 3 | ||||
-rw-r--r-- | src/server/__init__.py | 85 | ||||
-rw-r--r-- | src/server/mod_wsgi.c | 38 | ||||
-rw-r--r-- | src/server/wsgi_version.h | 4 |
7 files changed, 180 insertions, 24 deletions
@@ -296,15 +296,3 @@ agent configuration file. export NEW_RELIC_CONFIG_FILE mod_wsgi-express start-server wsgi.py --with-newrelic - -When using this option, if you have also installed the ``mod_wsgi-metrics`` -Python package, then additional metrics about Apache and mod_wsgi will also -be reported via the New Relic Platform API. These will appear as a separate -set of dashboards under 'mod_wsgi' in the left hand side navigation bar of -the New Relic UI. - -New Relic provides a free Lite tier so there is no excuse for not using it. -Learn about what your Python web application is really doing. [1]_ - -.. [1] Disclaimer: I work for New Relic and am the primary developer of - the Python agent. So of course it is awesome. :-) diff --git a/docs/release-notes/index.rst b/docs/release-notes/index.rst index 70ec171..f57fa2a 100644 --- a/docs/release-notes/index.rst +++ b/docs/release-notes/index.rst @@ -5,6 +5,7 @@ Release Notes .. toctree:: :maxdepth: 2 + version-4.4.11.rst version-4.4.10.rst version-4.4.9.rst version-4.4.8.rst diff --git a/docs/release-notes/version-4.4.11.rst b/docs/release-notes/version-4.4.11.rst new file mode 100644 index 0000000..1001a1d --- /dev/null +++ b/docs/release-notes/version-4.4.11.rst @@ -0,0 +1,61 @@ +============== +Version 4.4.11 +============== + +Version 4.4.11 of mod_wsgi can be obtained from: + + https://codeload.github.com/GrahamDumpleton/mod_wsgi/tar.gz/4.4.11 + +For details on the availability of Windows binaries see: + + https://github.com/GrahamDumpleton/mod_wsgi/tree/master/win32 + +Bugs Fixed +---------- + +1. No provision was made for operating systems with a very low limit on the +number of separate data blocks that could be passed to system ``writev()`` +call. This was an issue on Solaris where the limit is 16 and meant that since +version 4.4.0, daemon mode of mod_wsgi would fail where a HTTP request had +more than a small number of headers. + +2. When installing the ``mod_wsgi`` package using ``pip`` and rather +than activating the virtual environment you were referring to ``pip`` by +path from the ``bin`` directory, the ``mod_wsgi-httpd`` package which +had already been installed into the virtual environment would not be +detected. + +New Features +------------ + +1. Added the ``--service-log`` option to ``mod_wsgi-express`` for +specifying the name of a log file for a specific service script. The +arguments are the name of the service and the file name for the log. The +log file will be placed in the log directory, be it the default, or a +specific log directory if specified. + +2. Set various environment variables from ``mod_wsgi-express`` to identify +that it is being used, what hosts it is handling requests for, and whether +debug mode and/or specific debug mode features are enabled. This is so that +a web application can modify it's behaviour when ``mod_wsgi-express`` is +being used, or being used in specific ways. The environment variables which +are set are: + +* *MOD_WSGI_EXPRESS* - Indicates that ``mod_wsgi-express`` is being used. +* *MOD_WSGI_SERVER_NAME* - The primary server host name for the site. +* *MOD_WSGI_SERVER_ALIASES* - Secondary host names the site is known by. +* *MOD_WSGI_RELOADER_ENABLED* - Indicates if source code reloading enabled. +* *MOD_WSGI_DEBUG_MODE* - Indicates if debug mode has been enabled. +* *MOD_WSGI_DEBUGGER_ENABLED* - Indicates pdb debugger has been enabled. +* *MOD_WSGI_COVERAGE_ENABLED* - Indicates if coverage analysis has been + enabled. +* *MOD_WSGI_PROFILER_ENABLED* - Indicates if code profiling has been enabled. +* *MOD_WSGI_RECORDER_ENABLED* - Indicates if request/response recording + enabled. +* *MOD_WSGI_GDB_ENABLED* - Indicates if gdb process crash debugging enabled. + +For any environment variable indicating a feature has been enabled, it +will be set when enabled and have the value 'true'. + +For the list of server aliases, it will be a space separated list of host +names. @@ -122,7 +122,8 @@ APXS = os.environ.get('APXS') WITH_HTTPD_PACKAGE = False if APXS is None: - APXS = find_program(['mod_wsgi-apxs']) + APXS = find_program(['mod_wsgi-apxs'], + paths=[os.path.dirname(sys.executable)]) if APXS is not None: WITH_HTTPD_PACKAGE = True diff --git a/src/server/__init__.py b/src/server/__init__.py index fa26232..2bf5d4f 100644 --- a/src/server/__init__.py +++ b/src/server/__init__.py @@ -781,6 +781,31 @@ WSGIImportScript '%(script)s' \\ application-group=%%{GLOBAL} """ +APACHE_SERVICE_WITH_LOG_CONFIG = """ +<VirtualHost *:%(port)s> +<IfDefine WSGI_ROTATE_LOGS> +ErrorLog "|%(rotatelogs_executable)s \\ + %(log_directory)s/%(log_file)s.%%Y-%%m-%%d-%%H_%%M_%%S %(max_log_size)sM" +</IfDefine> +<IfDefine !WSGI_ROTATE_LOGS> +ErrorLog "%(log_directory)s/%(log_file)s" +</IfDefine> +WSGIDaemonProcess 'service:%(name)s' \\ + display-name=%%{GROUP} \\ + user='%(user)s' \\ + group='%(group)s' \\ + home='%(working_directory)s' \\ + threads=1 \\ + python-path='%(python_path)s' \\ + python-eggs='%(python_eggs)s' \\ + lang='%(lang)s' \\ + locale='%(locale)s' +WSGIImportScript '%(script)s' \\ + process-group='service:%(name)s' \\ + application-group=%%{GLOBAL} +</VirtualHost> +""" + def generate_apache_config(options): with open(options['httpd_conf'], 'w') as fp: print(APACHE_GENERAL_CONFIG % options, file=fp) @@ -852,18 +877,35 @@ def generate_apache_config(options): file=fp) if options['service_scripts']: + service_log_files = {} + if options['service_log_files']: + service_log_files.update(options['service_log_files']) users = dict(options['service_users'] or []) groups = dict(options['service_groups'] or []) for name, script in options['service_scripts']: user = users.get(name, '${WSGI_RUN_USER}') group = groups.get(name, '${WSGI_RUN_GROUP}') - print(APACHE_SERVICE_CONFIG % dict(name=name, user=user, - group=group, script=script, - python_path=options['python_path'], - working_directory=options['working_directory'], - python_eggs=options['python_eggs'], - lang=options['lang'], locale=options['locale']), - file=fp) + if name in service_log_files: + print(APACHE_SERVICE_WITH_LOG_CONFIG % dict(name=name, + user=user, group=group, script=script, + port=options['port'], + log_directory=options['log_directory'], + log_file=service_log_files[name], + rotatelogs_executable=options['rotatelogs_executable'], + max_log_size=options['max_log_size'], + python_path=options['python_path'], + working_directory=options['working_directory'], + python_eggs=options['python_eggs'], + lang=options['lang'], locale=options['locale']), + file=fp) + else: + print(APACHE_SERVICE_CONFIG % dict(name=name, user=user, + group=group, script=script, + python_path=options['python_path'], + working_directory=options['working_directory'], + python_eggs=options['python_eggs'], + lang=options['lang'], locale=options['locale']), + file=fp) if options['include_files']: for filename in options['include_files']: @@ -1328,8 +1370,18 @@ enable_profiler = %(enable_profiler)s profiler_directory = '%(profiler_directory)s' enable_recorder = %(enable_recorder)s recorder_directory = '%(recorder_directory)s' +enable_gdb = %(enable_gdb)s + +os.environ['MOD_WSGI_EXPRESS'] = 'true' +os.environ['MOD_WSGI_SERVER_NAME'] = '%(server_host)s' +os.environ['MOD_WSGI_SERVER_ALIASES'] = %(server_aliases)r or '' + +if reload_on_changes: + os.environ['MOD_WSGI_RELOADER_ENABLED'] = 'true' if debug_mode: + os.environ['MOD_WSGI_DEBUG_MODE'] = 'true' + # We need to fiddle sys.path as we are not using daemon mode and so # the working directory will not be added to sys.path by virtue of # 'home' option to WSGIDaemonProcess directive. We could use the @@ -1338,11 +1390,16 @@ if debug_mode: sys.path.insert(0, working_directory) +if enable_debugger: + os.environ['MOD_WSGI_DEBUGGER_ENABLED'] = 'true' + def output_coverage_report(): coverage_info.stop() coverage_info.html_report(directory=coverage_directory) if enable_coverage: + os.environ['MOD_WSGI_COVERAGE_ENABLED'] = 'true' + from coverage import coverage coverage_info = coverage() coverage_info.start() @@ -1355,11 +1412,19 @@ def output_profiler_data(): profiler_info.dump_stats(output_file) if enable_profiler: + os.environ['MOD_WSGI_PROFILER_ENABLED'] = 'true' + from cProfile import Profile profiler_info = Profile() profiler_info.enable() atexit.register(output_profiler_data) +if enable_recorder: + os.environ['MOD_WSGI_RECORDER_ENABLED'] = 'true' + +if enable_gdb: + os.environ['MOD_WSGI_GDB_ENABLED'] = 'true' + if with_newrelic_agent: if newrelic_config_file: os.environ['NEW_RELIC_CONFIG_FILE'] = newrelic_config_file @@ -2162,6 +2227,10 @@ option_list = ( help='When being run by the root user, the group that the ' 'distinct daemon process started to run the managed service ' 'should be run as.'), + optparse.make_option('--service-log-file', action='append', nargs=2, + dest='service_log_files', metavar='SERVICE FILE-NAME', + help='Specify the name of a separate log file to be used for ' + 'the managed service.'), optparse.make_option('--enable-docs', action='store_true', default=False, help='Flag indicating whether the mod_wsgi documentation should ' @@ -2668,6 +2737,8 @@ def _cmd_setup_server(command, args, options): else: host = options['host'] + options['server_host'] = host + if options['port'] == 80: options['url'] = 'http://%s/' % host else: diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c index b900303..09dc527 100644 --- a/src/server/mod_wsgi.c +++ b/src/server/mod_wsgi.c @@ -10081,8 +10081,8 @@ static apr_status_t wsgi_socket_send(apr_socket_t *sock, const char *buf, return APR_SUCCESS; } -static apr_status_t wsgi_socket_sendv(apr_socket_t *sock, struct iovec *vec, - int nvec) +static apr_status_t wsgi_socket_sendv_limit(apr_socket_t *sock, + struct iovec *vec, int nvec) { apr_status_t rv; apr_size_t written = 0; @@ -10137,6 +10137,40 @@ static apr_status_t wsgi_socket_sendv(apr_socket_t *sock, struct iovec *vec, return APR_SUCCESS; } +static apr_status_t wsgi_socket_sendv(apr_socket_t *sock, struct iovec *vec, + int nvec) +{ +#if defined(_SC_IOV_MAX) + static size_t iov_max = 0; + + if (iov_max == 0) + iov_max = sysconf(_SC_IOV_MAX); +#else + static size_t iov_max = APR_MAX_IOVEC_SIZE; +#endif + + if (nvec > iov_max) { + int offset = 0; + + while (nvec > 0) { + apr_status_t rv; + + rv = wsgi_socket_sendv_limit(sock, &vec[offset], + (nvec < iov_max ? nvec : (int)iov_max)); + + if (rv != APR_SUCCESS) + return rv; + + nvec -= iov_max; + offset += iov_max; + } + + return APR_SUCCESS; + } + else + return wsgi_socket_sendv_limit(sock, vec, nvec); +} + static apr_status_t wsgi_send_request(request_rec *r, WSGIRequestConfig *config, WSGIDaemonSocket *daemon) diff --git a/src/server/wsgi_version.h b/src/server/wsgi_version.h index ed32b06..ea29f10 100644 --- a/src/server/wsgi_version.h +++ b/src/server/wsgi_version.h @@ -25,8 +25,8 @@ #define MOD_WSGI_MAJORVERSION_NUMBER 4 #define MOD_WSGI_MINORVERSION_NUMBER 4 -#define MOD_WSGI_MICROVERSION_NUMBER 10 -#define MOD_WSGI_VERSION_STRING "4.4.10" +#define MOD_WSGI_MICROVERSION_NUMBER 11 +#define MOD_WSGI_VERSION_STRING "4.4.11" /* ------------------------------------------------------------------------- */ |