#34781: Clarify documentation of `request` objects in the `django.server` 
logging
namespace.
-----------------------------------------+------------------------
               Reporter:  Keryn Knight   |          Owner:  nobody
                   Type:  Uncategorized  |         Status:  new
              Component:  Documentation  |        Version:  dev
               Severity:  Normal         |       Keywords:
           Triage Stage:  Unreviewed     |      Has patch:  0
    Needs documentation:  0              |    Needs tests:  0
Patch needs improvement:  0              |  Easy pickings:  0
                  UI/UX:  0              |
-----------------------------------------+------------------------
 The docs currently say, of both `django.request` and `django.server`:
 > Messages to this logger have the following extra context:
 > **request**: The request object that generated the logging message.

 However, that appears to be true only in the strictest possible sense,
 because as far as I can tell, the `request` on a `django.server` message
 under runserver is actually ... the `socket.socket` instance
 
[https://github.com/python/cpython/blob/f51f0466c07eabc6177c2f64f70c952dada050e8/Lib/socketserver.py#L756
 mirrored] as the
 
[https://github.com/python/cpython/blob/f51f0466c07eabc6177c2f64f70c952dada050e8/Lib/socketserver.py#L805
 connection].

 Simplest steps I could figure out to show the problem, because frankly
 logging in Python is a nightmare, and Django doesn't exactly make it
 ''better''...

 Make a new project `django-admin startproject whatever`
 Go and edit `django/utils/log.py` and set up handlers like so:
 {{{
         "django.request": {
             "handlers": ["django.server"],
             "level": "INFO",
             "propagate": False,
         },
         "django.server": {
             "handlers": ["django.server"],
             "level": "INFO",
             "propagate": False,
         },
 }}}
 Set the `django.server` formatter like so:
 {{{
 "formatters": {
         "django.server": {
             "()": "django.utils.log.ServerFormatter",
             "format": "[{server_time}] {request} {message}",
             "style": "{",
         }
     },
 }}}
 Note the addition of the `{request}` parameter.

 Start the server `python manage.py runserver ...`

 Open your browser to `/` to see the `The install worked successfully!
 Congratulations!` welcome page.

 Look at your log output, it'll say something like:
 {{{
 [17/Aug/2023 11:00:23] <socket.socket fd=7, family=AddressFamily.AF_INET,
 type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8001),
 raddr=('127.0.0.1', 60767)> "GET / HTTP/1.1" 200 10629
 }}}
 which is ... I ''guess'' you could count it as a request object, though
 I'm more inclined to think that the presence of a `.request` attribute
 meant the docs could copy-paste/re-use the existing definition
 accidentally.

 OK so how's that different to the `django.request` logger?
 Open your browser to `/404` which I think forces a `django.request` record
 via `log_message` Look at your log output again, it'll say something like:
 {{{
 [17/Aug/2023 11:02:27,574] <WSGIRequest: GET '/404'> Not Found: /404
 [17/Aug/2023 11:02:27] <socket.socket fd=7, family=AddressFamily.AF_INET,
 type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8001),
 raddr=('127.0.0.1', 60767)> "GET /404 HTTP/1.1" 404 2101
 }}}

 Ignoring the fact the server time isn't even formatted the same...
 Note how **one** of the records is backed by an actual `WSGIRequest` (and
 ultimately can also be be either `HttpRequest` or `ASGIRequest`) which I
 think/guess is
 
[https://github.com/django/django/blob/d25f3892114466d689fd6936f79f3bd9a9acc30e/django/utils/log.py#L246
 from here]
 But the other is still that pesky socket, which would only have the
 requestline + raw requestline etc... That's from
 
[https://github.com/django/django/blob/d25f3892114466d689fd6936f79f3bd9a9acc30e/django/core/servers/basehttp.py#L185
 here I think?]

 -----------

 Expectations:

 Ideally, it'd have the **actual** `HttpRequest` subclass instance, but
 that may not actually be possible given where those log messages might
 actually occur in the overall machinery. That is, I can't see where you'd
 pass it around

 So if that's not possible, it'd be lovely to actually tighten up the
 documentation to make clear that you won't (necessarily? always?
 sometimes?) have that, but only the underlying socket/connection.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34781>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018a033754a7-a4665ad3-ba04-4d65-9c79-4dc71bd8b3d5-000000%40eu-central-1.amazonses.com.

Reply via email to