Skip to content

Commit 173134e

Browse files
committed
release 0.1.0
1 parent 7018a2e commit 173134e

File tree

12 files changed

+214
-90
lines changed

12 files changed

+214
-90
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Unclogger
22
=========
33

4-
Simple library for customisable structured logging.]
4+
Simple library for customisable structured logging.
55

66

77
## Development Environment
@@ -54,5 +54,3 @@ $ mkdocs build
5454
```
5555

5656
This will create the HTML documentation in the `site` directory.
57-
58-
API Documentation is served by GitLab Pages.

docs/assets/plunger-favicon.png

8.59 KB
Loading

docs/index.md

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22

33
`unclogger` is a simple library for customisable structured logging. It mirrors the standard Python logging library API, with a few additional functionalities.
44

5-
## Structured Logging
5+
!!! Info
6+
7+
Implementation detail: `unclogger` is using the [Structlog library](https://www.structlog.org) under the hood.
8+
9+
## Structured Loggers
610

711
Passing keyword arguments to a log method will add them to the log data. Log data is converted to a JSON message before sending.
812

913
**Note:** The JSON in examples below was formatted for convenience; in practice it is sent as a single line of text.
1014

15+
!!! Example
16+
17+
```python
1118
>>> from unclogger import get_logger
1219
>>> logger = get_logger("test logger")
1320
>>> logger.info("test test", foo="abc", bar=123)
@@ -19,12 +26,16 @@ Passing keyword arguments to a log method will add them to the log data. Log dat
1926
"level": "info",
2027
"timestamp": "2021-02-12T22:40:07.600385Z"
2128
}
22-
29+
>>>
30+
```
2331

2432
### Configuration
2533

26-
The logger can be configured using the special attribute `config`:
34+
The logger can be configured using the special attribute `config`. This can be used for configuring additional functionality, e.g. when [handling sensitive data](sensitive.md).
2735

36+
!!! Example
37+
38+
```python
2839
>>> from unclogger import get_logger
2940
>>> logger = get_logger("test logger")
3041
>>> logger.config.foo = "foo"
@@ -37,41 +48,19 @@ The logger can be configured using the special attribute `config`:
3748
Traceback (most recent call last):
3849
File "<stdin>", line 1, in <module>
3950
AttributeError: 'types.SimpleNamespace' object has no attribute 'baz'. Did you mean: 'bar'?
51+
>>>
52+
```
4053

4154
As can be seen in the error message above, `config` is an instance of [SimpleNamespace](https://docs.python.org/3.10/library/types.html#types.SimpleNamespace).
4255

4356

44-
### Global Context Binding
45-
46-
The [`context_bind`](reference.md#uncloggerloggercontext_bind) function will set values in the global context, where it can be used by any logger.
57+
### Local Context
4758

48-
>>> from unclogger import get_logger, bind_data
49-
>>> # binding data before even creating a logger
50-
>>> bind_data(abc="def")
51-
>>> logger1 = get_logger("test logger 1")
52-
>>> logger1.info("test test", foo="abc", bar=123)
53-
{
54-
"abc": "def",
55-
"foo": "abc",
56-
"bar": 123,
57-
"event": "test test",
58-
"logger": "test logger 1",
59-
"level": "info",
60-
"timestamp": "2021-02-12T22:43:48.062282Z"
61-
}
62-
>>> logger2 = get_logger("test logger 2")
63-
>>> # a different logger can access the same data
64-
>>> logger2.info("another message")
65-
{
66-
"abc": "def",
67-
"event": "another message",
68-
"logger": "test logger 2",
69-
"level": "info", "timestamp":
70-
"2021-02-12T22:45:05.599852Z"
71-
}
59+
Each logger has a local context; values can be bound to it so they can appear in any message sent by that logger.
7260

73-
### Local Context Binding
61+
!!! Example
7462

63+
```python
7564
>>> from unclogger import get_logger
7665
>>> logger = get_logger("test logger").bind(abc="def")
7766
>>> logger.info("test test", foo="abc", bar=123)
@@ -110,16 +99,40 @@ The [`context_bind`](reference.md#uncloggerloggercontext_bind) function will set
11099
"level": "info",
111100
"timestamp": "2021-02-12T23:08:21.768578Z"
112101
}
102+
>>>
103+
```
113104

114-
### Logging Level Configuration
115105

116-
>>> from unclogger import get_logger, configure
117-
>>> logger = get_logger("test logger")
118-
>>> logger.info("bar")
119-
{"event": "bar", "logger": "test logger", "level": "info", "timestamp": "2021-02-18T21:59:40.102272Z"}
120-
>>> logger.debug("bar")
121-
>>> configure("debug")
122-
>>> logger.debug("bar")
123-
{"event": "bar", "logger": "test logger", "level": "debug", "timestamp": "2021-02-18T22:00:09.147106Z"}
124-
>>> configure("warning")
125-
>>> logger.info("bar")
106+
## Global Context
107+
108+
The [`context_bind`](reference.md#uncloggerloggercontext_bind) function will set values in the global context, where it can be used by any logger.
109+
110+
!!! Example
111+
112+
```python
113+
>>> from unclogger import get_logger, context_bind
114+
>>> # binding data before even creating a logger
115+
>>> context_bind(abc="def")
116+
>>> logger1 = get_logger("test logger 1")
117+
>>> logger1.info("test test", foo="abc", bar=123)
118+
{
119+
"abc": "def",
120+
"foo": "abc",
121+
"bar": 123,
122+
"event": "test test",
123+
"logger": "test logger 1",
124+
"level": "info",
125+
"timestamp": "2021-02-12T22:43:48.062282Z"
126+
}
127+
>>> logger2 = get_logger("test logger 2")
128+
>>> # a different logger can access the same data
129+
>>> logger2.info("another message")
130+
{
131+
"abc": "def",
132+
"event": "another message",
133+
"logger": "test logger 2",
134+
"level": "info", "timestamp":
135+
"2021-02-12T22:45:05.599852Z"
136+
}
137+
>>>
138+
```

docs/reference.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,43 @@
11
# API Reference
22

3-
## ![mkapi](unclogger.get_logger)
3+
## Logger
44

5-
## ![mkapi](unclogger.context_bind)
5+
### ![mkapi](unclogger.get_logger)
66

7-
## ![mkapi](unclogger.configure)
7+
### ![mkapi](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+
### ![mkapi](unclogger.set_level)
38+
39+
## Processors
40+
41+
### Sensitive Data
42+
43+
#### ![mkapi](unclogger.processors.clean_data.clean_sensitive_data)

docs/sensitive.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
If the name of any field in the structured log message matches one of the listed sensitive names, the value of that field is (recursively) replaced with a safe value:
99

10+
!!! Example
11+
12+
```python
1013
>>> from unclogger import get_logger
1114
>>> logger = get_logger("test logger")
1215
>>> logger.info("clean password", password="blabla", foo={"Email": "[email protected]"})
@@ -18,19 +21,29 @@ If the name of any field in the structured log message matches one of the listed
1821
"level": "info",
1922
"timestamp": "2022-02-02T10:53:52.245833Z"
2023
}
24+
>>>
25+
```
2126

2227
A basic list of sensitive field names is included in `unclogger`:
2328

29+
!!! Example
30+
31+
```python
2432
>>> from unclogger.processors.clean_data import SENSITIVE_FIELDS
2533
>>> SENSITIVE_FIELDS
2634
['password', 'email', 'email_1', 'firstname', 'lastname', 'currentpassword', 'newpassword', 'tmppassword', 'authentication', 'refresh', 'auth', 'http_refresh', 'http_x_forwarded_authorization', 'http_x_endpoint_api_userinfo', 'http_authorization', 'idtoken', 'oauthidtoken', 'publickey', 'privatekey']
35+
>>>
36+
```
2737

2838
!!! Note
2939

3040
Note that the list is case-insensitive; `unclogger` normalizes all field names to lowercase, so e.g. `email` and `Email` are treated equally.
3141

3242
This list can be configured with an iterable of custom field names:
3343

44+
!!! Example
45+
46+
```python
3447
>>> from unclogger import get_logger
3548
>>> logger = get_logger("test logger")
3649
>>> logger.config.sensitive_keys = {"foo", "bar"}
@@ -49,11 +62,16 @@ This list can be configured with an iterable of custom field names:
4962
"timestamp":
5063
"2022-02-02T11:08:01.260019Z"
5164
}
65+
>>>
66+
```
5267

5368
### Configurable Replacement Value
5469

5570
A custom string can be used instead of the default replacement value:
5671

72+
!!! Example
73+
74+
```python
5775
>>> from unclogger import get_logger
5876
>>> logger = get_logger("test logger")
5977
>>> logger.config.replacement = "blablabla"
@@ -66,11 +84,16 @@ A custom string can be used instead of the default replacement value:
6684
"level": "info",
6785
"timestamp": "2022-12-13T20:02:38.520599Z"
6886
}
87+
>>>
88+
```
6989

7090
### Hashing Sensitive Data
7191

7292
Instead of a replacement string, `config.replacement` can define a Python callable:
7393

94+
!!! Example
95+
96+
```python
7497
>>> from unclogger import get_logger
7598
>>> logger = get_logger("test logger")
7699
>>> logger.config.replacement = hashlib.sha256
@@ -83,6 +106,8 @@ Instead of a replacement string, `config.replacement` can define a Python callab
83106
"level": "info",
84107
"timestamp": "2022-12-13T20:06:37.542212Z"
85108
}
109+
>>>
110+
```
86111

87112
This can be used so that the data can still be identified (e.g. an email address will always have the same has value) without sending the actual data to the log.
88113

@@ -98,6 +123,10 @@ This can be used so that the data can still be identified (e.g. an email address
98123
```
99124

