2

I am using Python 3.8.8 with the included logging library. To have a common string format in Python, I wanted to use also for logging the new format string variant with {}. I also want to use lazy evaluation of the logging string (so no "{}".format(var) or f"{var}").

According to this Stack Overflow post about pylint (so pylint logging-format-style=new), the following variant should work. However, there is an exception at logging.info.

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

var1 = "foo"
var2 = "blub"

logger.info("var1 {}, var2 {}", var1, var2) # Exception thrown!

The exception in the last line is as follows:

--- Logging error ---
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/logging/__init__.py", line 1081, in emit
    msg = self.format(record)
  File "/usr/local/lib/python3.8/logging/__init__.py", line 925, in format
    return fmt.format(record)
  File "/usr/local/lib/python3.8/logging/__init__.py", line 664, in format
    record.message = record.getMessage()
  File "/usr/local/lib/python3.8/logging/__init__.py", line 369, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting

I infered from the exception message that logging still expects the old style formatting with %s.

How can I use the new format string variant with {} at logging in Python 3.8.8 without using any additional wrapper function (as suggested by some other posts on Stack Overflow)? Although possible to define in pylint, is this maybe even not possible without any wrapper function?

Fabian
  • 403
  • 5
  • 13
  • Does this answer your question? [Logging variable data with new format string](https://stackoverflow.com/questions/13131400/logging-variable-data-with-new-format-string) – jonrsharpe Mar 31 '21 at 14:57
  • 1
    Fundamentally this is still true: [*"There would no changing this while preserving backward compatibility, since all logging calls which are out there in existing code will be using %-format strings."*](https://docs.python.org/3/howto/logging-cookbook.html#using-particular-formatting-styles-throughout-your-application) – jonrsharpe Mar 31 '21 at 15:03
  • @jonrsharpe Thanks for the suggestion of [that post](https://stackoverflow.com/questions/13131400/logging-variable-data-with-new-format-string). Before asking this question, I have already looked at that but this does not answer my question because first, it's Python 2.7, and second, it is using some wrapper function and by using already Python 3.8 I hope that's no more needed. – Fabian Mar 31 '21 at 17:51
  • The quote I posted is from the 3.latest docs, it hasn't somehow suddenly become the case that the logging calls in existence *aren't* using %. The fact that you don't like those answers doesn't make them not the answers. – jonrsharpe Mar 31 '21 at 18:25
  • @jonrsharpe My first comment was an answer to your first comment. Until now I didn't have time to look more detailed on your quote from the logging docs but I checked it now. It is true that I would have liked that there are already some changes from 2.7 to 3.8 but for me knowing that this still does not work, is also a totally valid and acceptable answer. Feel free to write this as an answer to the question and I will accept that. Otherwise I will write the answer to my question by myself. – Fabian Apr 01 '21 at 11:47
  • In any case, I still find it weird that pylint has an option to use new style logging formatting (`logging-format-style=new`) altough the logging library doesn't even support that. – Fabian Apr 01 '21 at 11:49

1 Answers1

0

I think Python string interpolation is easier to work with:

logger.info(f"var1 {var1}, var2 {var2}") 

To achieve lazy evaluation,

if logger.isEnabledFor(logging.INFO):
    logger.info(f"var1 {var1}, var2 {var2}") 
Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
  • 1
    This misses the entire point of the question. Passing an uninterpolated string to `logger.X` will interpolate the string only if it will be emitted – DeepSpace Mar 31 '21 at 14:53
  • No. The next best thing is to keep using `%s` or creating a custom style: https://stackoverflow.com/questions/13131400/logging-variable-data-with-new-format-string – DeepSpace Mar 31 '21 at 14:57
  • A need for lazy evaluation was not mentioned by the OP – Mike Slinn Mar 31 '21 at 15:10
  • @MikeSlinn Thank you for the suggestion. You are right, lazy evaluation was not mentionend from my side but it is something that I would like to have. I have updated my question. About your answer, yes, it works but for me using `logger.isEnabledFor` doesn't sound like an elegant solution but more like a workaround (especially if there is not just one log message but likely quite many) – Fabian Mar 31 '21 at 17:57
  • @Fabian, you could cache the enabled state in a var `e = logger.isEnabledFor(logging.INFO)` and then use boolean shortcut logic like this `e and logger.info(f"var1 {var1}, var2 {var2}")`. If `e` is false, the rest won't be evaluated. – David K. Hess Dec 18 '21 at 15:01