PyLint消息:日志记录格式插值

问题:PyLint消息:日志记录格式插值

对于以下代码:

logger.debug('message: {}'.format('test'))

pylint 产生以下警告:

日志记录格式插值(W1202):

在日志记录函数中使用%格式,并将%参数作为参数传递。在日志记录语句的调用形式为“ logging。(format_string.format(format_args …))”时使用。此类调用应改为使用%格式,但通过将参数作为参数传递,将插值留给日志记录函数。

我知道我可以关闭此警告,但我想理解它。我假定使用format()是在Python 3中打印语句的首选方法。为什么这对于logger语句不是正确的?

For the following code:

logger.debug('message: {}'.format('test'))

pylint produces the following warning:

logging-format-interpolation (W1202):

Use % formatting in logging functions and pass the % parameters as arguments Used when a logging statement has a call form of “logging.(format_string.format(format_args…))”. Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.

I know I can turn off this warning, but I’d like to understand it. I assumed using format() is the preferred way to print out statements in Python 3. Why is this not true for logger statements?


回答 0

logger语句不是正确的,因为它依赖于以前的“%”格式(例如字符串)来使用给logger调用提供的额外参数来对该字符串进行延迟插值。例如,而不是做:

logger.error('oops caused by %s' % exc)

你应该做

logger.error('oops caused by %s', exc)

因此,仅当实际发出消息时才对字符串进行插值。

使用时,您将无法利用此功能.format()


根据文档的“ 优化”部分logging

消息参数的格式将推迟到无法避免为止。但是,计算传递给日志记录方法的参数也可能很昂贵,并且如果记录器将只是丢弃您的事件,则可能要避免这样做。

It is not true for logger statement because it relies on former “%” format like string to provide lazy interpolation of this string using extra arguments given to the logger call. For instance instead of doing:

logger.error('oops caused by %s' % exc)

you should do

logger.error('oops caused by %s', exc)

so the string will only be interpolated if the message is actually emitted.

You can’t benefit of this functionality when using .format().


Per the Optimization section of the logging docs:

Formatting of message arguments is deferred until it cannot be avoided. However, computing the arguments passed to the logging method can also be expensive, and you may want to avoid doing it if the logger will just throw away your event.


回答 1

也许这段时间的差异可以帮助您。

以下描述不是您问题的答案,但可以帮助人们。

对于pylint的2.4:对于中记录样式3个选择.pylintrc文件:oldnewfstr

fstr选项在2.4中添加,在2.5中删除

.pylintrc文件说明(v2.4):

[LOGGING]

# Format style used to check logging format string. `old` means using %
# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings.
logging-format-style=old

对于旧的logging-format-style=old):

foo = "bar"
self.logger.info("foo: %s", foo)

对于logging-format-style=new):

foo = "bar"
self.logger.info("foo: {}", foo)
# OR
self.logger.info("foo: {foo}", foo=foo)

注意:即使选择选项,也无法使用。.format()new

pylint 对于此代码仍然给出相同的警告

self.logger.info("foo: {}".format(foo))  # W1202
# OR
self.logger.info("foo: {foo}".format(foo=foo))  # W1202

对于fstrlogging-format-style=fstr):

foo = "bar"
self.logger.info(f"foo: {foo}")

就个人而言,由于PEP-0498,我更喜欢fstr选项。

Maybe this time differences can help you.

Following description is not the answer for your question, but it can help people.

If you want to use fstrings (Literal String Interpolation) for logging, then you can disable it from .pylintrc file with disable=logging-fstring-interpolation, see: related issue and comment.

Also you can disable logging-format-interpolation.


For pylint 2.4:

There are 3 options for logging style in the .pylintrc file: old, new, fstr

fstr option added in 2.4 and removed in 2.5

Description from .pylintrc file (v2.4):

[LOGGING]

# Format style used to check logging format string. `old` means using %
# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings.
logging-format-style=old

for old (logging-format-style=old):

foo = "bar"
self.logger.info("foo: %s", foo)

for new (logging-format-style=new):

foo = "bar"
self.logger.info("foo: {}", foo)
# OR
self.logger.info("foo: {foo}", foo=foo)

Note: you can not use .format() even if you select new option.

pylint still gives the same warning for this code:

self.logger.info("foo: {}".format(foo))  # W1202
# OR
self.logger.info("foo: {foo}".format(foo=foo))  # W1202

for fstr (logging-format-style=fstr):

foo = "bar"
self.logger.info(f"foo: {foo}")

Personally, I prefer fstr option because of PEP-0498.


回答 2

以我的经验,对于惰性插值而言,比优化(对于大多数用例)更令人信服的原因是,它与Sentry之类的日志聚合器配合得很好。

考虑“用户已登录”日志消息。如果将用户插值到格式字符串中,则与用户一样多的不同日志消息。如果您像这样使用惰性插值,则日志聚合器可以更合理地将其解释为具有多个不同实例的同一条日志消息。

In my experience a more compelling reason than optimization (for most use cases) for the lazy interpolation is that it plays nicely with log aggregators like Sentry.

Consider a ‘user logged in’ log message. If you interpolate the user into the format string, you have as many distinct log messages as there are users. If you use lazy interpolation like this, the log aggregator can more reasonably interpret this as the same log message with a bunch of different instances.