100125
## Sensitive Text Values
126+
127+
!!! Example
128+
129+
```python
101130
>>> from unclogger import get_logger
102131
>>> logger = get_logger("test logger")
103132
>>> logger.info("'Authentication': 1234")
@@ -107,5 +136,7 @@ This can be used so that the data can still be identified (e.g. an email address
107136
"level": "info",
108137
"timestamp": "2022-02-02T11:22:21.997204Z"
109138
}
139+
>>>
140+
```
110141

111142
*[PII]: Personally Identifiable Information

mkdocs.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
site_name: Unclogger
2-
repo_url: https://github/berislavlopac/unclogger
2+
repo_url: https://github.com/berislavlopac/unclogger
33
site_description: Simple library for customisable structured logging.]
44
site_author: Berislav Lopac <[email protected]>
55
use_directory_urls: false
66
theme:
77
name: material
8-
logo: assets/plunger.png
8+
logo: assets/plunger-logo.png
9+
favicon: assets/plunger-favicon.png
910
plugins:
1011
- search
1112
- mkapi
1213
markdown_extensions:
1314
- abbr
1415
- attr_list
16+
- pymdownx.details
1517
- pymdownx.highlight:
1618
anchor_linenums: true
1719
- pymdownx.inlinehilite

setup.cfg

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,35 @@
22

