python-json-logger icon indicating copy to clipboard operation
python-json-logger copied to clipboard

Use ujson instead of standard library json

Open logileifs opened this issue 5 years ago • 1 comments

I've been trying to use ujson to serialize the records to string but I can't get it to work, I always get an error on line 172 in jsonlogger.py: ensure_ascii=self.json_ensure_ascii) TypeError: an integer is required (got type NoneType)

In my logging handler I'm doing this: self.formatter = CustomJsonFormatter( '(timestamp) (level) (name) (message)', json_serializer='ujson.dumps', )

I've tried passing json_ensure_ascii=True as well but that doesn't seem to have any effect

logileifs avatar Oct 05 '19 12:10 logileifs

The error is misleading due to the way Python renders type errors: because the TypeError was assigned to the function call it renders the last line of the function call, however the trouble is the entire

        return self.json_serializer(log_record,
                                    default=self.json_default,
                                    cls=self.json_encoder,
                                    indent=self.json_indent,
                                    ensure_ascii=self.json_ensure_ascii)

call: one of the parameter is a None where ujson.dumps requires an integer (if the parameter is passed in at all).

Given the listed parameters, I would assume "indent" is the issue: the standard library's json uses None as default value and placeholder for "compact representation". According to is readme, ujson uses 0 instead, and it does blow up with the exact error message you list when given a None:

>>> import json, ujson
>>> json.dumps({}, indent=None)
'{}'
>>> json.dumps({}, indent=0)
'{}'
>>> ujson.dumps({}, indent=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an integer is required (got type NoneType)
>>> ujson.dumps({}, indent=0)
'{}'

JsonFormatter's json_indent defaults to None. If you provide an explicit value of 0 instead, things should work properly.

Alternatively, you can pass a function (lambda) as your json_serializer and call ujson.dumps with whatever parameters you need:

Formatter(..., json_serializer=lambda obj, *args, **kwargs: usjon.dumps(obj))

though beware that you won't get the formatting & stringification jsonlogger performs by default.

xmo-odoo avatar Nov 19 '19 10:11 xmo-odoo