Skip to main content

A way to use stdlib's logging with the new Format Specification Mini-Language.

Project description

foffinf

A way to use stdlib's logging with the new Format Specification Mini-Language.

What?

We know it's bad to do this:

logger.info(f"The result is {result:05d}")

We should never build the log message ourselves, basically because two situations that are avoided by properly using logging:

  • performance: if the logging level is below INFO (in the case of the example) the resulting message is not really built
  • robustness: if result happens to not be a number, that example will crash, but the logging infrastructure will just present some error message (and everything will continue)

The recommended way is:

logger.info("The result is %05d", result)

But wait, we're living in the 21st century, are we still using printf-style string formatting?

With foffinf we can now write:

logger.info("The result is {:05d}", result)

Welcome to the future!

dino

Trust the dino :)

How to use it

Sadly we can not set up the whole logging system in our process to this new format, because most probably we will be using 3rd party libraries that actually have log calls using the old way, and we shall not break them.

So we need to indicate which module (the one we're writing, of course) shall use it. This is done with a foffinf.formatize call. As is standard to use the module's name, we can just:

import logging
import foffinf

foffinf.formatize(__name__)
logger = logging.getLogger(__name__)

# ...

logger.info("The result is {:05d}", result)

Affecting a specific logger module will not affect its parent or any sibling.

fofinff.formatize("mylib.mod1")

logging.getLogger("mylib.mod1")  # affected!
logging.getLogger("mylib")  # NOT affected
logging.getLogger("mylib.mod2")  # NOT affected
logging.getLogger()  # NOT affected
logging.getLogger("otherlib")  # NOT affected
logging.getLogger("mylib.mod1.submod")  # NOT affected

Note (in that last line) that by default it will neither affect submodules. To affect all children of a logger tree node:

fofinff.formatize("mylib.mod1", scatter=True)

logging.getLogger("mylib.mod1")  # affected!
logging.getLogger("mylib")  # NOT affected
logging.getLogger("mylib.mod2")  # NOT affected
logging.getLogger("mylib.mod1.submod_a")  # affected!
logging.getLogger("mylib.mod1.submod_b")  # affected!

I can't make it work when setup logging in a helper file

It's typical to have this structure:

.
├── somefile
├── LICENSE
├── otherfiles
├── the_super_lib
│   ├── magic_code.py
│   ├── some_log_setup.py
│   ├── etc.py
├── README.md
└── ...

In all parts of your code, you just do

logger = logging.getLogger(__name__)

But the logging setup is done in a module inside your lib, some_log_setup.py. In this case is exactly where you need to use the scatter parameter explained before, stating explicitly the root of your lib.

So, inside some_log_setup.py:

import foffinf
...
foffinf.formatize("the_super_lib", scatter=True)

This will formatize the calls in all your library's logging tree without affecting other libraries.

What about using named replacements?

The logging module treats a passed single dictionary as the possible replacements for named values. We honour that, so this is supported:

>>> info = {"foo": 3, "bar": 5}
>>> logger.info("The result is {foo} and {bar}", result)
The result is 3 and 5

If a single no-named parameter is used the dictionary is just shown:

>>> info = {"foo": 3, "bar": 5}
>>> logger.info("The result is {}", result)
The result is {"foo": 3, "bar": 5}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

foffinf-0.4.tar.gz (8.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

foffinf-0.4-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file foffinf-0.4.tar.gz.

File metadata

  • Download URL: foffinf-0.4.tar.gz
  • Upload date:
  • Size: 8.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for foffinf-0.4.tar.gz
Algorithm Hash digest
SHA256 6746bf81aaca1581e3d3a0373ac25be759285d09256c06cd13ea538085ed4b5e
MD5 539f647335a0edd62bf9bde25b48ea36
BLAKE2b-256 6aacaf6d7619f7a9cef375738aad287ee6724a0b79840d0052d6b90c49558c5f

See more details on using hashes here.

File details

Details for the file foffinf-0.4-py3-none-any.whl.

File metadata

  • Download URL: foffinf-0.4-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for foffinf-0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b80c125c5baa8b0f4033d96781fe7b2edbfaeff31bd57de9750aefc7c4a2fa66
MD5 8bb64daceb01bf15d1d47dba652f34f4
BLAKE2b-256 5ce5bb83656392f43128530fb7a0dd3d499af9f005b66cc7b177a294fb376ea4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page