unclogger 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. unclogger-0.2.1/.gitignore +202 -0
  2. unclogger-0.2.1/.readthedocs.yaml +22 -0
  3. unclogger-0.2.1/CONTRIBUTE.md +54 -0
  4. unclogger-0.2.1/PKG-INFO +49 -0
  5. unclogger-0.2.1/README.md +26 -0
  6. unclogger-0.2.1/docs/assets/plunger-favicon.png +0 -0
  7. unclogger-0.2.1/docs/assets/plunger-logo.png +0 -0
  8. unclogger-0.2.1/docs/index.md +175 -0
  9. unclogger-0.2.1/docs/reference.md +41 -0
  10. unclogger-0.2.1/justfile +52 -0
  11. unclogger-0.2.1/mkdocs.yml +50 -0
  12. unclogger-0.2.1/pyproject.toml +143 -0
  13. unclogger-0.2.1/release-notes/0.1.0.md +1 -0
  14. unclogger-0.2.1/release-notes/0.1.1.md +1 -0
  15. unclogger-0.2.1/release-notes/0.1.2.md +3 -0
  16. unclogger-0.2.1/release-notes/0.2.0.md +4 -0
  17. unclogger-0.2.1/release-notes/0.2.1.md +1 -0
  18. unclogger-0.2.1/tests/__init__.py +0 -0
  19. unclogger-0.2.1/tests/conftest.py +12 -0
  20. unclogger-0.2.1/tests/logger/__init__.py +0 -0
  21. unclogger-0.2.1/tests/logger/clean_data/__init__.py +0 -0
  22. unclogger-0.2.1/tests/logger/clean_data/conftest.py +57 -0
  23. unclogger-0.2.1/tests/logger/clean_data/test_clean_fields.py +116 -0
  24. unclogger-0.2.1/tests/logger/clean_data/test_hash_fields.py +47 -0
  25. unclogger-0.2.1/tests/logger/test_context.py +86 -0
  26. unclogger-0.2.1/tests/logger/test_logging.py +129 -0
  27. unclogger-0.2.1/tests/logger/test_processors.py +50 -0
  28. unclogger-0.2.1/tests/logger/test_set_level.py +36 -0
  29. unclogger-0.2.1/tests/test_defaults.py +32 -0
  30. unclogger-0.2.1/tox.ini +23 -0
  31. unclogger-0.2.1/unclogger/__init__.py +11 -0
  32. unclogger-0.2.1/unclogger/defaults.py +39 -0
  33. unclogger-0.2.1/unclogger/logger.py +107 -0
  34. unclogger-0.2.1/unclogger/processors.py +28 -0
