Formatting uWSGI requests logs

uWSGI has a —logformat option for building custom request loglines. Thesyntax is simple:

  1. [uwsgi]
  2. logformat = i am a logline reporting "%(method) %(uri) %(proto)" returning with status %(status)

All of the variables marked with %() are substituted using specific rules.Three kinds of logvars are defined (“offsetof”, functions, and user-defined).

offsetof

These are taken blindly from the internal wsgi_request structure of the current request.

  • %(uri) -> REQUEST_URI
  • %(method) -> REQUEST_METHOD
  • %(user) -> REMOTE_USER
  • %(addr) -> REMOTE_ADDR
  • %(host) -> HTTP_HOST
  • %(proto) -> SERVER_PROTOCOL
  • %(uagent) -> HTTP_USER_AGENT (starting from 1.4.5)
  • %(referer) -> HTTP_REFERER (starting from 1.4.5)

functions

These are simple functions called for generating the logvar value:

  • %(status) -> HTTP response status code
  • %(micros) -> response time in microseconds
  • %(msecs) -> response time in milliseconds
  • %(secs) -> response time in seconds
  • %(time) -> timestamp of the start of the request
  • %(ctime) -> ctime of the start of the request
  • %(epoch) -> the current time in Unix format
  • %(size) -> response body size + response headers size (since 1.4.5)
  • %(ltime) -> human-formatted (Apache style) request time (since 1.4.5)
  • %(hsize) -> response headers size (since 1.4.5)
  • %(rsize) -> response body size (since 1.4.5)
  • %(cl) -> request content body size (since 1.4.5)
  • %(pid) -> pid of the worker handling the request (since 1.4.6)
  • %(wid) -> id of the worker handling the request (since 1.4.6)
  • %(switches) -> number of async switches (since 1.4.6)
  • %(vars) -> number of CGI vars in the request (since 1.4.6)
  • %(headers) -> number of generated response headers (since 1.4.6)
  • %(core) -> the core running the request (since 1.4.6)
  • %(vsz) -> address space/virtual memory usage (in bytes) (since 1.4.6)
  • %(rss) -> RSS memory usage (in bytes) (since 1.4.6)
  • %(vszM) -> address space/virtual memory usage (in megabytes) (since 1.4.6)
  • %(rssM) -> RSS memory usage (in megabytes) (since 1.4.6)
  • %(pktsize) -> size of the internal request uwsgi packet (since 1.4.6)
  • %(modifier1) -> modifier1 of the request (since 1.4.6)
  • %(modifier2) -> modifier2 of the request (since 1.4.6)
  • %(metric.XXX) -> access the XXX metric value (see The Metrics subsystem)
  • %(rerr) -> number of read errors for the request (since 1.9.21)
  • %(werr) -> number of write errors for the request (since 1.9.21)
  • %(ioerr) -> number of write and read errors for the request (since 1.9.21)
  • %(tmsecs) -> timestamp of the start of the request in milliseconds since the epoch (since 1.9.21)
  • %(tmicros) -> timestamp of the start of the request in microseconds since the epoch (since 1.9.21)
  • %(var.XXX) -> the content of request variable XXX (like var.PATH_INFO or var.HTTP_X_MY_HEADER for headers from request, available from 1.9.21)

User-defined logvars

You can define logvars within your request handler. These variables live onlyper-request.

  1. import uwsgi
  2. def application(env, start_response):
  3. uwsgi.set_logvar('foo', 'bar')
  4. # returns 'bar'
  5. print uwsgi.get_logvar('foo')
  6. uwsgi.set_logvar('worker_id', str(uwsgi.worker_id()))
  7. ...

With the following log format you will be able to access code-defined logvars:

  1. uwsgi --logformat 'worker id = %(worker_id) for request "%(method) %(uri) %(proto)" test = %(foo)'

uWSGI default logging

To generate uWSGI-compatible logs:

  1. [uwsgi]
  2. ...
  3. log-format = [pid: %(pid)|app: -|req: -/-] %(addr) (%(user)) {%(vars) vars in %(pktsize) bytes} [%(ctime)] %(method) %(uri) => generated %(rsize) bytes in %(msecs) msecs (%(proto) %(status)) %(headers) headers in %(hsize) bytes (%(switches) switches on core %(core))
  4.  
  5. ...

Apache-style combined request logging

To generate Apache-compatible logs:

  1. [uwsgi]
  2. ...
  3. log-format = %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)"
  4. ...

Hacking logformat

(Updated to 1.9.21)

You can register new “logchunk” (the function to call for each logformat symbol) with

  1. struct uwsgi_logchunk *uwsgi_register_logchunk(char *name, ssize_t (*func)(struct wsgi_request *, char **), int need_free);
  • name – the name of the symbol
  • need_free – if 1, means the pointer set by func must be free()d
  • func – the function to call in the log handler
  1. static ssize_t uwsgi_lf_foobar(struct wsgi_request *wsgi_req, char **buf) {
  2. *buf = uwsgi_num2str(wsgi_req->status);
  3. return strlen(*buf);
  4. }
  5.  
  6. static void register_logchunks() {
  7. uwsgi_register_logchunk("foobar", uwsgi_lf_foobar, 1);
  8. }
  9.  
  10. struct uwsgi_plugin foobar_plugin = {
  11. .name = "foobar",
  12. .on_load = register_logchunks,
  13. };

Now if you load the foobar plugin, you will be able to use the %(foobar) request logging variable (that would report the request status).