title: Python 3.7 logging: f-strings vs %
body: <p>I'm running into a performance problem in a project, and I narrowed it down to some of the log lines. It seems that f-strings are calculated even when my logging facility is above the level of the line that is logging.  </p>
  
  <p>Consider this example to demonstrate the issue: </p>
  
  <pre><code>import logging
  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger('MyLogger')
  
  class MyClass:
      def __init__(self, name: str) -&gt; None:
          self._name = name
      def __str__(self) -&gt; str:
          print('GENERATING STRING')
          return self._name
  
  c = MyClass('foo')
  logger.debug(f'Created: {c}')
  </code></pre>
  
  <p>When this example is run, I get "GENERATING STRING" printed to screen, indicating that the <code>__str__</code> method is being ran even though my logging level is set to <code>INFO</code> and the log line is for <code>DEBUG</code>.  </p>
  
  <p>From what I can tell today, the solution is to use the following vs an f-string. </p>
  
  <pre><code>logger.debug('Created: %s', c)
  </code></pre>
  
  <p>There are three things going through my head right now. </p>
  
  <ul>
  <li>Most of the examples and docs I read seem to be pretty old.</li>
  <li>This project is Python 3.7+ only (not worried about being backwards compatible).   </li>
  <li>I have a lot of lines of code to update. </li>
  </ul>
  
  <p>I'm curious to know what others do in this situation.  Is the <code>%s</code> the best (most modern) approach?  Is there a more modern way that I should be logging as demonstrated above? </p>
  
  <p>I have a lot of code to update (fix), and I'm hoping to align with modern best practices. </p>