Log encoders

uWSGI 1.9.16 got the “log encoding” feature.

An encoder receives a logline and give back a “transformation” of it.

Encoders can be added by plugins, and can be enabled in chain (the output of an encoder will be the input of the following one and so on).

[uwsgi]
; send logs to udp address 192.168.173.13:1717
logger = socket:192.168.173.13:1717
; before sending a logline to the logger encode it in gzip
log-encoder = gzip
; after gzip add a 'clear' prefix to easy decode
log-encoder = prefix i am gzip encoded
...

with this configuration the log server will receive the “i am gzip encoded” string followed by the tru log message encoded in gzip

The log encoder syntax is the following:

log-encoder = <encoder>[ args]

so args (if any) are separated by a single space

Request logs VS stdout/stderr

The –log-encoder option encodes only the stdout/stderr logs.

If you want to encode request logs to use –log-req-encoder:

[uwsgi]
; send request logs to udp address 192.168.173.13:1717
req-logger = socket:192.168.173.13:1717
; before sending a logline to the logger encode it in gzip
log-req-encoder = gzip
; after gzip add a 'clear' prefix to easy decode
log-req-encoder = prefix i am gzip encoded
...

Routing encoders

Log routing allows sending each logline to a different log engine based on regexps. You can use the same system with encoders too:

[uwsgi]
; by default send logs to udp address 192.168.173.13:1717
logger = socket:192.168.173.13:1717
; an alternative logger using the same address
logger = secondlogger socket:192.168.173.13:1717
; use 'secondlogger' for the logline containing 'uWSGI'
log-route = secondlogger uWSGI
; before sending a logline to the 'secondlogger' logger encode it in gzip
log-encoder = gzip:secondlogger
...

Core encoders

The following encoders are available in the uwsgi ‘core’:

prefix add a raw prefix to each log msg

suffix add a raw suffix to each log msg

nl add a newline char to each log msg

gzip compress each msg with gzip (requires zlib)

compress compress each msg with zlib compress (requires zlib)

format apply the specified format to each log msg:

[uwsgi]
...
log-encoder = format [FOO ${msg} BAR]
...

json like format but each variable is json escaped

[uwsgi]
...
log-encoder = json {"unix":${unix}, "msg":"${msg}"}
...

The following variables (for format and json) are available:

${msg} the raw log message (newline stripped)

${msgnl} the raw log message (with newline)

${unix} the current unix time

${micros} the current unix time in microseconds

${strftime:xxx} strftime using the xxx format:

[uwsgi]
...
; we need to escape % to avoid magic vars nameclash
log-encoder = json {"unix":${unix}, "msg":"${msg}", "date":"${strftime:%%d/%%m/%%Y %%H:%%M:%%S}"}
...

The msgpack encoder

This is the first log-encoder plugin officially added to uWSGI sources. It allows encoding of loglines in msgpack (http://msgpack.org/) format.

The syntax is pretty versatile as it has been developed for adding any information to a single packet

log-encoder = msgpack <format>

format is pretty complex as it is a list of the single items in the whole packet.

For example if you want to encode the {‘foo’:’bar’, ‘test’:17} dictionary you need to read it as:

a map of 2 items | the string foo | the string bar | the string test | the integer 17

for a total of 5 items.

A more complex structure {‘boo’:30, ‘foo’:’bar’, ‘test’: [1,3,3,17.30,nil,true,false]}

will be

a map of 3 items | the string boo | the number 30| the string foo| the string bar | the string test | an array of 7 items | the integer 1 | the integer 3 | the integer 3 | the float 17.30 | a nil | a true | a false

The <format> string is a representation of this way:

map:2|str:foo|str:bar|str:test|int:17

The pipe is the seprator of each item. The string before the colon is the type of item, followed by the optional argument

The following item types are supported:

map a dictionary, the argument is the number of items

array an array, the argument is the number of items

str a string, the argument is the string itself

bin a byte array, the argument is the binary stream itself

int an integer, the argument is the number

float a float, the argument is the number

nil undefined/NULL

true boolean TRUE

false boolean FALSE

in addition to msgpack types, a series of dynamic types are available:

msg translate the logline to a msgpack string with newline chopped

msgbin translate the logline to a msgpack byte array with newline chopped

msgnl translate the logline to a msgpack string (newline included)

msgbin translate the logline to a msgpack byte array (newline included)

unix translate to an integer of the unix time

micros translate to an integer of the unix time in microseconds

strftime translate to a string using strftime syntax. The strftime format is the argument

As an example you can send logline to a logstash server via udp:

(logstash debug configuration):

input {
     udp {
             codec =>   msgpack {}
             port => 1717
     }
}
output {
     stdout { debug => true }
     elasticsearch { embedded => true }
}
[uwsgi]
logger = socket:192.168.173.13:1717
log-encoder = msgpack map:4|str:message|msg|str:hostname|str:%h|str:version|str:%V|str:appname|str:myapp
...

this will generate the following structure:

{
   "message": "*** Starting uWSGI 1.9.16-dev-29d80ce (64bit) on [Sat Sep  7 15:04:32 2013] ***",
   "hostname": "unbit.it",
   "version": "1.9.16-dev",
   "appname": "myapp"
}

that will be stored in elasticsearch

Notes

Encoders automatically enable –log-master

For best performance consider allocating a thread for log sending with –threaded-logger