From c31476c46e436d148878787d259931fa31726413 Mon Sep 17 00:00:00 2001 From: Fabien MARTY Date: Wed, 21 Aug 2024 09:25:10 +0200 Subject: [PATCH] add some env vars for default configuration --- docs/configure.md | 35 +++++++++++++++++++++++++++++++---- stlog/formatter.py | 18 ++++++++++++++++++ stlog/setup.py | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/docs/configure.md b/docs/configure.md index ae09ae2..340a7e7 100644 --- a/docs/configure.md +++ b/docs/configure.md @@ -399,11 +399,28 @@ As we love {{twelvefactorapp}} plenty of default behavior of `stlog` can be conf - 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 to `stdout` or `stderr` (depending on `STLOG_DESTINATION` value) with a "human formatter" and will be use a `rich` (colors...) output depending in `STLOG_USE_RICH` value. By default, `rich` output will be automatically used if the terminal support it and if the `rich` library is installed. +- `json`: the output will be sent to `stdout` or `stderr` (depending on `STLOG_DESTINATION` value) with a generic "JSON formatter" in a compact mode (without indentation) +- `json-human`: the output will be sent to `stdout` or `stderr` (depending on `STLOG_DESTINATION` value) with a generic "JSON formatter" in an indented way +- `json-gcp`: the output will be sent to `stdout` or `stderr` (depending on `STLOG_DESTINATION` value) 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 {{apilink("output.make_stream_or_rich_stream_output")}} function: -- if empty or set to `NONE` or `AUTO` => nothing (the function makes automatically a `StreamOuput` or a `RichStreamOutput`, see above for details) +- if empty or set to `NONE` or `AUTO` => nothing (the function makes automatically a `StreamOuput` or a `RichStreamOutput` depending on the terminal support and if the `rich` library is installed) - if set to `1`, `TRUE`, `YES` => the function will always return a `RichStreamOutput` (even the log stream is redirected to a file!) - else (`0`, `FALSE`, `NO`...) => the function will always return a standard `StreamOutput` (with colors and fancy things) @@ -433,13 +450,23 @@ This variable can change the default value of `read_extra_kwargs_from_standard_l These variables can be used to inject a global context. See [usage documentation](../usage) for details. +### `STLOG_DEFAULT_IGNORE_COMPOUND_TYPES` + +- if set to `1`, `TRUE`, `YES`: compound types (dict, list...) are silently ignored in `LogFmtKVFormatter` (used by default by "human" outputs) +- else (`0`, `FALSE`, `NO`...): compound type will be displayed + +The default is to ignore. + +!!! note "What about JSON outputs?" + + This variable has no effect on JSON outputs. + ### `STLOG_UNIT_TESTS_MODE` !!! warning "Private feature!" This is a private feature (DON'T USE IT) to get always the same output (fixed date, fixed process number...) -### FIXME (document) +### `STLOG_PROGRAM_NAME` -- STLOG_IGNORE_COMPOUND_TYPES -- STLOG_PROGRAM_NAME \ No newline at end of file +Default program name when getting a logger without name. If not set, we will try to guess. \ No newline at end of file diff --git a/stlog/formatter.py b/stlog/formatter.py index ea2a112..dc38d84 100644 --- a/stlog/formatter.py +++ b/stlog/formatter.py @@ -47,6 +47,24 @@ }} }} """ +DEFAULT_STLOG_GCP_JSON_FORMAT = """ +{{ + "timestamp": {asctime}, + "logger": {name}, + "severity": {levelname}, + "message": {message}, + "source": {{ + "path": {pathname}, + "lineno": {lineno}, + "module": {module}, + "funcName": {funcName}, + "process": {process}, + "processName": {processName}, + "thread": {thread}, + "threadName": {threadName} + }} +}} +""" DEFAULT_STLOG_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" diff --git a/stlog/setup.py b/stlog/setup.py index 6153a89..43001ca 100644 --- a/stlog/setup.py +++ b/stlog/setup.py @@ -10,15 +10,48 @@ from stlog.adapter import getLogger from stlog.base import GLOBAL_LOGGING_CONFIG, check_env_false -from stlog.output import Output, make_stream_or_rich_stream_output +from stlog.formatter import DEFAULT_STLOG_GCP_JSON_FORMAT, JsonFormatter +from stlog.output import Output, StreamOutput, make_stream_or_rich_stream_output DEFAULT_LEVEL: str = os.environ.get("STLOG_LEVEL", "INFO") DEFAULT_CAPTURE_WARNINGS: bool = check_env_false("STLOG_CAPTURE_WARNINGS", True) DEFAULT_PROGRAM_NAME: str | None = os.environ.get("STLOG_PROGRAM_NAME", None) +DEFAULT_DESTINATION: str = os.environ.get("STLOG_DESTINATION", "stderr").lower() +DEFAULT_OUTPUT: str = os.environ.get("STLOG_OUTPUT", "console").lower() + + +def _make_default_stream() -> typing.TextIO: + if DEFAULT_DESTINATION == "stderr": + return sys.stderr + elif DEFAULT_DESTINATION == "stdout": + return sys.stdout + raise Exception( + f"bad value:{DEFAULT_DESTINATION} for STLOG_DESTINATION env var => must be 'stderr' or 'stdout'" + ) def _make_default_outputs() -> list[Output]: - return [make_stream_or_rich_stream_output(stream=sys.stderr)] + if DEFAULT_OUTPUT == "console": + return [make_stream_or_rich_stream_output(stream=_make_default_stream())] + elif DEFAULT_OUTPUT == "json": + return [StreamOutput(stream=_make_default_stream(), formatter=JsonFormatter())] + elif DEFAULT_OUTPUT == "json-human": + return [ + StreamOutput( + stream=_make_default_stream(), formatter=JsonFormatter(indent=4) + ) + ] + elif DEFAULT_OUTPUT == "json-gcp": + return [ + StreamOutput( + stream=_make_default_stream(), + formatter=JsonFormatter(fmt=DEFAULT_STLOG_GCP_JSON_FORMAT), + ) + ] + else: + raise Exception( + f"bad value:{DEFAULT_OUTPUT} for STLOG_OUTPUT env var => must be 'console', 'json', 'json-human' or 'json-gcp'" + ) def _logging_excepthook(