33
import pytest
44

5-
from unclogger import configure
5+
from unclogger import set_level
66

77

8-
def test_configure_sets_default_log_level():
8+
def test_sets_default_log_level():
99
# configure() is called at import time
1010
assert logging.root.level == logging.INFO
1111

1212

13-
def test_configure_sets_log_level_with_textual_parameter(caplog):
13+
def test_sets_log_level_with_textual_parameter(caplog):
1414
with caplog.at_level(logging.INFO):
1515
assert logging.root.level == logging.INFO
16-
configure("DEBUG")
16+
set_level("DEBUG")
1717
assert logging.root.level == logging.DEBUG
18-
configure("error")
18+
set_level("error")
1919
assert logging.root.level == logging.ERROR
2020

2121

22-
def test_configure_sets_log_level_with_integer_parameter(caplog):
22+
def test_sets_log_level_with_integer_parameter(caplog):
2323
with caplog.at_level(logging.INFO):
2424
assert logging.root.level == logging.INFO
25-
configure(logging.DEBUG)
25+
set_level(logging.DEBUG)
2626
assert logging.root.level == logging.DEBUG
27-
configure(40)
27+
set_level(40)
2828
assert logging.root.level == logging.ERROR
29-
configure("30")
29+
set_level("30")
3030
assert logging.root.level == logging.WARNING
3131

3232

3333
@pytest.mark.parametrize("value", ("foo", "bar baz", 12.5, "12.5"))
34-
def test_configure_raises_an_exception_on_incorrect_argument(value):
34+
def test_raises_an_exception_on_incorrect_argument(value):
3535
with pytest.raises(ValueError):
36-
configure(value)
36+
set_level(value)

unclogger/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"""Simple library for customisable structured logging."""
22

3-
from .logger import configure, context_bind, context_clear, get_logger, Unclogger
3+
import logging as _std_logging
4+
5+
from .logger import context_bind, context_clear, get_logger, set_level, Unclogger
46

57
getLogger = get_logger # alias for compatibility with standard logging
68

7-
configure()
9+
_std_logging.basicConfig(format="%(message)s")
10+
set_level()

0 commit comments

Comments
 (0)