Message PyLint: interpolation-format-de-journalisation

161

Pour le code suivant:

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

pylint produit l'avertissement suivant:

interpolation-format-de-journalisation (W1202):

Utilisez le formatage% dans les fonctions de journalisation et transmettez les paramètres% en tant qu'arguments Utilisé lorsqu'une instruction de journalisation a une forme d'appel de «journalisation. (Format_string.format (format_args ...))». De tels appels devraient utiliser le formatage% à la place, mais laisser l'interpolation à la fonction de journalisation en passant les paramètres comme arguments.

Je sais que je peux désactiver cet avertissement, mais j'aimerais le comprendre. J'ai supposé que l'utilisation format()était la meilleure façon d'imprimer des instructions en Python 3. Pourquoi n'est-ce pas vrai pour les instructions de journalisation?

pfnuesel
la source

Réponses:

204

Ce n'est pas vrai pour l'instruction logger car elle s'appuie sur l'ancien format "%" comme string pour fournir une interpolation paresseuse de cette chaîne en utilisant des arguments supplémentaires donnés à l'appel du logger. Par exemple au lieu de faire:

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

tu devrais faire

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

donc la chaîne ne sera interpolée que si le message est effectivement émis.

Vous ne pouvez pas bénéficier de cette fonctionnalité lors de l'utilisation .format().


Selon la section Optimisation de la loggingdocumentation:

Le formatage des arguments de message est différé jusqu'à ce qu'il ne puisse pas être évité. Cependant, le calcul des arguments passés à la méthode de journalisation peut également être coûteux, et vous voudrez peut-être éviter de le faire si l'enregistreur va simplement rejeter votre événement.

sthenault
la source
4
@pfnuesel, .format () est développé avant l'appel à logger.error, tandis que "l'interpolation paresseuse" signifie que l'expansion n'est effectuée que si nécessaire (par exemple, le message est en fait affiché quelque part)
sthenault
10
Existe-t-il une bonne référence pour que cette évaluation paresseuse soit préférée et fasse une différence? Je n'ai pas pu en trouver un dans PEP282 ou dans la bibliothèque de journalisation
culix
25
Mais cela signifie-t-il simplement que nous aurons des problèmes de maintenance avec notre code plus tard? Serons-nous plus tard «recommandés» par pylint pour passer au .format()style à un moment donné parce qu'il logginga été mis à niveau? Je demande parce que je suis plus intéressé par la maintenabilité que par les performances de vitesse de pointe, du moins pour la plupart des tâches.
Mike Williamson
3
@MikeWilliamson: Je pense que ce message est un avertissement car il y a des effets secondaires possibles, mais vous pouvez l'ignorer en toute sécurité.
saihtamtellim
5
Bien qu'une grande partie de la motivation derrière l'avertissement concerne les performances (c'est-à-dire si une instruction de journal n'est pas émise, le coût d'interpolation est économisé), il convient de noter que dans de nombreuses applications (sans doute la plupart), le coût des performances est négligeable. Voir: github.com/PyCQA/pylint/issues/2395 et github.com/PyCQA/pylint/issues/2354
Adam Parkin
23

Peut-être que cette différence de temps peut vous aider.

La description suivante n'est pas la réponse à votre question, mais elle peut aider les gens.

Pour pylint 2.4: Il y a 3 options pour le style journalisation dans le .pylintrcfichier: old, new,fstr

fstroption ajoutée en 2.4 et supprimée en 2.5

Description du .pylintrcfichier (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

pour l' ancien ( logging-format-style=old):

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

pour nouveau ( logging-format-style=new):

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

Remarque : vous ne pouvez pas utiliser .format()même si vous sélectionneznew option.

pylint donne toujours le même avertissement pour ce code:

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

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

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

Personnellement, je préfère l'option fstr à cause de PEP-0498 .

Mustafagok
la source
2
vous pouvez ajouter "python.linting.pylintArgs": ["--logging-format-style=old"]au fichier vscode / settings.json. docs
mustafagok
2
dans pylint 2.3.1: la optparse.OptionValueError: option logging-format-style: invalid value: 'fstr', should be in ['old', 'new']mise à niveau vers le dernier pylint (2.4.4) a corrigé ce problème.
Florian Castellane le
J'ai l'erreur suivante:Try installing a more recent version of python-pylint, and please open a bug report if the issue persists in t\ he latest release. Thanks!
alper le
4

D'après mon expérience, une raison plus convaincante que l'optimisation (pour la plupart des cas d'utilisation) de l'interpolation paresseuse est qu'elle joue bien avec les agrégateurs de journaux comme Sentry.

Considérez un message de journal «utilisateur connecté». Si vous interpolez l'utilisateur dans la chaîne de format, vous avez autant de messages de journal distincts que d'utilisateurs. Si vous utilisez une interpolation paresseuse comme celle-ci, l'agrégateur de journaux peut plus raisonnablement interpréter cela comme le même message de journal avec un tas d'instances différentes.

Tristan Crockett
la source