summaryrefslogtreecommitdiff
path: root/docs/logging.rst
blob: 799b75d6aec9ce24b7ab6299e942a48d09b14acb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
.. _access-logging:

==============
Access Logging
==============

The WSGI design is modular.  Waitress logs error conditions, debugging
output, etc., but not web traffic.  For web traffic logging, Paste
provides `TransLogger
<https://web.archive.org/web/20160707041338/http://pythonpaste.org/modules/translogger.html>`_
:term:`middleware`.  TransLogger produces logs in the `Apache Combined
Log Format <https://httpd.apache.org/docs/current/logs.html#combined>`_.


.. _logging-to-the-console-using-python:

Logging to the Console Using Python
-----------------------------------

``waitress.serve`` calls ``logging.basicConfig()`` to set up logging to the
console when the server starts up.  Assuming no other logging configuration
has already been done, this sets the logging default level to
``logging.WARNING``.  The Waitress logger will inherit the root logger's
level information (it logs at level ``WARNING`` or above).

Waitress sends its logging output (including application exception
renderings) to the Python logger object named ``waitress``.  You can
influence the logger level and output stream using the normal Python
``logging`` module API.  For example:

.. code-block:: python

   import logging
   logger = logging.getLogger('waitress')
   logger.setLevel(logging.INFO)

Within a PasteDeploy configuration file, you can use the normal Python
``logging`` module ``.ini`` file format to change similar Waitress logging
options.  For example:

.. code-block:: ini

   [logger_waitress]
   level = INFO


.. _logging-to-the-console-using-pastedeploy:

Logging to the Console Using PasteDeploy
----------------------------------------

TransLogger will automatically setup a logging handler to the console when called with no arguments.
It "just works" in environments that don't configure logging.
This is by virtue of its default configuration setting of ``setup_console_handler = True``.


.. TODO:
.. .. _logging-to-a-file-using-python:

.. Logging to a File Using Python
.. ------------------------------

.. Show how to configure the WSGI logger via python.


.. _logging-to-a-file-using-pastedeploy:

Logging to a File Using PasteDeploy
------------------------------------

TransLogger does not write to files, and the Python logging system
must be configured to do this.  The Python class :class:`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 add a
``[filter:translogger]`` section, then use a ``[pipeline:main]``
section file to form a WSGI pipeline with both the translogger and
your application in it.  For instance, if you have this:

.. code-block:: ini

   [app:wsgiapp]
   use = egg:mypackage#wsgiapp

   [server:main]
   use = egg:waitress#main
   host = 127.0.0.1
   port = 8080

Add this:

.. code-block:: ini

   [filter:translogger]
   use = egg:Paste#translogger
   setup_console_handler = False

   [pipeline:main]
   pipeline = translogger
              wsgiapp

Using PasteDeploy this way to form and serve a pipeline is equivalent to
wrapping your app in a TransLogger instance via the bottom of the ``main``
function of your project's ``__init__`` file:

.. code-block:: python

    from mypackage import wsgiapp
    from waitress import serve
    from paste.translogger import TransLogger
    serve(TransLogger(wsgiapp, setup_console_handler=False))

.. note::
    TransLogger will automatically set up 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
its output to the console when we request a page:

.. code-block:: text

    00:50:53,694 INFO [wsgiapp] Returning: Hello World!
                      (content-type: text/plain)
    00:50:53,695 INFO [wsgi] 192.168.1.111 - - [11/Aug/2011:20:09:33 -0700] "GET /hello
    HTTP/1.1" 404 - "-"
    "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 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

    # Begin logging configuration

    [loggers]
    keys = root, wsgiapp, wsgi

    [handlers]
    keys = console, accesslog

    [logger_wsgi]
    level = INFO
    handlers = accesslog
    qualname = wsgi
    propagate = 0

    [handler_accesslog]
    class = FileHandler
    args = ('%(here)s/access.log','a')
    level = INFO
    formatter = generic

As mentioned above, non-root loggers by default propagate their log records
to the root logger's handlers (currently the console handler). Setting
``propagate`` to ``0`` (``False``) here disables this; so the ``wsgi`` logger
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 including the
following in your configuration file:

.. code-block:: ini

    [formatters]
    keys = generic, accesslog

    [formatter_accesslog]
    format = %(message)s

Finally alter the existing configuration to wire this new
``accesslog`` formatter into the FileHandler:

.. code-block:: ini

    [handler_accesslog]
    class = FileHandler
    args = ('%(here)s/access.log','a')
    level = INFO
    formatter = accesslog