# syslogformat
**Python [`logging.Formatter`][1] class for [syslog][2] style messages**
[![GitHub last commit][github-last-commit-img]][github-last-commit]
[![License: Apache-2.0][apache2-img]][apache2]
[![PyPI version][pypi-latest-version-img]][pypi-latest-version]
[📑 Documentation][3] | [🧑💻 Source Code][4] | [🐛 Bug Tracker][5]
## Installation
`pip install syslogformat`
## Usage
### Basic configuration
As is the case with any logging formatter setup, you need to use the special `()` key to indicate the custom class to use.
(See the [Dictionary Schema Details][6] and [User-defined objects][7] sections in the official `logging.config` documentation.)
For example, you could use the following config dictionary, pass it to the [`logging.config.dictConfig`][8] function, and start logging like this:
```python hl_lines="7"
import logging.config
log_config = {
"version": 1,
"formatters": {
"my_syslog_formatter": {
"()": "syslogformat.SyslogFormatter",
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "my_syslog_formatter",
"stream": "ext://sys.stdout",
}
},
"root": {"handlers": ["console"], "level": "DEBUG"},
}
logging.config.dictConfig(log_config)
logging.debug("foo")
logging.info("bar")
logging.warning("baz")
try:
raise ValueError("this is bad")
except ValueError as e:
logging.exception("oof")
```
This will send the following to your stdout:
```
<15>foo | root
<14>bar | root
<12>baz | root
<11>oof | root --> Traceback (most recent call last): --> File "/path/to/module.py", line 26, in <module> --> raise ValueError("this is bad") --> ValueError: this is bad
```
### The `PRI` prefix
To adhere to the `syslog` standard outlined in RFC 3164, every log message must begin with the so called [`PRI` part][9].
This is a code enclosed in angle brackets that indicates the **facility** generating the message and **severity** of the event.
The facility is encoded as an integer between 0 and 23 and the severity is encoded as an integer between 0 and 7.
The `PRI` code is calculated by multiplying the facility by 8 and adding the severity.
Programs like **`systemd-journald`** hide the `PRI` part in their output, but interpret it behind the scenes to allow things like highlighting messages of a certain level a different color and filtering by severity.
By default the facility code `1` is used, which indicates user-level messages, but this can be easily configured (see below).
Since a `DEBUG` log message corresponds to a severity of `7`, the resulting `PRI` part of the first log message in the example above is `<15>` (since `1 * 8 + 7 == 15`).
An `ERROR` has the severity `3`, so that message has the `PRI` part `<11>`.
### Default message format
By default the message format of the `SyslogFormatter` is `%(message)s | %(name)s` (and equivalent for `$` or `{` [styles][10]).
In addition, all line-breaks (including those in the exception traceback) are replaced with ` --> ` by default.
All of this can be easily changed and configured to fit your needs (see below).
### Configuration options
In addition to the usual [formatter options][11], the `SyslogFormatter` provides the following parameters:
| Parameter | Description | Default |
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------:|
| `facility` | The facility value to use for every log message | `1` |
| `line_break_repl` | To prevent a single log message taking up more than one line, every line-break (and consecutive whitespace) is replaced with this string. Passing `None` disables this behavior. | ` --> ` |
| `level_formats` | If provided a mapping of log level thresholds to format strings, the formatter will prioritize the format with the highest level threshold for all log records at or above that level. | `None` |
For more details, check the API of the `SyslogFormatter` constructor in the [documentation][3].
### Extended configuration example
Here is an example using a [custom message format][12] and specifying a different facility and line break replacement:
```python hl_lines="8-11"
import logging.config
log_config = {
"version": 1,
"formatters": {
"my_syslog_formatter": {
"()": "syslogformat.SyslogFormatter",
"format": "{levelname:<8}{message} [{name}]",
"style": "{",
"facility": 16,
"line_break_repl": " 🚀 ",
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "my_syslog_formatter",
"stream": "ext://sys.stdout",
}
},
"root": {"handlers": ["console"], "level": "DEBUG"},
}
logging.config.dictConfig(log_config)
logging.debug("foo")
logging.info("bar")
logging.warning("baz")
try:
raise ValueError("this is bad")
except ValueError as e:
logging.exception("oof")
```
Output:
```
<135>DEBUG foo [root]
<134>INFO bar [root]
<132>WARNING baz [root]
<131>ERROR oof [root] 🚀 Traceback (most recent call last): 🚀 File "/path/to/module.py", line 30, in <module> 🚀 raise ValueError("this is bad") 🚀 ValueError: this is bad
```
Since the facility was set to `16`, the PRI code ends up being `16 * 8 + 7 == 135` for `DEBUG` level messages and `16 * 8 + 3 == 131` for `ERROR` messages.
Exception texts are of course still appended, when the `exception` log method is called (or the `exc_info` argument is passed), but the custom `line_break_repl` here is used for reformatting those texts.
## Dependencies
- Python `>=3.8` `<=3.12`
- No third-party dependencies
- OS agnostic
[github-last-commit]: https://github.com/daniil-berg/syslogformat/commits
[github-last-commit-img]: https://img.shields.io/github/last-commit/daniil-berg/syslogformat?label=Last%20commit&logo=git
[apache2]: https://apache.org/licenses/LICENSE-2.0
[apache2-img]: https://img.shields.io/badge/Apache-2.0-darkred.svg?logo=apache
[pypi-latest-version]: https://pypi.org/project/syslogformat/
[pypi-latest-version-img]: https://img.shields.io/pypi/v/syslogformat?color=teal&logo=pypi
[1]: https://docs.python.org/3/library/logging.html#formatter-objects
[2]: https://datatracker.ietf.org/doc/html/rfc3164#section-4.1
[3]: https://daniil-berg.github.io/syslogformat
[4]: https://github.com/daniil-berg/syslogformat
[5]: https://github.com/daniil-berg/syslogformat/issues
[6]: https://docs.python.org/3/library/logging.config.html#dictionary-schema-details
[7]: https://docs.python.org/3/library/logging.config.html#logging-config-dict-userdef
[8]: https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig
[9]: https://datatracker.ietf.org/doc/html/rfc3164#section-4.1.1
[10]: https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles
[11]: https://docs.python.org/3/library/logging.html#logging.Formatter
[12]: https://docs.python.org/3/library/logging.html#logrecord-attributes
Raw data
{
"_id": null,
"home_page": "",
"name": "syslogformat",
"maintainer": "",
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": "Daniil Fajnberg <mail@daniil.fajnberg.de>",
"keywords": "logging,formatting,syslog",
"author": "",
"author_email": "Daniil Fajnberg <mail@daniil.fajnberg.de>",
"download_url": "https://files.pythonhosted.org/packages/00/67/976ab275fd7b8b1f0d991780a04341a13f4997d48d0df5104f27549c180b/syslogformat-1.0.0.tar.gz",
"platform": null,
"description": "# syslogformat\n\n**Python [`logging.Formatter`][1] class for [syslog][2] style messages**\n\n[![GitHub last commit][github-last-commit-img]][github-last-commit]\n[![License: Apache-2.0][apache2-img]][apache2]\n[![PyPI version][pypi-latest-version-img]][pypi-latest-version]\n\n[\ud83d\udcd1 Documentation][3] | [\ud83e\uddd1\u200d\ud83d\udcbb Source Code][4] | [\ud83d\udc1b Bug Tracker][5]\n\n## Installation\n\n`pip install syslogformat`\n\n## Usage\n\n### Basic configuration\n\nAs is the case with any logging formatter setup, you need to use the special `()` key to indicate the custom class to use.\n(See the [Dictionary Schema Details][6] and [User-defined objects][7] sections in the official `logging.config` documentation.)\n\nFor example, you could use the following config dictionary, pass it to the [`logging.config.dictConfig`][8] function, and start logging like this:\n\n```python hl_lines=\"7\"\nimport logging.config\n\nlog_config = {\n \"version\": 1,\n \"formatters\": {\n \"my_syslog_formatter\": {\n \"()\": \"syslogformat.SyslogFormatter\",\n }\n },\n \"handlers\": {\n \"console\": {\n \"class\": \"logging.StreamHandler\",\n \"level\": \"DEBUG\",\n \"formatter\": \"my_syslog_formatter\",\n \"stream\": \"ext://sys.stdout\",\n }\n },\n \"root\": {\"handlers\": [\"console\"], \"level\": \"DEBUG\"},\n}\nlogging.config.dictConfig(log_config)\n\nlogging.debug(\"foo\")\nlogging.info(\"bar\")\nlogging.warning(\"baz\")\ntry:\n raise ValueError(\"this is bad\")\nexcept ValueError as e:\n logging.exception(\"oof\")\n```\n\nThis will send the following to your stdout:\n\n```\n<15>foo | root\n<14>bar | root\n<12>baz | root\n<11>oof | root --> Traceback (most recent call last): --> File \"/path/to/module.py\", line 26, in <module> --> raise ValueError(\"this is bad\") --> ValueError: this is bad\n```\n\n### The `PRI` prefix\n\nTo adhere to the `syslog` standard outlined in RFC 3164, every log message must begin with the so called [`PRI` part][9].\nThis is a code enclosed in angle brackets that indicates the **facility** generating the message and **severity** of the event.\nThe facility is encoded as an integer between 0 and 23 and the severity is encoded as an integer between 0 and 7.\nThe `PRI` code is calculated by multiplying the facility by 8 and adding the severity.\n\nPrograms like **`systemd-journald`** hide the `PRI` part in their output, but interpret it behind the scenes to allow things like highlighting messages of a certain level a different color and filtering by severity.\n\nBy default the facility code `1` is used, which indicates user-level messages, but this can be easily configured (see below).\nSince a `DEBUG` log message corresponds to a severity of `7`, the resulting `PRI` part of the first log message in the example above is `<15>` (since `1 * 8 + 7 == 15`).\nAn `ERROR` has the severity `3`, so that message has the `PRI` part `<11>`.\n\n### Default message format\n\nBy default the message format of the `SyslogFormatter` is `%(message)s | %(name)s` (and equivalent for `$` or `{` [styles][10]).\n\nIn addition, all line-breaks (including those in the exception traceback) are replaced with ` --> ` by default.\n\nAll of this can be easily changed and configured to fit your needs (see below).\n\n### Configuration options\n\nIn addition to the usual [formatter options][11], the `SyslogFormatter` provides the following parameters:\n\n| Parameter | Description | Default |\n|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------:|\n| `facility` | The facility value to use for every log message | `1` |\n| `line_break_repl` | To prevent a single log message taking up more than one line, every line-break (and consecutive whitespace) is replaced with this string. Passing `None` disables this behavior. | ` --> ` |\n| `level_formats` | If provided a mapping of log level thresholds to format strings, the formatter will prioritize the format with the highest level threshold for all log records at or above that level. | `None` |\n\nFor more details, check the API of the `SyslogFormatter` constructor in the [documentation][3].\n\n### Extended configuration example\n\nHere is an example using a [custom message format][12] and specifying a different facility and line break replacement:\n\n```python hl_lines=\"8-11\"\nimport logging.config\n\nlog_config = {\n \"version\": 1,\n \"formatters\": {\n \"my_syslog_formatter\": {\n \"()\": \"syslogformat.SyslogFormatter\",\n \"format\": \"{levelname:<8}{message} [{name}]\",\n \"style\": \"{\",\n \"facility\": 16,\n \"line_break_repl\": \" \ud83d\ude80 \",\n }\n },\n \"handlers\": {\n \"console\": {\n \"class\": \"logging.StreamHandler\",\n \"level\": \"DEBUG\",\n \"formatter\": \"my_syslog_formatter\",\n \"stream\": \"ext://sys.stdout\",\n }\n },\n \"root\": {\"handlers\": [\"console\"], \"level\": \"DEBUG\"},\n}\nlogging.config.dictConfig(log_config)\n\nlogging.debug(\"foo\")\nlogging.info(\"bar\")\nlogging.warning(\"baz\")\ntry:\n raise ValueError(\"this is bad\")\nexcept ValueError as e:\n logging.exception(\"oof\")\n```\n\nOutput:\n\n```\n<135>DEBUG foo [root]\n<134>INFO bar [root]\n<132>WARNING baz [root]\n<131>ERROR oof [root] \ud83d\ude80 Traceback (most recent call last): \ud83d\ude80 File \"/path/to/module.py\", line 30, in <module> \ud83d\ude80 raise ValueError(\"this is bad\") \ud83d\ude80 ValueError: this is bad\n```\n\nSince the facility was set to `16`, the PRI code ends up being `16 * 8 + 7 == 135` for `DEBUG` level messages and `16 * 8 + 3 == 131` for `ERROR` messages.\n\nException texts are of course still appended, when the `exception` log method is called (or the `exc_info` argument is passed), but the custom `line_break_repl` here is used for reformatting those texts.\n\n## Dependencies\n\n- Python `>=3.8` `<=3.12`\n- No third-party dependencies\n- OS agnostic\n\n\n[github-last-commit]: https://github.com/daniil-berg/syslogformat/commits\n[github-last-commit-img]: https://img.shields.io/github/last-commit/daniil-berg/syslogformat?label=Last%20commit&logo=git\n[apache2]: https://apache.org/licenses/LICENSE-2.0\n[apache2-img]: https://img.shields.io/badge/Apache-2.0-darkred.svg?logo=apache\n[pypi-latest-version]: https://pypi.org/project/syslogformat/\n[pypi-latest-version-img]: https://img.shields.io/pypi/v/syslogformat?color=teal&logo=pypi\n\n[1]: https://docs.python.org/3/library/logging.html#formatter-objects\n[2]: https://datatracker.ietf.org/doc/html/rfc3164#section-4.1\n[3]: https://daniil-berg.github.io/syslogformat\n[4]: https://github.com/daniil-berg/syslogformat\n[5]: https://github.com/daniil-berg/syslogformat/issues\n[6]: https://docs.python.org/3/library/logging.config.html#dictionary-schema-details\n[7]: https://docs.python.org/3/library/logging.config.html#logging-config-dict-userdef\n[8]: https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig\n[9]: https://datatracker.ietf.org/doc/html/rfc3164#section-4.1.1\n[10]: https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles\n[11]: https://docs.python.org/3/library/logging.html#logging.Formatter\n[12]: https://docs.python.org/3/library/logging.html#logrecord-attributes\n",
"bugtrack_url": null,
"license": "Apache Software License Version 2.0",
"summary": "Python `logging.Formatter` class for syslog style messages",
"version": "1.0.0",
"project_urls": {
"Documentation": "http://daniil-berg.github.io/syslogformat",
"Issue Tracker": "https://github.com/daniil-berg/syslogformat/issues",
"Repository": "https://github.com/daniil-berg/syslogformat"
},
"split_keywords": [
"logging",
"formatting",
"syslog"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d998f5bed1f2efb472411fcc2668ef20bd588183478d01724e7d4a1672f03b92",
"md5": "7eef7352b087ac0f92eeda5b355aeb8f",
"sha256": "ff7375f341098e802ef7225e56290f789578ddc6a235365475af42456e7ea3c2"
},
"downloads": -1,
"filename": "syslogformat-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7eef7352b087ac0f92eeda5b355aeb8f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 17593,
"upload_time": "2023-11-15T19:19:33",
"upload_time_iso_8601": "2023-11-15T19:19:33.184605Z",
"url": "https://files.pythonhosted.org/packages/d9/98/f5bed1f2efb472411fcc2668ef20bd588183478d01724e7d4a1672f03b92/syslogformat-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0067976ab275fd7b8b1f0d991780a04341a13f4997d48d0df5104f27549c180b",
"md5": "89a226edad0ac4208bc6c6dca11a2f99",
"sha256": "83bd396047892f72bad0387f7310fc5f6ab84df556e59c0b76d34d6f0e5e1838"
},
"downloads": -1,
"filename": "syslogformat-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "89a226edad0ac4208bc6c6dca11a2f99",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 26265,
"upload_time": "2023-11-15T19:19:34",
"upload_time_iso_8601": "2023-11-15T19:19:34.831833Z",
"url": "https://files.pythonhosted.org/packages/00/67/976ab275fd7b8b1f0d991780a04341a13f4997d48d0df5104f27549c180b/syslogformat-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-11-15 19:19:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "daniil-berg",
"github_project": "syslogformat",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "syslogformat"
}