Verbosity Feature
Splatlog has a verbosity system that allows you to configure which loggers are set to which level as you twist the knob on a single verbosity parameter.
Verbosity Values (splatlog.typing.Verbosity)
- A verbosity is an int.
- It can not be negative.
- It must be less than
sys.maxint. - In practice it usually ranges from
0to4-or-so. - The higher the verbosity, the more logging you see.
You can test if a value is a verbosity with splatlog.typings.isVerbosity and
cast to a verbosity with splatlog.typings.asVerbosity. See documentation for
those function for examples.
Verbosity is directly inspired by the -v, -vv, -vvv, ... pattern of option
flags common in command line interfaces on unix-like systems.
Verbosity Levels
To use verbosity, you provide a verbosity levels mapping.
- Each key is a logger name (type str).
- The coresponding value is a sequence of tuple pairs.
- The first element is a verbosity, as discussed above.
- The second element is the log level to take effect at that verbosity.
To apply verbosity levels globally, pass a mapping to setup.
Here we apply verbosity levels to an example logger named verbosity-feature.
- Setting verbosity to
0or1will set theverbosity-featurelogger's level toWARNING. - Setting verbosity to
2will set the logger's level toINFO. - Setting verbosity to
3or more will set the logger's level toDEBUG.
>>> import splatlog
>>> splatlog.del_verbosity_levels()
>>> splatlog.del_verbosity()
>>> splatlog.setup(
... console="stdout",
... verbosity_levels={
... "verbosity-feature": (
... (0, splatlog.WARNING),
... (2, splatlog.INFO),
... (3, splatlog.DEBUG),
... ),
... },
... )
We can verify this behavior by getting the logger and changing the verbosity.
>>> log = splatlog.get_logger(name="verbosity-feature")
>>> log.level is splatlog.NOTSET
True
>>> splatlog.set_verbosity(0)
>>> log.level is splatlog.WARNING
True
>>> splatlog.set_verbosity(1)
>>> log.level is splatlog.WARNING
True
>>> splatlog.set_verbosity(2)
>>> log.level is splatlog.INFO
True
>>> splatlog.set_verbosity(3)
>>> log.level is splatlog.DEBUG
True
>>> splatlog.set_verbosity(4)
>>> log.level is splatlog.DEBUG
True
Handler-Specific Verbosity Levels
Global verbosity levels are convenient if you only have a single handler or want to control the level of logging reaching all handlers, but there are use cases where handlers have significantly different purposes and need their levels specifically controlled.
The primary example is logging important information to stdio for people to look at and logging a more comprehensive set of records to a file or stream for a log management system to ingest.
To support this use case, verbosity levels can be assigned to specific logging handlers instead of the loggers themselves.
In this example, we will log everything from verbosity-feature to a JSON
stream, and control what goes to stdout with verbosity.
First, we need to quickly reset the verbosity and verbosity levels.
>>> splatlog.del_verbosity_levels()
>>> splatlog.del_verbosity()
Now we create a JSON handler to receive records. For testing purposes this will
simply write to an io.StringIO instance. We'll also use the pretty
configuration to make the output easier to read.
>>> import logging
>>> from io import StringIO
>>> json_io = StringIO()
Here is the setup:
- The root log level is
DEBUGin order to allow all records through to our JSON handler, which is assigned as theexporthandler. - The
consolehandler writes to stdout (doctest doesn't capture stderr!) and has the same verbosity levels configuration as the previous section. - Verbosity is set to
0to start.
>>> splatlog.setup(
... level=splatlog.DEBUG,
... export=dict(
... stream=json_io,
... level=splatlog.DEBUG,
... formatter="pretty"
... ),
... console=dict(
... console="stdout",
... verbosity_levels={
... "verbosity-feature": (
... (0, splatlog.WARNING),
... (2, splatlog.INFO),
... (3, splatlog.DEBUG),
... ),
... },
... ),
... verbosity=0,
... )
Let's quickly confirm the setup did what we expect:
>>> splatlog.get_verbosity() == 0
True
>>> log.getEffectiveLevel() is splatlog.DEBUG
True
>>> splatlog.get_named_handler("console").verbosity_levels[log.name].get_level(
... splatlog.get_verbosity(),
... ) == splatlog.WARNING
True
When logging a WARNING we will see it both in stdout and the JSON stream.
>>> log.warning("Watch out now!")
WARNING verbosity-feature
msg Watch out now!
>>> print(json_io.getvalue())
{
"t": ...,
"level": "WARNING",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Watch out now!"
}
However, when logging a DEBUG message, it will only appear in the JSON stream.
>>> log.debug("Won't show in stdout, because verbosity's too low!")
>>> print(json_io.getvalue())
{
"t": ...,
"level": "WARNING",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Watch out now!"
}
{
"t": ...,
"level": "DEBUG",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Won't show in stdout, because verbosity's too low!"
}
Now we turn up the verbosity to see a DEBUG message appear in both.
>>> splatlog.set_verbosity(3)
>>> log.debug(
... "Ok, now we should see it in stdout",
... verbosity=splatlog.get_verbosity(),
... )
DEBUG verbosity-feature
msg Ok, now we should see it in stdout
data verbosity int 3
>>> print(json_io.getvalue())
{
"t": ...,
"level": "WARNING",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Watch out now!"
}
{
"t": ...,
"level": "DEBUG",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Won't show in stdout, because verbosity's too low!"
}
{
"t": ...,
"level": "DEBUG",
"name": "verbosity-feature",
"file": "<doctest verbosity.md[...]>",
"line": 1,
"msg": "Ok, now we should see it in stdout",
"data": {
"verbosity": 3
}
}