Skip to content

Commit 75ae0a0

Browse files
authored
Merge pull request #8 from armurox/add-version-0.0.6
Add version 0.0.6
2 parents 4ad91ef + ab81861 commit 75ae0a0

File tree

6 files changed

+84
-42
lines changed

6 files changed

+84
-42
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
pytest:
1111
needs: [lint]
12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-22.04
1313
strategy:
1414
matrix:
1515
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
@@ -27,7 +27,7 @@ jobs:
2727
run: tox
2828

2929
lint:
30-
runs-on: ubuntu-latest
30+
runs-on: ubuntu-22.04
3131
steps:
3232
- uses: actions/checkout@v2
3333
- name: Set up Python 3.10
@@ -45,7 +45,7 @@ jobs:
4545
testpypi-package:
4646
if: github.event_name == 'release' && github.event.release.prerelease == true
4747
needs: [pytest]
48-
runs-on: ubuntu-latest
48+
runs-on: ubuntu-22.04
4949
steps:
5050
- uses: actions/checkout@v2
5151
- name: Set up Python 3.10
@@ -75,7 +75,7 @@ jobs:
7575
pypi-package:
7676
if: github.event_name == 'release' && github.event.release.prerelease == false
7777
needs: [pytest]
78-
runs-on: ubuntu-latest
78+
runs-on: ubuntu-22.04
7979
steps:
8080
- uses: actions/checkout@v2
8181
- name: Set up Python 3.10

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,20 @@ logging.config.dictConfig(LOGGING)
128128
The essence boils down to adding the RedactingFilter to your logging config, and to the filters section of the associated handlers to which you want to apply the redaction.
129129

130130

131-
## Release Notes - v0.0.5:
131+
## Release Notes - v0.0.6:
132132

133133
### Improvements and Changes
134-
- Optimized function that applies the redaction (was setting the logger message value twice).
135-
- Changed default_mask key initialization to mask
136-
- Changed patterns key initialization to mask_patterns
134+
- Allow redaction of any generic mapping type, including:
135+
1. `dict`
136+
2. `collections.OrderedDict`
137+
3. `frozendict.frozendict`
138+
4. `collections.ChainMap`
139+
5. `types.MappingProxyType`
140+
6. `collections.UserDict`
141+
and any other mapping class that inherits from `collections.Mapping`
137142