@@ -0,0 +1,202 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ BUILD_NUMBER/
12
+ develop-eggs/
13
+ build/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ pip-wheel-metadata/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ # Usually these files are written by a python script from a template
33
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
34
+ *.manifest
35
+ *.spec
36
+
37
+ # Installer logs
38
+ pip-log.txt
39
+ pip-delete-this-directory.txt
40
+
41
+ # Unit test / coverage reports
42
+ htmlcov/
43
+ .tox/
44
+ .nox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *-coverage.xml
51
+ *.cover
52
+ *.py,cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+ test-reports/
56
+
57
+ # Various testing files
58
+ .mutmut-cache
59
+
60
+ # Translations
61
+ *.mo
62
+ *.pot
63
+
64
+ # Django stuff:
65
+ *.log
66
+ local_settings.py
67
+ db.sqlite3
68
+ db.sqlite3-journal
69
+
70
+ # Flask stuff:
71
+ instance/
72
+ .webassets-cache
73
+
74
+ # Scrapy stuff:
75
+ .scrapy
76
+
77
+ # Sphinx documentation
78
+ docs/_build/
79
+
80
+ # PyBuilder
81
+ target/
82
+
83
+ # Jupyter Notebook
84
+ .ipynb_checkpoints
85
+ .ipynb
86
+
87
+ # IPython
88
+ profile_default/
89
+ ipython_config.py
90
+
91
+ # pyenv
92
+ # For a library or package, you might want to ignore these files since the code is
93
+ # intended to run in multiple environments; otherwise, check them in:
94
+ .python-version
95
+
96
+ # lock files
97
+ # According to pypa/pipenv#598, it is recommended to include the lock file in version control.
98
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
99
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
100
+ # install all needed dependencies.
101
+ #Pipfile.lock
102
+ poetry.lock
103
+ requirements.txt
104
+ requirements.in
105
+ pdm.lock
106
+ uv.lock
107
+
108
+ # other tools
109
+ .pdm-python
110
+ .pdm-build
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .envrc
125
+ .venv
126
+ env/
127
+ venv/
128
+ ENV/
129
+ env.bak/
130
+ venv.bak/
131
+
132
+ # Spyder project settings
133
+ .spyderproject
134
+ .spyproject
135
+
136
+ # Rope project settings
137
+ .ropeproject
138
+
139
+ # mkdocs documentation
140
+ /site
141
+
142
+ # mypy
143
+ .mypy_cache/
144
+ .dmypy.json
145
+ dmypy.json
146
+
147
+ # Pyre type checker
148
+ .pyre/
149
+
150
+ # pytype static type analyzer
151
+ .pytype/
152
+
153
+ # PyCharm stuff
154
+ .idea
155
+ # User-specific stuff
156
+ .idea/**/workspace.xml
157
+ .idea/**/tasks.xml
158
+ .idea/**/usage.statistics.xml
159
+ .idea/**/dictionaries
160
+ .idea/**/shelf
161
+
162
+ # Generated files
163
+ .idea/**/contentModel.xml
164
+
165
+ # Sensitive or high-churn files
166
+ .idea/**/dataSources/
167
+ .idea/**/dataSources.ids
168
+ .idea/**/dataSources.local.xml
169
+ .idea/**/sqlDataSources.xml
170
+ .idea/**/dynamic.xml
171
+ .idea/**/uiDesigner.xml
172
+ .idea/**/dbnavigator.xml
173
+
174
+ # Editor workspace files
175
+ .vscode
176
+
177
+ .testmondata
178
+
179
+ # macOS
180
+ .DS_Store
181
+
182
+ # Docker stuff for local dev
183
+ docker-compose.override.yml
184
+
185
+ .skip-hooks
186
+
187
+ tmp/
188
+ .ruff_cache
189
+
190
+ # run configurations
191
+ .run/
192
+ /.run/
193
+
194
+ # kube manifest
195
+ helm/baked_manifest.yaml
196
+
197
+ # local storage
198
+ _storage
199
+ database.json
200
+
201
+ # localstack cache
202
+ volume/cache
@@ -0,0 +1,22 @@
1
+ # .readthedocs.yaml
2
+ # Read the Docs configuration file
3
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4
+
5
+ # Required
6
+ version: 2
7
+
8
+ # Set the version of Python and other tools you might need
9
+ build:
10
+ os: ubuntu-22.04
11
+ tools:
12
+ python: "3.10"
13
+
14
+ mkdocs:
15
+ configuration: mkdocs.yml
16
+
17
+ python:
18
+ install:
19
+ - method: pip
20
+ path: .
21
+ extra_requirements:
22
+ - docs
@@ -0,0 +1,54 @@
1
+ Contributing Guidelines
2
+ =========
3
+
4
+ ## Development Environment
5
+
6
+ To manage packaging and dependencies, please [install `uv` first](https://docs.astral.sh/uv/getting-started/installation/).
7
+
8
+ Tu run development scripts, please [install `just`](https://just.systems/man/en/). To display the list of all `just` commands (a.k.a. recipes), run `just`:
9
+
10
+ ```shell
11
+ $ just
12
+ Available recipes:
13
+ help # List available recipes.
14
+ test # Run unit tests.
15
+ test-cov # Run unit tests with coverage report.
16
+ lint # Run linting and formating checks.
17
+ type # Run static typing analysis.
18
+ analyze # Run security checks.
19
+ check # Run all checks.
20
+ commits # Extract the latest commits
21
+ reformat # Reformat the code using isort and ruff.
22
+ docs # Serve documentation website for development purposes.
23
+ docs-build # Build the documentation website.
24
+ reqs # Extract current production requirements. Save to a file by appending `> requirements.txt`.
25
+ ```
26
+
27
+
28
+ ### Development Checks
29
+
30
+ During development, the command `just check` will execute a number of checks and tests on the library codebase:
31
+
32
+ * correct dependency declarations using `deptry`
33
+ * code linting check using `ruff`
34
+ * code format check using `ruff format`
35
+ * documentation styling check using `pydocstyle`
36
+
37
+ The full unit test suite can be executed with `just test`.
38
+
39
+
40
+ ## API Documentation
41
+
42
+ The project documentation can then be served locally by running:
43
+
44
+ ```shell
45
+ $ just docs
46
+ ```
47
+
48
+ To build the static documentation site, run:
49
+
50
+ ```shell
51
+ $ just docs-build
52
+ ```
53
+
54
+ This will create the HTML documentation in the `site` directory.
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: unclogger
3
+ Version: 0.2.1
4
+ Summary: Custom wrapper for enhanced structured logging.
5
+ Project-URL: Homepage, https://unclogger.readthedocs.io
6
+ Project-URL: Documentation, https://unclogger.readthedocs.io
7
+ Project-URL: Repository, https://github.com/berislavlopac/unclogger
8
+ Author-email: Berislav Lopac <berislav@lopac.net>
9
+ License: MIT
10
+ Requires-Python: <4.0,>=3.10
11
+ Requires-Dist: structlog>=24.1
12
+ Provides-Extra: clean
13
+ Requires-Dist: sanitary>=0.1.0; extra == 'clean'
14
+ Provides-Extra: docs
15
+ Requires-Dist: jinja2>=3.1.3; extra == 'docs'
16
+ Requires-Dist: mkapi>=1.0.14; extra == 'docs'
17
+ Requires-Dist: mkdocs-material>=9.5.4; extra == 'docs'
18
+ Requires-Dist: mkdocs>=1.3.0; extra == 'docs'
19
+ Requires-Dist: pymdown-extensions>=10.7; extra == 'docs'
20
+ Provides-Extra: sanitary
21
+ Requires-Dist: sanitary>=0.1.0; extra == 'sanitary'
22
+ Description-Content-Type: text/markdown
23
+
24
+ Unclogger
25
+ =========
26
+
27
+ Simple Python library for customizable structured logging.
28
+
29
+ [![Documentation Status](https://readthedocs.org/projects/unclogger/badge/?version=latest)](https://unclogger.readthedocs.io/en/latest/?badge=latest)
30
+
31
+ ## Quick Intro
32
+
33
+ ```python
34
+ from unclogger import get_logger
35
+ logger = get_logger("test logger")
36
+ logger.info("test test", foo="abc", bar=123)
37
+ ```
38
+
39
+ Output:
40
+ ```json
41
+ {
42
+ "foo": "abc",
43
+ "bar": 123,
44
+ "event": "test test",
45
+ "logger": "test logger",
46
+ "level": "info",
47
+ "timestamp": "2021-02-12T22:40:07.600385Z"
48
+ }
49
+ ```
@@ -0,0 +1,26 @@
1
+ Unclogger
2
+ =========
3
+
4
+ Simple Python library for customizable structured logging.
5
+
6
+ [![Documentation Status](https://readthedocs.org/projects/unclogger/badge/?version=latest)](https://unclogger.readthedocs.io/en/latest/?badge=latest)
7
+
8
+ ## Quick Intro
9
+
10
+ ```python
11
+ from unclogger import get_logger
12
+ logger = get_logger("test logger")
13
+ logger.info("test test", foo="abc", bar=123)
14
+ ```
15
+
16
+ Output:
17
+ ```json
18
+ {
19
+ "foo": "abc",
20
+ "bar": 123,
21
+ "event": "test test",
22
+ "logger": "test logger",
23
+ "level": "info",
24
+ "timestamp": "2021-02-12T22:40:07.600385Z"
25
+ }
26
+ ```
@@ -0,0 +1,175 @@
1
+ # Introduction
2
+
3
+ **Unclogger** is a simple library for customisable structured logging. It mirrors the standard Python logging library API, with a few additional functionalities.
4
+
5
+ !!! Info "Implementation detail"
6
+
7
+ Unclogger is using the [Structlog library](https://www.structlog.org) under the hood.
8
+
9
+ ??? Note
10
+
11
+ The JSON messages in examples below were formatted for convenience; in practice they are sent as a single line of text.
12
+
13
+ ## Structured Loggers
14
+
15
+ Unclogger creates a logger object which adds one important functionality on top of the [standard logging library](https://docs.python.org/3/library/logging.html): in addition to a textual log message, any additional values passed to logging methods as keyword arguments will be included to the log context, along with a few standard fields:
16
+
17
+ * `event`: The original textual log message.
18
+ * `logger`: Name of the logger instance that created the message.
19
+ * `level`: The [log level](https://docs.python.org/3/library/logging.html#logging-levels) of the message.
20
+ * `timestamp`: Time date of the message in ISO 8601 format.
21
+
22
+ The final logging context will be converted and emitted as a JSON-formatted message.
23
+
24
+
25
+ !!! Example
26
+
27
+ ```python
28
+ >>> from unclogger import get_logger
29
+ >>> logger = get_logger("test logger")
30
+ >>> logger.info("test test", foo="abc", bar=123)
31
+ {
32
+ "foo": "abc",
33
+ "bar": 123,
34
+ "event": "test test",
35
+ "logger": "test logger",
36
+ "level": "info",
37
+ "timestamp": "2021-02-12T22:40:07.600385Z"
38
+ }
39
+ >>>
40
+ ```
41
+
42
+ ### Configuration
43
+
44
+ The logger can be configured using the special attribute `config`. This can be used for configuring additional functionality.
45
+
46
+ !!! Example
47
+
48
+ ```python
49
+ >>> from unclogger import get_logger
50
+ >>> logger = get_logger("test logger")
51
+ >>> logger.config.foo = "foo"
52
+ >>> logger.config.bar = "bar"
53
+ >>> print(logger.config.foo)
54
+ foo
55
+ >>> print(logger.config.bar)
56
+ foo
57
+ >>> print(logger.config.baz)
58
+ Traceback (most recent call last):
59
+ File "<stdin>", line 1, in <module>
60
+ AttributeError: 'types.SimpleNamespace' object has no attribute 'baz'. Did you mean: 'bar'?
61
+ >>>
62
+ ```
63
+
64
+ As can be seen in the error message above, `config` is an instance of [SimpleNamespace](https://docs.python.org/3/library/types.html#types.SimpleNamespace).
65
+
66
+
67
+ ### Local Context
68
+
69
+ Each logger has a local context; values can be bound to it so they can appear in any message sent by that logger.
70
+
71
+ !!! Example
72
+
73
+ ```python
74
+ >>> from unclogger import get_logger
75
+ >>> logger = get_logger("test logger").bind(abc="def")
76
+ >>> logger.info("test test", foo="abc", bar=123)
77
+ {
78
+ "abc": "def",
79
+ "foo": "abc",
80
+ "bar": 123,
81
+ "event": "test test",
82
+ "logger": "test logger",
83
+ "level": "info", "timestamp":
84
+ "2021-02-12T23:04:11.743922Z"
85
+ }
86
+ >>> # let's bind some more
87
+ >>> import uuid
88
+ >>> logger = logger.bind(some_uuid=uuid.uuid4())
89
+ {
90
+ "abc": "def",
91
+ "some_uuid": "88227c28-f5a6-430a-bdee-9e967c6c8d13",
92
+ "foo": "abc",
93
+ "bar": 123,
94
+ "event": "test test",
95
+ "logger": "test logger",
96
+ "level": "info",
97
+ "timestamp": "2021-02-12T23:06:15.917766Z"
98
+ }
99
+ >>> # let's change a bound value
100
+ >>> logger = logger.bind(abc="I have a new value now")
101
+ >>> logger.info("test test", foo="abc", bar=123)
102
+ {
103
+ "abc": "I have a new value now",
104
+ "some_uuid": "88227c28-f5a6-430a-bdee-9e967c6c8d13",
105
+ "foo": "abc",
106
+ "bar": 123,
107
+ "event": "test test",
108
+ "logger": "test logger",
109
+ "level": "info",
110
+ "timestamp": "2021-02-12T23:08:21.768578Z"
111
+ }
112
+ >>>
113
+ ```
114
+
115
+
116
+ ## Global Context
117
+
118
+ The [`context_bind`](reference.md#unclogger.context_bind) function will set values in the global context, where they can be used by any logger.
119
+
120
+ !!! Example
121
+
122
+ ```python
123
+ >>> from unclogger import get_logger, context_bind
124
+ >>> # binding data before even creating a logger
125
+ >>> context_bind(abc="def")
126
+ >>> logger1 = get_logger("test logger 1")
127
+ >>> logger1.info("test test", foo="abc", bar=123)
128
+ {
129
+ "abc": "def",
130
+ "foo": "abc",
131
+ "bar": 123,
132
+ "event": "test test",
133
+ "logger": "test logger 1",
134
+ "level": "info",
135
+ "timestamp": "2021-02-12T22:43:48.062282Z"
136
+ }
137
+ >>> logger2 = get_logger("test logger 2")
138
+ >>> # a different logger can access the same data
139
+ >>> logger2.info("another message")
140
+ {
141
+ "abc": "def",
142
+ "event": "another message",
143
+ "logger": "test logger 2",
144
+ "level": "info", "timestamp":
145
+ "2021-02-12T22:45:05.599852Z"
146
+ }
147
+ >>>
148
+ ```
149
+
150
+ ## Custom Processors
151
+
152
+ It is possible to add other `structlog` processors into the logger configuration. For example, to hide sensitive information that might be present in the logged data (using the [Sanitary](https://sanitary.readthedocs.io) library as an example):
153
+
154
+ !!! Example
155
+
156
+ ```python
157
+ >>> from sanitary import StructlogSanitizer
158
+ >>> from unclogger import add_processors, get_logger
159
+ >>>
160
+ >>> add_processors(StructlogSanitizer(keys={"password", "email"}))
161
+ >>>
162
+ >>> logger = get_logger("test logger")
163
+ >>> logger.info("test test", foo="abc", email="test@example.com", password="myPa55w0rd")
164
+ {
165
+ "foo": "abc",
166
+ "email": "********",
167
+ "password": "********",
168
+ "event": "test test",
169
+ "logger": "test logger",
170
+ "level": "info",
171
+ "timestamp": "2021-02-12T22:40:07.600385Z"
172
+ }
173
+ >>>
174
+ ```
175
+
@@ -0,0 +1,41 @@
1
+ # API Reference
2
+
3
+ ## Logger
4
+
5
+ ::: unclogger.get_logger
6
+
7
+ ::: unclogger.context_bind
8
+
9
+ ## Global Log Level Configuration
10
+
11
+ ??? Example
12
+
13
+ ```python
14
+ >>> from unclogger import get_logger, set_level
15
+ >>> logger = get_logger("test logger")
16
+ >>> logger.info("bar")
17
+ {
18
+ "event": "bar",
19
+ "logger": "test logger",
20
+ "level": "info",
21
+ "timestamp": "2021-02-18T21:59:40.102272Z"
22
+ }
23
+ >>> logger.debug("bar")
24
+ >>> set_level("debug")
25
+ >>> logger.debug("bar")
26
+ {
27
+ "event": "bar",
28
+ "logger": "test logger",
29
+ "level": "debug",
30
+ "timestamp": "2021-02-18T22:00:09.147106Z"
31
+ }
32
+ >>> set_level("warning")
33
+ >>> logger.info("bar")
34
+ >>>
35
+ ```
36
+
37
+ ::: unclogger.set_level
38
+
39
+ ## Custom Processors
40
+
41
+ ::: unclogger.processors.add_processors
@@ -0,0 +1,52 @@
1
+ # List available recipes.
2
+ help:
3
+ @just --list --unsorted
4
+
5
+ # Run unit tests.
6
+ test:
7
+ uv run --all-extras pytest --spec
8
+
9
+ # Run unit tests with coverage report.
10
+ test-cov:
11
+ uv run --all-extras pytest --cov --spec
12
+
13
+ # Run linting and formating checks.
14
+ lint:
15
+ uv run deptry .
16
+ uv run ruff format --check .
17
+ uv run ruff check .
18
+ uv run pydocstyle unclogger/
19
+
20
+ # Run static typing analysis.
21
+ type:
22
+ uv run mypy --install-types --non-interactive unclogger/
23
+
24
+ # Run security checks.
25
+ analyze:
26
+ uvx vulture --min-confidence 100 unclogger/
27
+ uvx radon mi --show --multi --min B unclogger/
28
+
29
+ # Run all checks.
30
+ check: lint type analyze
31
+
32
+ # Extract the latest commits
33
+ commits:
34
+ git log $(git describe --tags --abbrev=0)..HEAD --oneline --no-decorate
35
+
36
+ # Reformat the code using isort and ruff.
37
+ [confirm]
38
+ reformat:
39
+ uv run ruff format .
40
+ uv run ruff check --select I --fix .
41
+
42
+ # Serve documentation website for development purposes.
43
+ docs:
44
+ uv run --extra docs mkdocs serve
45
+
46
+ # Build the documentation website.
47
+ docs-build:
48
+ uv run --extra docs mkdocs build
49
+
50
+ # Extract current production requirements. Save to a file by appending `> requirements.txt`.
51
+ reqs:
52
+ uv export --no-default-groups
@@ -0,0 +1,50 @@
1
+ site_name: Unclogger
2
+ repo_url: https://github.com/berislavlopac/unclogger
3
+ site_description: Simple library for customisable structured logging.
4
+ site_author: Berislav Lopac <berislav@lopac.net>
5
+ use_directory_urls: false
6
+ theme:
7
+ name: material
8
+ logo: assets/plunger-logo.png
9
+ favicon: assets/plunger-favicon.png
10
+ features:
11
+ - search.suggest
12
+ palette:
13
+ # Palette toggle for automatic mode
14
+ - media: "(prefers-color-scheme)"
15
+ toggle:
16
+ icon: material/brightness-auto
17
+ name: Switch to light mode
18
+
19
+ # Palette toggle for light mode
20
+ - media: "(prefers-color-scheme: light)"
21
+ scheme: default
22
+ toggle:
23
+ icon: material/brightness-7
24
+ name: Switch to dark mode
25
+
26
+ # Palette toggle for dark mode
27
+ - media: "(prefers-color-scheme: dark)"
28
+ scheme: slate
29
+ toggle:
30
+ icon: material/brightness-4
31
+ name: Switch to system preference
32
+ plugins:
33
+ - search
34
+ - mkapi
35
+ markdown_extensions:
36
+ - abbr
37
+ - attr_list
38
+ - pymdownx.details
39
+ - pymdownx.highlight:
40
+ anchor_linenums: true
41
+ - pymdownx.inlinehilite
42
+ - pymdownx.snippets
43
+ - pymdownx.superfences
44
+ - toc:
45
+ permalink: yes
46
+ - codehilite:
47
+ guess_lang: no
48
+ nav:
49
+ - index.md
50
+ - reference.md