| Name | stlog JSON |
| Version |
0.3.0
JSON |
| download |
| home_page | None |
| Summary | None |
| upload_time | 2024-08-21 07:32:59 |
| maintainer | None |
| docs_url | None |
| author | Fabien MARTY |
| requires_python | <4.0,>=3.7 |
| license | MIT |
| keywords |
|
| VCS |
|
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
<!-- WARNING: generated from README.md.j2, do not modify this file manually but modify README.md.j2 instead
and execute 'poetry run invoke readme' to regenerate this README.md file -->
# stlog
[](https://github.com/fabien-marty/stlog/actions/workflows/lint.yaml)
[](https://app.codecov.io/github/fabien-marty/stlog)
[](https://pypi.org/project/stlog/)
[Full documentation](https://fabien-marty.github.io/stlog/)
<!--intro-start-->
## What is it?
**ST**andard **ST**ructured **LOG** (`stlog`) is Python 3.7+ [structured logging](#structured) library:
- built on [standard python logging](https://docs.python.org/3/library/logging.html) and [contextvars](https://docs.python.org/3/library/contextvars.html)
- very easy to configure with "good/opinionated" default values
- which produces great output **for both humans and machines**
- which believes in [Twelve-Factor App](https://12factor.net/) principles about config and logs
- **dependency free** (but can use fancy stuff (colors, augmented traceback...) from [the rich library](https://github.com/Textualize/rich) *(if installed)*)
## Features
- **standard, standard, standard**: all stlog objects are built on [standard python logging](https://docs.python.org/3/library/logging.html) and are compatible with:
- other existing handlers, formatters...
- libraries which are using a standard logger *(and `stlog` can automatically reinject the global context in log records produced by these libraries)*
- easy shorcuts to configure your logging
- provides nice outputs **for humans AND for machines** *(you can produce both at the same time)*
- structured with 4 levels of context you can choose or combine:
- a global one set by environment variables *(read at process start)*
- a kind of global one (thanks to [contextvars](https://docs.python.org/3/library/contextvars.html))
- a context linked to the logger object itself (defined during its building)
- a context linked to the log message itself
- a lot of configuration you can do with environment variables (in the spirit of [Twelve-Factor App](https://12factor.net/) principles)
## Non-Features
- *"A twelve-factor app never concerns itself with routing or storage of its output stream."*
- we are going to make an exception on this for log files *(see roadmap)*
- but we don't want to introduce complex/network outputs like syslog, elasticsearch, loki...
- standard, standard, standard: we do not want to move away from [standard python logging](https://docs.python.org/3/library/logging.html) compatibility
## <a name="structured"></a> What is *structured logging*?
> Structured logging is a technique used in software development to produce log messages that are more easily parsed and analyzed by machines.
> Unlike traditional logging, which typically consists of free-form text messages, structured logging uses a well-defined format that includes
> named fields with specific data types.
>
> The benefits of structured logging are many. By using a standard format, it becomes easier to automate the processing and analysis of logs.
> This can help with tasks like troubleshooting issues, identifying patterns, and monitoring system performance. It can also make it easier
> to integrate logs with other systems, such as monitoring and alerting tools.
>
> Some common formats for structured logging include JSON, XML, and key-value pairs. In each case, the format includes a set of fields that provide information about the log message, such as the severity level, timestamp, source of the message, and any relevant metadata.
>
> Structured logging is becoming increasingly popular as more developers recognize its benefits. Many logging frameworks and libraries now include support for structured logging, making it easier for developers to adopt the technique in their own projects.
>
> (thanks to ChatGPT)
<!--intro-end-->
## Quickstart
<!--quickstart-start-->
### Installation
```
pip install stlog
```
### Very minimal usage
```python
import stlog
stlog.info("It works", foo="bar", x=123)
stlog.critical("Houston, we have a problem!")
```
Output (without `rich` library installed):
```
2023-03-29T14:48:37Z root [ INFO ] It works {foo=bar x=123}
2023-03-29T14:48:37Z root [ CRITICAL ] Houston, we have a problem!
```
Output (with `rich` library installed):

### Basic usage
```python
from stlog import getLogger, setup
# Set the logging default configuration (human output on stderr)
setup()
# Get a logger
logger = getLogger(__name__)
logger.info("It works", foo="bar", x=123)
logger.critical("Houston, we have a problem!")
```
Output (without `rich` library installed):
```
2023-03-29T14:48:37Z __main__ [ INFO ] It works {foo=bar x=123}
2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem!
```
Output (with `rich` library installed):

### Usage with context
```python
from stlog import LogContext, getLogger, setup
# Set the logging default configuration (human output on stderr)
setup()
# ...
# Set the (kind of) global execution context
# (thread, worker, async friendly: one context by execution)
# (for example in a wsgi/asgi middleware)
# Note: ExecutionContext is a static class, so a kind of global singleton
LogContext.reset_context()
LogContext.add(request_id="4c2383f5")
LogContext.add(client_id=456, http_method="GET")
# ... in another file/class/...
# Get a logger
logger = getLogger(__name__)
logger.info("It works", foo="bar", x=123)
logger.critical("Houston, we have a problem!")
```
Output (without `rich` library installed):
```
2023-03-29T14:48:37Z __main__ [ INFO ] It works {client_id=456 foo=bar http_method=GET request_id=4c2383f5 x=123}
2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem! {client_id=456 http_method=GET request_id=4c2383f5}
```
Output (with `rich` library installed):

What about if you want to get a more parsing friendly output (for example in JSON on `stdout`) while keeping the human output on `stderr` (without any context)?
```python
import sys
from stlog import LogContext, getLogger, setup
from stlog.output import StreamOutput
from stlog.formatter import HumanFormatter, JsonFormatter
setup(
outputs=[
StreamOutput(
stream=sys.stderr,
formatter=HumanFormatter(exclude_extras_keys_fnmatchs=["*"]),
),
StreamOutput(stream=sys.stdout, formatter=JsonFormatter(indent=4)),
]
)
# See previous example for details
LogContext.reset_context()
LogContext.add(request_id="4c2383f5")
LogContext.add(client_id=456, http_method="GET")
logger = getLogger(__name__)
logger.info("It works", foo="bar", x=123)
logger.critical("Houston, we have a problem!")
```
Human output (on `stderr`):
```
2023-03-29T14:48:37Z __main__ [ INFO ] It works
2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem!
```
JSON ouput (on `stdout`) for machines:
```json
{
"client_id": 456,
"foo": "bar",
"http_method": "GET",
"level": "INFO",
"logger": "__main__",
"message": "It works",
"request_id": "4c2383f5",
"source": {
"funcName": "<module>",
"lineno": 21,
"module": "qs3",
"path": "/path/filename.py",
"process": 6789,
"processName": "MainProcess",
"thread": 12345,
"threadName": "MainThread"
},
"time": "2023-03-29T14:48:37Z",
"x": 123
}
{
"client_id": 456,
"http_method": "GET",
"level": "CRITICAL",
"logger": "__main__",
"message": "Houston, we have a problem!",
"request_id": "4c2383f5",
"source": {
"funcName": "<module>",
"lineno": 22,
"module": "qs3",
"path": "/path/filename.py",
"process": 6789,
"processName": "MainProcess",
"thread": 12345,
"threadName": "MainThread"
},
"time": "2023-03-29T14:48:37Z"
}
```
<!--quickstart-end-->
## Roadmap
- [ ] add `file` outputs
- [x] add a full `logfmt` formatter
- [ ] more configuration options through env vars
Raw data
{
"_id": null,
"home_page": null,
"name": "stlog",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.7",
"maintainer_email": null,
"keywords": null,
"author": "Fabien MARTY",
"author_email": "fabien.marty@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/0f/ca/cb3f50a4105a21d0d1f74b93ccf01f0025a2f40f234efa77b374c87f1d38/stlog-0.3.0.tar.gz",
"platform": null,
"description": "\n <!-- WARNING: generated from README.md.j2, do not modify this file manually but modify README.md.j2 instead\n and execute 'poetry run invoke readme' to regenerate this README.md file -->\n\n # stlog\n\n[](https://github.com/fabien-marty/stlog/actions/workflows/lint.yaml)\n[](https://app.codecov.io/github/fabien-marty/stlog)\n[](https://pypi.org/project/stlog/)\n\n[Full documentation](https://fabien-marty.github.io/stlog/)\n\n<!--intro-start-->\n\n## What is it?\n\n**ST**andard **ST**ructured **LOG** (`stlog`) is Python 3.7+ [structured logging](#structured) library:\n\n- built on [standard python logging](https://docs.python.org/3/library/logging.html) and [contextvars](https://docs.python.org/3/library/contextvars.html)\n- very easy to configure with \"good/opinionated\" default values\n- which produces great output **for both humans and machines**\n- which believes in [Twelve-Factor App](https://12factor.net/) principles about config and logs\n- **dependency free** (but can use fancy stuff (colors, augmented traceback...) from [the rich library](https://github.com/Textualize/rich) *(if installed)*)\n\n## Features\n\n- **standard, standard, standard**: all stlog objects are built on [standard python logging](https://docs.python.org/3/library/logging.html) and are compatible with:\n - other existing handlers, formatters...\n - libraries which are using a standard logger *(and `stlog` can automatically reinject the global context in log records produced by these libraries)*\n- easy shorcuts to configure your logging\n- provides nice outputs **for humans AND for machines** *(you can produce both at the same time)*\n- structured with 4 levels of context you can choose or combine:\n - a global one set by environment variables *(read at process start)*\n - a kind of global one (thanks to [contextvars](https://docs.python.org/3/library/contextvars.html))\n - a context linked to the logger object itself (defined during its building)\n - a context linked to the log message itself\n- a lot of configuration you can do with environment variables (in the spirit of [Twelve-Factor App](https://12factor.net/) principles)\n\n## Non-Features\n\n- *\"A twelve-factor app never concerns itself with routing or storage of its output stream.\"*\n - we are going to make an exception on this for log files *(see roadmap)*\n - but we don't want to introduce complex/network outputs like syslog, elasticsearch, loki...\n- standard, standard, standard: we do not want to move away from [standard python logging](https://docs.python.org/3/library/logging.html) compatibility \n\n## <a name=\"structured\"></a> What is *structured logging*?\n\n> Structured logging is a technique used in software development to produce log messages that are more easily parsed and analyzed by machines. \n> Unlike traditional logging, which typically consists of free-form text messages, structured logging uses a well-defined format that includes\n> named fields with specific data types.\n> \n> The benefits of structured logging are many. By using a standard format, it becomes easier to automate the processing and analysis of logs.\n> This can help with tasks like troubleshooting issues, identifying patterns, and monitoring system performance. It can also make it easier\n> to integrate logs with other systems, such as monitoring and alerting tools.\n> \n> Some common formats for structured logging include JSON, XML, and key-value pairs. In each case, the format includes a set of fields that provide information about the log message, such as the severity level, timestamp, source of the message, and any relevant metadata.\n> \n> Structured logging is becoming increasingly popular as more developers recognize its benefits. Many logging frameworks and libraries now include support for structured logging, making it easier for developers to adopt the technique in their own projects.\n>\n> (thanks to ChatGPT)\n\n<!--intro-end-->\n\n## Quickstart\n\n<!--quickstart-start-->\n\n### Installation\n\n```\npip install stlog\n```\n\n### Very minimal usage\n\n```python\nimport stlog\n\nstlog.info(\"It works\", foo=\"bar\", x=123)\nstlog.critical(\"Houston, we have a problem!\")\n \n```\n\nOutput (without `rich` library installed):\n\n```\n2023-03-29T14:48:37Z root [ INFO ] It works {foo=bar x=123}\n2023-03-29T14:48:37Z root [ CRITICAL ] Houston, we have a problem!\n \n```\n\nOutput (with `rich` library installed):\n\n\n \n\n\n### Basic usage\n\n```python\nfrom stlog import getLogger, setup\n\n# Set the logging default configuration (human output on stderr)\nsetup()\n\n# Get a logger\nlogger = getLogger(__name__)\nlogger.info(\"It works\", foo=\"bar\", x=123)\nlogger.critical(\"Houston, we have a problem!\")\n \n```\n\nOutput (without `rich` library installed):\n\n```\n2023-03-29T14:48:37Z __main__ [ INFO ] It works {foo=bar x=123}\n2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem!\n \n```\n\nOutput (with `rich` library installed):\n\n\n \n\n### Usage with context\n\n```python\nfrom stlog import LogContext, getLogger, setup\n\n# Set the logging default configuration (human output on stderr)\nsetup()\n\n# ...\n\n# Set the (kind of) global execution context\n# (thread, worker, async friendly: one context by execution)\n# (for example in a wsgi/asgi middleware)\n# Note: ExecutionContext is a static class, so a kind of global singleton\nLogContext.reset_context()\nLogContext.add(request_id=\"4c2383f5\")\nLogContext.add(client_id=456, http_method=\"GET\")\n\n# ... in another file/class/...\n\n# Get a logger\nlogger = getLogger(__name__)\nlogger.info(\"It works\", foo=\"bar\", x=123)\nlogger.critical(\"Houston, we have a problem!\")\n \n```\n\nOutput (without `rich` library installed):\n\n```\n2023-03-29T14:48:37Z __main__ [ INFO ] It works {client_id=456 foo=bar http_method=GET request_id=4c2383f5 x=123}\n2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem! {client_id=456 http_method=GET request_id=4c2383f5}\n \n```\n\nOutput (with `rich` library installed):\n\n\n \n\nWhat about if you want to get a more parsing friendly output (for example in JSON on `stdout`) while keeping the human output on `stderr` (without any context)?\n\n```python\nimport sys\nfrom stlog import LogContext, getLogger, setup\nfrom stlog.output import StreamOutput\nfrom stlog.formatter import HumanFormatter, JsonFormatter\n\nsetup(\n outputs=[\n StreamOutput(\n stream=sys.stderr,\n formatter=HumanFormatter(exclude_extras_keys_fnmatchs=[\"*\"]),\n ),\n StreamOutput(stream=sys.stdout, formatter=JsonFormatter(indent=4)),\n ]\n)\n\n# See previous example for details\nLogContext.reset_context()\nLogContext.add(request_id=\"4c2383f5\")\nLogContext.add(client_id=456, http_method=\"GET\")\nlogger = getLogger(__name__)\nlogger.info(\"It works\", foo=\"bar\", x=123)\nlogger.critical(\"Houston, we have a problem!\")\n \n```\n\nHuman output (on `stderr`):\n\n```\n2023-03-29T14:48:37Z __main__ [ INFO ] It works\n2023-03-29T14:48:37Z __main__ [ CRITICAL ] Houston, we have a problem!\n \n```\n\nJSON ouput (on `stdout`) for machines:\n\n```json\n{\n \"client_id\": 456,\n \"foo\": \"bar\",\n \"http_method\": \"GET\",\n \"level\": \"INFO\",\n \"logger\": \"__main__\",\n \"message\": \"It works\",\n \"request_id\": \"4c2383f5\",\n \"source\": {\n \"funcName\": \"<module>\",\n \"lineno\": 21,\n \"module\": \"qs3\",\n \"path\": \"/path/filename.py\",\n \"process\": 6789,\n \"processName\": \"MainProcess\",\n \"thread\": 12345,\n \"threadName\": \"MainThread\"\n },\n \"time\": \"2023-03-29T14:48:37Z\",\n \"x\": 123\n}\n{\n \"client_id\": 456,\n \"http_method\": \"GET\",\n \"level\": \"CRITICAL\",\n \"logger\": \"__main__\",\n \"message\": \"Houston, we have a problem!\",\n \"request_id\": \"4c2383f5\",\n \"source\": {\n \"funcName\": \"<module>\",\n \"lineno\": 22,\n \"module\": \"qs3\",\n \"path\": \"/path/filename.py\",\n \"process\": 6789,\n \"processName\": \"MainProcess\",\n \"thread\": 12345,\n \"threadName\": \"MainThread\"\n },\n \"time\": \"2023-03-29T14:48:37Z\"\n}\n \n```\n\n<!--quickstart-end-->\n\n## Roadmap\n\n- [ ] add `file` outputs\n- [x] add a full `logfmt` formatter\n- [ ] more configuration options through env vars\n",
"bugtrack_url": null,
"license": "MIT",
"summary": null,
"version": "0.3.0",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "70caa45b3120c4cc0b6501540747609234a908bd80911e362c662c2ca72cbaea",
"md5": "78fb581bc73d5cced219c7397afe3baf",
"sha256": "2c70c6b0b2e23a72241029cc13d176a7bd03db875e16bb06c641f8b96d370fe8"
},
"downloads": -1,
"filename": "stlog-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "78fb581bc73d5cced219c7397afe3baf",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.7",
"size": 21768,
"upload_time": "2024-08-21T07:32:58",
"upload_time_iso_8601": "2024-08-21T07:32:58.055236Z",
"url": "https://files.pythonhosted.org/packages/70/ca/a45b3120c4cc0b6501540747609234a908bd80911e362c662c2ca72cbaea/stlog-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0fcacb3f50a4105a21d0d1f74b93ccf01f0025a2f40f234efa77b374c87f1d38",
"md5": "8fc622457eddb4390d3efdbe2fd74853",
"sha256": "de10bac49e24a7dd1402326b59bf927cc231583ee1c4330c267b9a9cc44d401c"
},
"downloads": -1,
"filename": "stlog-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "8fc622457eddb4390d3efdbe2fd74853",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.7",
"size": 20069,
"upload_time": "2024-08-21T07:32:59",
"upload_time_iso_8601": "2024-08-21T07:32:59.349518Z",
"url": "https://files.pythonhosted.org/packages/0f/ca/cb3f50a4105a21d0d1f74b93ccf01f0025a2f40f234efa77b374c87f1d38/stlog-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-21 07:32:59",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "stlog"
}