Configure
To go further...
This page is about configuring existing stlog objects. To go further, you can also read the Extend page.
The setup() function
stlog library seems great but I don't want to use a special way to configure it!
Yes, you can configure stlog library without custom shortcuts like Output or setup(). See FAQ for details about that.
The log level
First of all, you can tune the (minimal) log level as a global parameter for all outputs/loggers.
from stlog import setup, getLogger
# Filter messages < WARNING
setup(level="WARNING")
getLogger().info("ignored message")
You can also override this in the setup function for a specific logger name:
from stlog import setup, getLogger
# Filter messages < WARNING
setup(level="WARNING", extra_levels={"bar": "DEBUG"})
getLogger("foo").info("ignored message")
getLogger("bar").debug("not ignored message thanks to the extra_levels override")
Of course, you can still use setLevel() on logger instances.
Tip
You can also use logging levels as integer. Example: logging.DEBUG
The outputs
The main configuration option of the setup function is the outputs parameter
which takes a list of output.Output objects.
You can see how to create your own outputs in the extend page.
For now, you can use four output types:
- a
output.StreamOutputobject which represents a standard stream output (for example on the consolestdoutorstderr) - a
output.RichStreamOutputobject which represents a "rich" stream output for a real and modern terminal emulator (with colors and fancy stuff)
rich library
To use a output.RichStreamOutput, you must install the rich library by yourself.
It's a mandatory requirement for this ouput.
If you don't know which one to use or if you need an automatic behavior (depending on the fact that the rich library is installed or not
or if we are writing to a real terminal and not to a filter redirected to a file for example), you can use a very handy
factory: output.make_stream_or_rich_stream_output which will automatically choose for you.
Each Output can provide custom options but there are two common ones:
formatterwhich can be used to override the defaultlogging.Formatterobjectlevelwhich can be used to override the default logging level (for this specific output if this level is not already filtered atLoggerlevel)filterswhich can be used to add somelogging.Filterfor this specific output (note: you can also add filters at the logger level withaddFilter()method)
Here is an example to configure two outputs:
- one classic stream output to
stderrwith an overridden formatter and an overridden log level - one classic file output to
/tmp/stlog.logwith a JSON formatter
import sys
from stlog import setup
from stlog.output import FileOutput, StreamOutput
from stlog.formatter import HumanFormatter, JsonFormatter
setup(
level="INFO",
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(exclude_extras_keys_fnmatchs=["*"]),
level="WARNING",
),
FileOutput(filename=sys.stdout, formatter=JsonFormatter(indent=4)),
]
)
Formatters?
You have a dedicated section about Formatters and stlog custom Formatters bellow.
Default output is and "automatic rich or not rich" stream on stderr with a HumanFormatter as formatter.
Filters?
Here is an example:
import sys
import logging
from stlog import setup, getLogger
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter, JsonFormatter
def this_is_a_filter(record: logging.LogRecord) -> False:
if record.getMessage() == "message to filter":
# We don't want this message
return False
return True
setup(
level="INFO",
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(exclude_extras_keys_fnmatchs=["*"]),
level="WARNING",
),
StreamOutput(stream=sys.stdout, formatter=JsonFormatter(indent=4)),
filters=[this_is_a_filter],
]
)
getLogger("foo").info("message to filter") # this message will be filtered
Warnings and "not catched" exceptions
Python warnings are automatically captured with the stlog logging infrastructure.
You can disable this with capture_warnings=False parameter:
Moreover, stlog capture your "not catched" exceptions to emit them as ERROR messages. You can disable this or tune this with:
You can also provide your own hook. See this python documentation for details.
Standard logging compatibility options
By default, stlog is going to inject global contexts into standard logging calls.
If you want to disable this behavior:
You can go further by connecting the standard logging extra kwargs to stlog:
from stlog import setup
import logging
setup(read_extra_kwargs_from_standard_logging=True)
logging.warning(
"standard logger with extra kwargs", extra={"foo": "bar", "foo2": "bar2"}
)
Formatters
In stlog we have two kinds of formatters:
- standard/classic formatters in
stlog.formatters: they are compatible with python logging Formatters - kvformatters in
stlog.kvformatters: these custom classes build a newextrasplaceholder (with all key/values from contexts) you can use in your standard formatters (as a part on the format string)
KV formatters
Let's start with "KV formatters". They are completely specific to stlog but optional. They format extra key values into a single {extras}
placeholder you can use classically with "standard formatters". They are optional because you can also use individual placeholders for each
key/value.
Let's say, you have to extra key values:
foo="bar"foo2="bar2"
In the standard formatter format, you can use {foo} and {foo2} placeholders without a "KV formatter" at all. But you need to know the
name of all key values you want to add to your log messages (because you have to list them in the format string):
Example:
- if the formatter format string is
{levelname}: {message} (foo={foo}, foo2={foo2})"and if you log withstlog.getLogger().warning("this is a warning", foo="bar", foo2="bar2"), you are going to get:warning: this is a warning (foo=bar, foo2=bar2) - but if you use a
LogFmtKVFormatterand a format string:{levelname}: {message} {extras}, you are going to get:warning: this is a warning {foo=bar, foo2=bar2}
So "KV formatters" are only responsible of serializing all extra key values to an {extras} string placeholder. If you don't use
this placeholder in your format string, you don't need a "KV formatter" at all.
what about %(extras)s placeholder instead?
stlog use new formatter strings (with style="{"). So placeholders are using the form: {name}. If you prefer old-style
placeholders with style="%" you can of course switch to the old-style and you use %(extras)s placeholder instead.
Available "KV formatters"
Here are available "KV formatters". You can of course write yours (see extend page in documentation).
EmptyKVFormatter
This one is not very interesting as it always returns an empty string as {extras}.
TemplateKVFormatter
This one formats {extras} with string templating.
See kvformatter.TemplateKVFormatter for details.
Example:
import sys
from stlog import setup, getLogger
from stlog.kvformatter import TemplateKVFormatter
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter
setup(
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(
fmt="{asctime}: ***{levelname}*** {message}{extras}",
kv_formatter=TemplateKVFormatter(
template="{key} => {value}",
separator=", ",
prefix="\n ",
),
),
)
]
)
getLogger().warning("this is a warning", foo="bar", foo2="bar2")
LogFmtKVFormatter
This class formats {extras} with logfmt format.
See kvformatter.LogFmtKVFormatter for details.
Example:
import sys
from stlog import setup, getLogger
from stlog.kvformatter import LogFmtKVFormatter
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter
setup(
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(
fmt="{asctime}: ***{levelname}*** {message}{extras}",
kv_formatter=LogFmtKVFormatter(
prefix=" [",
suffix="]",
),
),
)
]
)
getLogger().warning("this is a warning", foo="foo bar", foo2="bar2")
What about compound types in extras?
FIXME
Standard formatters
Common options
All stlog formatters have common options you can find on the API reference.
These options are common logging.Formatter options extended with some stlog custom options.
Extra options are mainly about context key/values formatting. We are going to see some real examples after.
HumanFormatter
This formatter can be used to get a human friendly output (without the rich library).
Let's start with a simple example:
import sys
from stlog import setup, getLogger
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter
setup(outputs=[StreamOutput(stream=sys.stderr, formatter=HumanFormatter())])
getLogger(__name__).warning("this is a warning", foo="bar", foo2="bar2")
Default format is:
Of course, you can change this format with for example:
import sys
from stlog import setup, getLogger
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter
format = "{asctime} {levelname} from process #{process}: {message}\n => {extras}"
asctime_format = "%H:%M:%SZ"
setup(
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(fmt=format, datefmt=asctime_format),
)
]
)
getLogger(__name__).warning("this is a warning", foo="bar", foo2="bar2")
{extras} format?
By default, HumanFormatter use a LogFmtKVFormatter for formatting the {extras} placeholder. Of course, you
can change or tune that by providing your own instance of KVFormatter to HumanFormatter object.
RichHumanFormatter
This formatter can be used to get a human friendly output (with the rich library library installed).
Default format is:
:arrow_forward: [log.time]{asctime}[/log.time] {name} [{rich_level_style}]{levelname:^8s}[/{rich_level_style}] [bold]{rich_escaped_message}[/bold]{extras}
This formatter provides some custom placeholders:
{rich_escaped_message}: the standard{message}placeholder but escaped to avoid some accidental rich markup rendering inside message{rich_escaped_extras}: same thing but for{extras}placeholder{rich_level_style}: contain a smart rich markup style depending on the log level
{extras}/{rich_escaped_extras} format?
By default, RichHumanFormatter use a LogFmtKVFormatter for formatting the {extras} placeholder with custom
attributes:
prefix="\n :arrow_right_hook: "suffix=""template="[repr.attrib_name]{key}[/repr.attrib_name][repr.attrib_equal]=[/repr.attrib_equal][repr.attrib_value]{value}[/repr.attrib_value]"
Of course, you can change or tune that by providing your own instance of KVFormatter to HumanFormatter object.
LogFmtFormatter
This formatter will format your logs with the logfmt format.
Default format is:
But the use of this format is special with this formatter as placeholders can be encoded to be valid for logfmt format. So to configure an alternate format:
- use the
key={placeholder}syntax (with space separated key/values blocs) - don't try to escape or quote your values , it will be done automatically and dynamically, so don't use quotes in your format
- use the placeholder
{extras}alone at the end (without leading space) to get all extra key/values
import sys
from stlog import setup, getLogger
from stlog.output import StreamOutput
from stlog.formatter import LogFmtFormatter
fmt = "time={asctime} logger={name} process={process} level={levelname} message={message}{extras}"
setup(outputs=[StreamOutput(stream=sys.stderr, formatter=LogFmtFormatter(fmt=fmt))])
getLogger(__name__).warning("this is a warning", foo="bar", foo2="bar2")
getLogger(__name__).critical(
'this is a critical message with\nmultiple\nlines and "quotes"'
)
JsonFormatter
This formatter will format your logs in the JSON format.
Default format is:
{{
"time": {asctime},
"logger": {name},
"level": {levelname},
"message": {message},
"source": {{
"path": {pathname},
"lineno": {lineno},
"module": {module},
"funcName": {funcName},
"process": {process},
"processName": {processName},
"thread": {thread},
"threadName": {threadName}
}}
}}
But the use of this format is special with this formatter as placeholders can be encoded to be valid for JSON. So to configure an alternate format:
- provide a nearly JSON valid format (except for placeholders, see next item)
- don't try to escape your values, it will be done automatically and dynamically, so don't use quotes in your format around placeholders
- there is no
{extras}placeholder (see below)
What about {extras} placeholder in JSON format?
Extra key/values are automatically injected in the JSON as root keys if include_extras_in_key="" (default).
You can include all extras keys as a child dict or another root key by using for example: includes_extras_in_key="extras" to get
something like:
Available Environment variables
As we love Twelve-Factor App plenty of default behavior of stlog can be configured with environment variables.
configuration priority?
In order of importance (the last one wins):
- default values (set in the code)
- environment variables
- explicit configuration in the code (always wins)
STLOG_LEVEL
This variable can tune the default "log level". Use CRITICAL, FATAL, ERROR, WARN, WARNING, INFO, DEBUG or NOTSET as value.
STLOG_DESTINATION
This variable can tune the default destination. Use stdout or stderr as value. Default to stderr.
STLOG_OUTPUT
This variable can set the default output and format. You can use:
console: the output will be sent tostdoutorstderr(depending onSTLOG_DESTINATIONvalue) with a "human formatter" and will be use arich(colors...) output depending inSTLOG_USE_RICHvalue. By default,richoutput will be automatically used if the terminal support it and if therichlibrary is installed.json: the output will be sent tostdoutorstderr(depending onSTLOG_DESTINATIONvalue) with a generic "JSON formatter" in a compact mode (without indentation)json-human: the output will be sent tostdoutorstderr(depending onSTLOG_DESTINATIONvalue) with a generic "JSON formatter" in an indented wayjson-gcp: the output will be sent tostdoutorstderr(depending onSTLOG_DESTINATIONvalue) with a GCP "JSON formatter" (to be automatically decoded and displayed in GCP logging products)
STLOG_USE_RICH
This variable can tune the behavior of output.make_stream_or_rich_stream_output function:
- if empty or set to
NONEorAUTO=> nothing (the function makes automatically aStreamOuputor aRichStreamOutputdepending on the terminal support and if therichlibrary is installed) - if set to
1,TRUE,YES=> the function will always return aRichStreamOutput(even the log stream is redirected to a file!) - else (
0,FALSE,NO...) => the function will always return a standardStreamOutput(with colors and fancy things)
use_rich parameter?
This can be overriden by the use_rich parameter when calling output.make_stream_or_rich_stream_output
STLOG_CAPTURE_WARNINGS
This variable can change the default value of capture_warnings parameter of the setup function:
- if set to
0,FALSE,NO: default value ofcapture_warningsis set toFalse
STLOG_REINJECT_CONTEXT_IN_STANDARD_LOGGING
This variable can change the default value of reinject_context_in_standard_logging parameter of the setup function:
- if set to
0,FALSE,NO: default value ofreinject_context_in_standard_loggingis set toFalse
STLOG_READ_EXTRA_KWARGS_FROM_STANDARD_LOGGING
This variable can change the default value of read_extra_kwargs_from_standard_logging parameter of the setup function:
- if set to
1,TRUE,YES: default value ofread_extra_kwargs_from_standard_loggingis set toTrue
STLOG_ENV_JSON_CONTEXT and STLOG_ENV_CONTEXT_*
These variables can be used to inject a global context. See usage documentation for details.
STLOG_DEFAULT_IGNORE_COMPOUND_TYPES
- if set to
1,TRUE,YES: compound types (dict, list...) are silently ignored inLogFmtKVFormatter(used by default by "human" outputs) - else (
0,FALSE,NO...): compound type will be displayed
The default is to ignore.
What about JSON outputs?
This variable has no effect on JSON outputs.
STLOG_UNIT_TESTS_MODE
Private feature!
This is a private feature (DON'T USE IT) to get always the same output (fixed date, fixed process number...)
STLOG_PROGRAM_NAME
Default program name when getting a logger without name. If not set, we will try to guess.
RICH_DUMP_EXCEPTION_ON_CONSOLE_SHOW_LOCALS
If set to 1, TRUE or YES: when using rich output on console, dump exceptions with local variables.