1. Flexible logging¶
Python’s standard logging module was conceived some time ago. It can be difficult to configure and it lacks the ability to easily communicate structured data.
The Turberfield logger
module is designed
for use in both web-native applications and offline tooling.
It is flexible and easily customisable.
from turberfield.utils.logger import LogManager
logger = LogManager().get_logger("root")
logger.info("Hello, World!")
2022-05-25 18:40:00.766978| INFO|root| Hello, World!
The main feature of these Loggers is that you can set them to format any arbitrary data you might want to send them.
A logger has a frame which is a list of the formats of all the fields it can present to a LogAdapter.
print(logger.frame)
['{now}', '{level.name:>8}', '{logger.name}', ' {0}']
This frame can be modified at run time to add extra fields to the log. Unlike the standard logging module, it doesn’t matter if that data is missing:
import http
logger.frame += ["{status.name}"]
logger.info("Situation report", status=http.HTTPStatus.OK)
2022-05-25 18:53:51.767937| INFO|root| Situation report|OK
You can supply a customised LogAdapter to perform filtering or reformatting on an endpoint-specific basis.
import re
import platform
from turberfield.utils.logger import LogAdapter
class Alarmist(LogAdapter):
patterns = [
(re.compile("NOTE"), (234, 0, 255)),
(re.compile("INFO"), (0, 255, 255)),
(re.compile("ERROR"), (234, 255, 0)),
(re.compile("WARNING"), (255, 106, 0)),
(re.compile("CRITICAL"), (255, 0, 106)),
]
def colour_field(self, field, word):
if "level" in field:
r, g, b = next(
(c for r, c in self.patterns if r.search(word)),
(200, 200, 200)
)
return f"[38;2;{r};{g};{b}m{word}[0m"
else:
return word
def render(self, entry):
if platform.system().lower() == "windows":
return super().render(entry)
return "|".join(
self.colour_field(f, w)
for f, w in zip(entry.origin.frame, entry.tokens)
)
Once you have configured a logger, you can clone it as the basis of another.
root_logger = log_manager.get_logger("root")
logger = root_logger.clone("main")
logger.set_route(logger.Level.INFO, Alarmist(), sys.stderr)
logger.info("Hello, World!")
logger.warning("Stay safe out there!")
This example is included in the module. Run python -m turberfield.utils.logger
to see
that these log entries are now in colour on the terminal.
By default, logging goes to sys.stderr. You can log to a file by passing the necessary path.
logger.set_route(logger.Level.DEBUG, LogAdapter(), pathlib.Path("logger.log"))
logger.error("I didn't mean that.")
logger.debug("It doesn't hurt to check.")
logger.note("Whistle a happy tune!")
logger.critical(
"We've run out of disk space!",
status=http.HTTPStatus.INSUFFICIENT_STORAGE
)
$ cat logger.log
2022-05-25 19:11:55.260938| ERROR|main| I didn't mean that.|
2022-05-25 19:11:55.261088| DEBUG|main| It doesn't hurt to check.|
2022-05-25 19:11:55.261178| NOTE|main| Whistle a happy tune!|
2022-05-25 19:11:55.261241|CRITICAL|main| We've run out of disk space!|INSUFFICIENT_STORAGE