diff options
Diffstat (limited to 'docs/narr')
| -rw-r--r-- | docs/narr/assets.rst | 175 | ||||
| -rw-r--r-- | docs/narr/configuration.rst | 4 | ||||
| -rw-r--r-- | docs/narr/environment.rst | 22 | ||||
| -rw-r--r-- | docs/narr/i18n.rst | 8 | ||||
| -rw-r--r-- | docs/narr/logging.rst | 52 | ||||
| -rw-r--r-- | docs/narr/startup.rst | 8 |
6 files changed, 250 insertions, 19 deletions
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index b0a8d18b0..95863848b 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -287,6 +287,181 @@ suggestion for a pattern; any setting name other than ``media_location`` could be used. .. index:: + single: Cache Busting + +.. _cache_busting: + +Cache Busting +------------- + +.. versionadded:: 1.6 + +In order to maximize performance of a web application, you generally want to +limit the number of times a particular client requests the same static asset. +Ideally a client would cache a particular static asset "forever", requiring +it to be sent to the client a single time. The HTTP protocol allows you to +send headers with an HTTP response that can instruct a client to cache a +particular asset for an amount of time. As long as the client has a copy of +the asset in its cache and that cache hasn't expired, the client will use the +cached copy rather than request a new copy from the server. The drawback to +sending cache headers to the client for a static asset is that at some point +the static asset may change, and then you'll want the client to load a new copy +of the asset. Under normal circumstances you'd just need to wait for the +client's cached copy to expire before they get the new version of the static +resource. + +A commonly used workaround to this problem is a technique known as "cache +busting". Cache busting schemes generally involve generating a URL for a +static asset that changes when the static asset changes. This way headers can +be sent along with the static asset instructing the client to cache the asset +for a very long time. When a static asset is changed, the URL used to refer to +it in a web page also changes, so the client sees it as a new resource and +requests a copy, regardless of any caching policy set for the resource's old +URL. + +:app:`Pyramid` can be configured to produce cache busting URLs for static +assets by passing the optional argument, ``cachebust`` to +:meth:`~pyramid.config.Configurator.add_static_view`: + +.. code-block:: python + :linenos: + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cachebust=True) + +Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache +busting scheme which adds the md5 checksum for a static asset as a path segment +in the asset's URL: + +.. code-block:: python + :linenos: + + js_url = request.static_url('mypackage:folder/static/js/myapp.js') + # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js` + +When the asset changes, so will its md5 checksum, and therefore so will its +URL. Supplying the ``cachebust`` argument also causes the static view to set +headers instructing clients to cache the asset for ten years, unless the +``max_cache_age`` argument is also passed, in which case that value is used. + +.. note:: + + md5 checksums are cached in RAM so if you change a static resource without + restarting your application, you may still generate URLs with a stale md5 + checksum. + +Disabling the Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It can be useful in some situations (e.g. development) to globally disable all +configured cache busters without changing calls to +:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the +``PYRAMID_PREVENT_CACHEBUST`` environment variable or the +``pyramid.prevent_cachebust`` configuration value to a true value. + +Customizing the Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Revisiting from the previous section: + +.. code-block:: python + :linenos: + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cachebust=True) + +Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default +cache busting implementation that should work for many situations. The +``cachebust`` may be set to any object that implements the interface, +:class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly +equivalent to: + +.. code-block:: python + :linenos: + + from pyramid.static import PathSegmentMd5CacheBuster + + # config is an instance of pyramid.config.Configurator + config.add_static_view(name='static', path='mypackage:folder/static', + cachebust=PathSegmentMd5CacheBuster()) + +:app:`Pyramid` includes a handful of ready to use cache buster implementations: +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 +checksum token in the path portion of the asset's URL, +:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum +token to the query string of the asset's URL, and +:class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an +arbitrary token you provide to the query string of the asset's URL. + +In order to implement your own cache buster, you can write your own class from +scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` +interface. Alternatively you may choose to subclass one of the existing +implementations. One of the most likely scenarios is you'd want to change the +way the asset token is generated. To do this just subclass an existing +implementation and replace the :meth:`~pyramid.interfaces.ICacheBuster.token` +method. Here is an example which just uses Git to get the hash of the +currently checked out code: + +.. code-block:: python + :linenos: + + import os + import subprocess + from pyramid.static import PathSegmentMd5CacheBuster + + class GitCacheBuster(PathSegmentMd5CacheBuster): + """ + Assuming your code is installed as a Git checkout, as opposed to as an + egg from an egg repository like PYPI, you can use this cachebuster to + get the current commit's SHA1 to use as the cache bust token. + """ + def __init__(self): + here = os.path.dirname(os.path.abspath(__file__)) + self.sha1 = subprocess.check_output( + ['git', 'rev-parse', 'HEAD'], + cwd=here).strip() + + def token(self, pathspec): + return self.sha1 + +Choosing a Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~ + +The default cache buster implementation, +:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming +that you're using :app:`Pyramid` to serve your static assets. The md5 checksum +is fine grained enough that browsers should only request new versions of +specific assets that have changed. Many caching HTTP proxies will fail to +cache a resource if the URL contains a query string. In general, therefore, +you should prefer a cache busting strategy which modifies the path segment to +a strategy which adds a query string. + +It is possible, however, that your static assets are being served by another +web server or externally on a CDN. In these cases modifying the path segment +for a static asset URL would cause the external service to fail to find the +asset, causing your customer to get a 404. In these cases you would need to +fall back to a cache buster which adds a query string. It is even possible +that there isn't a copy of your static assets available to the :app:`Pyramid` +application, so a cache busting implementation that generates md5 checksums +would fail since it can't access the assets. In such a case, +:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable +fallback. The following code would set up a cachebuster that just uses the +time at start up as a cachebust token: + +.. code-block:: python + :linenos: + + import time + from pyramid.static import QueryStringConstantCacheBuster + + config.add_static_view( + name='http://mycdn.example.com/', + path='mypackage:static', + cachebust=QueryStringConstantCacheBuster(str(time.time()))) + +.. index:: single: static assets view .. _advanced_static: diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst index 52615533d..f7fa94daf 100644 --- a/docs/narr/configuration.rst +++ b/docs/narr/configuration.rst @@ -17,6 +17,10 @@ plugging application code that you've written into :app:`Pyramid` is also referred to within this documentation as "configuration"; you are configuring :app:`Pyramid` to call the code that makes up your application. +.. seealso:: + For information on ``.ini`` files for Pyramid applications see the + :ref:`startup_chapter` chapter. + There are two ways to configure a :app:`Pyramid` application: :term:`imperative configuration` and :term:`declarative configuration`. Both are described below. diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst index 7bac12ea7..0b06fb80b 100644 --- a/docs/narr/environment.rst +++ b/docs/narr/environment.rst @@ -157,6 +157,28 @@ feature when this is true. | | | +---------------------------------+----------------------------------+ +Preventing Cache Busting +------------------------ + +Prevent the ``cachebust`` static view configuration argument from having any +effect globally in this process when this value is true. No cache buster will +be configured or used when this is true. + +.. versionadded:: 1.6 + +.. seealso:: + + See also :ref:`cache_busting`. + ++---------------------------------+----------------------------------+ +| Environment Variable Name | Config File Setting Name | ++=================================+==================================+ +| ``PYRAMID_PREVENT_CACHEBUST`` | ``pyramid.prevent_cachebust`` | +| | or ``prevent_cachebust`` | +| | | +| | | ++---------------------------------+----------------------------------+ + Debugging All ------------- diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst index 95f663584..3313f8dad 100644 --- a/docs/narr/i18n.rst +++ b/docs/narr/i18n.rst @@ -792,9 +792,11 @@ Then as a part of the code of a custom :term:`locale negotiator`: .. code-block:: python :linenos: - from pyramid.threadlocal import get_current_registry - settings = get_current_registry().settings - languages = settings['available_languages'].split() + from pyramid.settings import aslist + + def my_locale_negotiator(request): + languages = aslist(request.registry.settings['available_languages']) + # ... This is only a suggestion. You can create your own "available languages" configuration scheme as necessary. diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst index 71029bb33..c16673ae6 100644 --- a/docs/narr/logging.rst +++ b/docs/narr/logging.rst @@ -16,6 +16,11 @@ how to send log messages to loggers that you've configured. a third-party scaffold which does not create these files, the configuration information in this chapter may not be applicable. +.. index: + pair: settings; logging + pair: .ini; logging + pair: logging; configuration + .. _logging_config: Logging Configuration @@ -242,7 +247,7 @@ level is set to ``INFO``, whereas the application's log level is set to [logger_myapp] level = DEBUG handlers = - qualname = helloworld + qualname = myapp All of the child loggers of the ``myapp`` logger will inherit the ``DEBUG`` level unless they're explicitly set differently. Meaning the ``myapp.views``, @@ -294,15 +299,26 @@ use the :term:`pyramid_exclog` package. Details about its configuration are in its `documentation <http://docs.pylonsproject.org/projects/pyramid_exclog/dev/>`_. +.. index:: + single: TransLogger + single: middleware; TransLogger + pair: configuration; middleware + single: settings; middleware + pair: .ini; middleware + +.. _request_logging_with_pastes_translogger: + Request Logging with Paste's TransLogger ---------------------------------------- -Paste provides the `TransLogger -<http://pythonpaste.org/modules/translogger.html>`_ :term:`middleware` for -logging requests using the `Apache Combined Log Format -<http://httpd.apache.org/docs/2.2/logs.html#combined>`_. TransLogger combined -with a FileHandler can be used to create an ``access.log`` file similar to -Apache's. +The term:`WSGI` design is modular. Waitress logs error conditions, debugging +output, etc., but not web traffic. For web traffic logging Paste provides the +`TransLogger <http://pythonpaste.org/modules/translogger.html>`_ +:term:`middleware`. TransLogger produces logs in the `Apache Combined Log +Format <http://httpd.apache.org/docs/2.2/logs.html#combined>`_. But +TransLogger does not write to files, the Python logging system must be +configured to do this. The Python FileHandler_ logging handler can be used +alongside TransLogger to create an ``access.log`` file similar to Apache's. Like any standard :term:`middleware` with a Paste entry point, TransLogger can be configured to wrap your application using ``.ini`` file syntax. First, @@ -343,10 +359,12 @@ function of your project's ``__init__`` file: app = TransLogger(app, setup_console_handler=False) return app -TransLogger will automatically setup a logging handler to the console when -called with no arguments, so it 'just works' in environments that don't -configure logging. Since we've configured our own logging handlers, we need -to disable that option via ``setup_console_handler = False``. + +.. note:: + TransLogger will automatically setup a logging handler to the console when + called with no arguments, so it 'just works' in environments that don't + configure logging. Since our logging handlers are configured we disable + the automation via ``setup_console_handler = False``. With the filter in place, TransLogger's logger (named the ``wsgi`` logger) will propagate its log messages to the parent logger (the root logger), sending @@ -361,9 +379,9 @@ its output to the console when we request a page: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" -To direct TransLogger to an ``access.log`` FileHandler, we need to add that -FileHandler to the list of handlers (named ``accesslog``), and ensure that the -``wsgi`` logger is configured and uses this handler accordingly: +To direct TransLogger to an ``access.log`` FileHandler, we need the following +to add a FileHandler (named ``accesslog``) to the list of handlers, and ensure +that the ``wsgi`` logger is configured and uses this handler accordingly: .. code-block:: ini @@ -395,7 +413,7 @@ directs its records only to the ``accesslog`` handler. Finally, there's no need to use the ``generic`` formatter with TransLogger as TransLogger itself provides all the information we need. We'll use a formatter that passes-through the log messages as is. Add a new formatter -called ``accesslog`` by include the following in your configuration file: +called ``accesslog`` by including the following in your configuration file: .. code-block:: ini @@ -405,7 +423,9 @@ called ``accesslog`` by include the following in your configuration file: [formatter_accesslog] format = %(message)s -Then wire this new ``accesslog`` formatter into the FileHandler: + +Finally alter the existing configuration to wire this new +``accesslog`` formatter into the FileHandler: .. code-block:: ini diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index 7b4a7ea08..a1a23ed52 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -19,6 +19,7 @@ console. .. index:: single: startup process + pair: settings; .ini The Startup Process ------------------- @@ -139,6 +140,13 @@ Here's a high-level time-ordered overview of what happens when you press The server serves the application, and the application is running, waiting to receive requests. +.. seealso:: + Logging configuration is described in the :ref:`logging_chapter` + chapter. There, in :ref:`request_logging_with_pastes_translogger`, + you will also find an example of how to configure + :term:`middleware` to add pre-packaged functionality to your + application. + .. index:: pair: settings; deployment single: custom settings |