138143
### Bug Fixes
139-
- Handled any exceptions related to deepcopies failing, related to attempt to redact IOStreams, including TypeError
144+
- Fix bug that was converting non-string data types to strings. (Reported in issue [#7](https://github.com/armurox/loggingredactor/issues/7))
140145

141146

142147
## A Note about the Motivation behind Logging Redactor:

loggingredactor/redacting_filter.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import re
22
import logging
33
import copy
4+
from collections.abc import Mapping
45

56

67
class RedactingFilter(logging.Filter):
@@ -32,22 +33,23 @@ def redact(self, content, key=None):
3233
except Exception:
3334
return content
3435
if content_copy:
35-
if isinstance(content_copy, dict):
36-
for k, v in content_copy.items():
37-
content_copy[k] = self._mask if k in self._mask_keys else self.redact(v)
36+
if isinstance(content_copy, Mapping): # Covers all dict-like objects
37+
content_copy = type(content_copy)([
38+
(k, self._mask if k in self._mask_keys else self.redact(v))
39+
for k, v in content_copy.items()
40+
])
3841

3942
elif isinstance(content_copy, list):
4043
content_copy = [self.redact(value) for value in content_copy]
4144

42-
elif isinstance(content, tuple):
45+
elif isinstance(content_copy, tuple):
4346
content_copy = tuple(self.redact(value) for value in content_copy)
4447

4548
# Support for keys in extra field
4649
elif key and key in self._mask_keys:
4750
content_copy = self._mask
4851

49-
else:
50-
content_copy = isinstance(content_copy, str) and content_copy or str(content_copy)
52+
elif isinstance(content_copy, str):
5153
for pattern in self._mask_patterns:
5254
content_copy = re.sub(pattern, self._mask, content_copy)
5355

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
url = f"https://github.com/armurox/loggingredactor/tree/{branch}"
1212

1313
# Get version from environment variable
14-
version = os.getenv('RELEASE_VERSION', '0.0.6') # Default to '0.0.5' if RELEASE_VERSION is not set
14+
version = os.getenv('RELEASE_VERSION', '0.0.6') # Default to '0.0.6' if RELEASE_VERSION is not set
1515
# Get development status
1616
split_version = version.split('-')
1717
if len(split_version) == 2:

tests/test_redacting_filter.py

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
import pytest
33
import logging
44
import loggingredactor
5+
from frozendict import frozendict
6+
from collections import OrderedDict, UserDict, ChainMap
7+
from types import MappingProxyType
8+
9+
MAPPING_TYPES = [dict, OrderedDict, UserDict, ChainMap, frozendict, MappingProxyType]
510

611

712
@pytest.fixture
@@ -67,7 +72,7 @@ def test_arg_list_with_digits(caplog, logger_setup):
6772
logger = logger_setup([re.compile(r'\d{3}')])
6873
nums = [123, '4567']
6974
logger.warning("foo %s", nums)
70-
assert caplog.records[0].message == "foo ['****', '****7']"
75+
assert caplog.records[0].message == "foo [123, '****7']"
7176
assert nums == [123, '4567']
7277

7378

@@ -83,7 +88,7 @@ def test_arg_dict_with_digits(caplog, logger_setup):
8388
logger = logger_setup([re.compile(r'\d{3}')])
8489
bar = {'bar': 123}
8590
logger.warning("foo %s", bar)
86-
assert caplog.records[0].message == "foo {'bar': '****'}"
91+
assert caplog.records[0].message == "foo {'bar': 123}"
8792
assert bar == {'bar': 123}
8893

8994

@@ -147,15 +152,15 @@ def test_extra_int_value(caplog, logger_setup):
147152
logger = logger_setup([re.compile(r'\d{3}')])
148153
bar = {'bar': 123}
149154
logger.warning("foo", extra=bar)
150-
assert caplog.records[0].bar == "****"
155+
assert caplog.records[0].bar == 123
151156
assert bar == {'bar': 123}
152157

153158

154159
def test_extra_float_value(caplog, logger_setup):
155160
logger = logger_setup([re.compile(r'\d{3}')])
156161
bar = {'bar': 123.6}
157162
logger.warning("foo", extra=bar)
158-
assert caplog.records[0].bar == "****.6"
163+
assert caplog.records[0].bar == 123.6
159164
assert bar == {'bar': 123.6}
160165

161166

@@ -177,35 +182,62 @@ def test_extra_nested_dict(caplog, logger_setup):
177182

178183
def test_extra_do_redact_key(caplog, logger_setup):
179184
logger = logger_setup([re.compile(r'\d{3}')])
180-
extra_data = {'thing987': '123'}
181-
logger.warning("foo", extra=extra_data)
182-
assert caplog.records[0].thing987 == "****"
183-
extra_data = {'thing987': '123'}
185+
for mapping_type in MAPPING_TYPES:
186+
extra_data = mapping_type({'thing987': '123'})
187+
logger.warning("foo", extra=extra_data)
188+
assert caplog.records[0].thing987 == "****"
189+
assert extra_data == {'thing987': '123'}
190+
assert isinstance(extra_data, mapping_type)
184191

185192

186193
def test_extra_do_not_redact_key(caplog, logger_setup):
187194
logger = logger_setup([re.compile(r'\d{3}')])
188-
extra_data = {'thing987': 'foobar'}
189-
logger.warning("foo", extra=extra_data)
190-
assert caplog.records[0].thing987 == "foobar"
191-
extra_data = {'thing987': 'foobar'}
195+
for mapping_type in MAPPING_TYPES:
196+
extra_data = mapping_type({'thing987': 'foobar'})
197+
logger.warning("foo", extra=extra_data)
198+
assert caplog.records[0].thing987 == "foobar"
199+
assert extra_data == {'thing987': 'foobar'}
200+
assert isinstance(extra_data, mapping_type)
192201

193202

194203
def test_extra_nested_dict_with_list(caplog, logger_setup):
195204
logger = logger_setup([re.compile(r'\d{3}')])
196-
extra_data = {
197-
'bar': {
198-
'thing': ['one', '456'],
199-
},
200-
}
201-
logger.warning("foo", extra=extra_data)
202-
assert caplog.records[0].bar['thing'][0] == 'one'
203-
assert caplog.records[0].bar['thing'][1] == '****'
204-
assert extra_data == {
205-
'bar': {
206-
'thing': ['one', '456'],
207-
},
208-
}
205+
for mapping_type in MAPPING_TYPES:
206+
extra_data = mapping_type({
207+
'bar': mapping_type({
208+
'thing': ['one', '456'],
209+
}),
210+
})
211+
logger.warning("foo", extra=extra_data)
212+
assert caplog.records[0].bar['thing'][0] == 'one'
213+
assert caplog.records[0].bar['thing'][1] == '****'
214+
assert extra_data == {
215+
'bar': {
216+
'thing': ['one', '456'],
217+
},
218+
}
219+
assert isinstance(extra_data, mapping_type)
220+
assert isinstance(extra_data['bar'], mapping_type)
221+
222+
223+
def test_extra_nested_dict_with_tuple(caplog, logger_setup):
224+
logger = logger_setup([re.compile(r'\d{3}')])
225+
for mapping_type in MAPPING_TYPES:
226+
extra_data = mapping_type({
227+
'bar': mapping_type({
228+
'thing': ('one', '456'),
229+
}),
230+
})
231+
logger.warning("foo", extra=extra_data)
232+
assert caplog.records[0].bar['thing'][0] == 'one'
233+
assert caplog.records[0].bar['thing'][1] == '****'
234+
assert extra_data == {
235+
'bar': {
236+
'thing': ('one', '456'),
237+
},
238+
}
239+
assert isinstance(extra_data, mapping_type)
240+
assert isinstance(extra_data['bar'], mapping_type)
209241

210242

211243
def test_match_group(caplog, logger_setup):

tox.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ deps = ruff
1717
commands = ruff check .
1818

1919
[testenv]
20-
deps = pytest-cov
20+
deps =
21+
pytest-cov
22+
frozendict
23+
.
2124
commands = python -m pytest --cov=./loggingredactor
2225

2326
[testenv:flake8]

0 commit comments

Comments
 (0)