Framework
- Flake8
flake8-logging-format
Flake8 extension to validate (lack of) logging format strings
What's This?
Python logging supports a special extra keyword
for passing a dictionary of user-defined attributes to include in a logging event. One way to ensure consistency and
rigor in logging is to always use extra to pass non-constant data and, therefore, to never use format strings,
concatenation, or other similar techniques to construct a log string.
In other words, do this:
logger.info(
"Hello {world}",
extra=dict(
world="Earth"
)
)
Instead of:
logger.info(
"Hello {world}".format(world=Earth)
)
Extra Whitelist
As a further level of rigor, we can enforce that extra dictionaries only use keys from a well-known whitelist.
Usage:
flake8 --enable-extra-whitelist
The built-in Whitelist supports plugins using entry_points with a key of "logging.extra.whitelist". Each
registered entry point must be a callable that returns an iterable of string.
In some cases you may want to log sensitive data only in debugging scenarios. This is supported in 2 ways:
- We do not check the logging.extra.whitelist for lines logged at the
debuglevel - You may also prefix a keyword with 'debug_' and log it at another level. You can safely assume these will be filtered out of shipped logs.
Violations Detected
G001Logging statements should not usestring.format()for their first argumentG002Logging statements should not use%formatting for their first argumentG003Logging statements should not use+concatenation for their first argumentG004Logging statements should not usef"..."for their first argument (only in Python 3.6+)G010Logging statements should not usewarn(usewarninginstead)G100Logging statements should not useextraarguments unless whitelistedG101Logging statement should not useextraarguments that clash with LogRecord fieldsG200Logging statements should not include the exception in logged string (useexceptionorexc_info=True)G201Logging statements should not useerror(..., exc_info=True)(useexception(...)instead)G202Logging statements should not use redundantexc_info=Trueinexception
These violations are disabled by default. To enable them for your project, specify the code(s) in your setup.cfg:
[flake8]
enable-extensions=G
Motivation
Our motivation has to do with balancing the needs of our team and those of our customers. On the one hand, developers and front-line support should be able to look at application logs. On the other hand, our customers don't want their data shared with anyone, including internal employees.
The implementation approaches this in two ways:
-
By trying to prevent the use of string concatenation in logs (vs explicit variable passing in the standard logging
extradictionary) -
By providing an (optional) mechanism for whitelisting which field names may appear in the
extradictionary
Naturally, this does not prevent developers from doing something like:
extra=dict(
user_id=user.name,
)
but then avoiding a case like this falls back to other processes around pull-requests, code review and internal policy.