wearpants / twiggy

Pythonic logger, shipped in Redhat & Debian
BSD 3-Clause "New" or "Revised" License
47 stars 11 forks source link

Print literal braces with out erroring #82

Closed MatthewScholefield closed 6 years ago

MatthewScholefield commented 6 years ago
>>> from twiggy import quick_setup, log
>>> quick_setup()
>>> log.debug('My data:' + str({'this': 'is a test'}))
2017-11-17T06:25:47Z:INFO:twiggy.internal|Error formatting message level: <LogLevel DEBUG>, format: "My data:{'this': 'is a test'}", fields: {'time': <built-in function gmtime>}, options: {'trace': None, 'style': 'braces', 'suppress_newlines': True}, args: (), kwargs: {}
TRACE Traceback (most recent call last):
TRACE   File "/usr/lib/python3.5/site-packages/twiggy/logger.py", line 246, in _emit
TRACE     msg = Message(level, format_spec, self._fields.copy(), self._options.copy(), args, kwargs)
TRACE   File "/usr/lib/python3.5/site-packages/twiggy/message.py", line 86, in __init__
TRACE     s = format_spec.format(*args, **kwargs)
TRACE KeyError: "'this'"

I'm assuming it's treating the JSON as something to pass to format like "{0}".format, however, can this exception be caught and it fail by just logging the plain text?

As a side note, two better alternatives would be:

log.fields(**{'this': 'is a test'}).debug('My data')
log.debug('My data: {}', {'this': 'is a test'})
wearpants commented 6 years ago

Not sure I see the problem here... you're passing a new-style format string for the text part of the message, if you want to include literal braces in that, you need to escape them here same as anywhere else.

If you'd like to log some JSON, pass values to fields(..) and then JSONify in a Twiggy output, rather than inline in your code... make sense?

MatthewScholefield commented 6 years ago

What do you mean by JSONifying twiggy output with fields? What I'm getting at is: I used to use Python's logging module to log some data structures. Something like this:

data = {"type": 12, "data": ["This is the data"]}
logger.debug(str(data))

What's the correct way to do that with Twiggy? I get that I'm passing an invalid format string, but other loggers don't format messages by default. Is there a way to set something like .options(style='percent') for all logs?

MatthewScholefield commented 6 years ago

Also, in general, I think it's useful to have some way to print unformatted text. For instance:

query = input('Enter a query:')
web_response = fetch_response(query)
log.debug(web_response)  # Kaboom!
# ...
print('Your answer is:', answer)
Enter a query: something
17.11.30 - 04:43:08 : INFO : twiggy.internal|Error formatting message level: <LogLevel DEBUG>, format: 'Answer Body: <p>Yes it is possible, just provide the <code>colorid</code> parameter when adding an event. You can retrieve the list of colours from the <a href="https://developers.google.com/google-apps/calendar/v3/reference/colors/get" rel="nofollow noreferrer">colors endpoint</a>.</p>\n\n<p>Here is a sample code for getting the list of colors:</p>\n\n<pre><code>$colors = $service-&gt;colors-&gt;get();\n\n// Print available calendarListEntry colors.\nforeach ($colors-&gt;getCalendar() as $key =&gt; $color) {\n  print "colorId : {$key}\\n";\n  print "  Background: {$color-&gt;getBackground()}\\n";\n  print "  Foreground: {$color-&gt;getForeground()}\\n";\n}\n// Print available event colors.\nforeach ($colors-&gt;getEvent() as $key =&gt; $color) {\n  print "colorId : {$key}\\n";\n  print "  Background: {$color-&gt;getBackground()}\\n";\n  print "  Foreground: {$color-&gt;getForeground()}\\n";\n}\n</code></pre>\n\n<p>You can also check this <a href="https://eduardopereira.pt/wp-content/uploads/2012/06/google_calendar_api_event_color_chart.png" rel="nofollow noreferrer">Google Calendar v3 events color</a>.</p>\n\n<p>Hope this helps.</p>\n', fields: {'time': <built-in function gmtime>}, options: {'style': 'braces', 'trace': None, 'suppress_newlines': True}, args: (), kwargs: {}
TRACE Traceback (most recent call last):
TRACE   File "/home/matthew/.virtualenvs/mycroft-light/lib/python3.5/site-packages/twiggy/logger.py", line 246, in _emit
TRACE     msg = Message(level, format_spec, self._fields.copy(), self._options.copy(), args, kwargs)
TRACE   File "/home/matthew/.virtualenvs/mycroft-light/lib/python3.5/site-packages/twiggy/message.py", line 86, in __init__
TRACE     s = format_spec.format(*args, **kwargs)
TRACE KeyError: '\n  print "colorId '
Your answer is: now mixed with throwup
wearpants commented 6 years ago

The correct way would be to stuff your data in fields(..), then write a formatter (sorry, not an output) to JSON-ify it. See http://twiggy.readthedocs.io/en/stable/configuration.html#formats and #85.

That this works in stdlib logging is an artifact of printf (aka percent) formatting, which will happily splat out strings even if there aren't enough parameters passed. If you want to use braces, create a new log object in your code and use that:

from twiggy import log
log = log.options(style='percent') # new local logger instance

query = input('Enter a query:')
web_response = fetch_response(query)
log.debug(web_response)  # Kaboom!
# ...
print('Your answer is:', answer)

See also #86, which would add explicit support for literal strings, as well as repr()ing a raw object