logging-objects-with-schema 1.0.2__tar.gz → 1.0.4__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.
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/PKG-INFO +12 -3
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/README.md +11 -2
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/pyproject.toml +1 -1
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/pyproject.toml.orig +1 -1
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/schema_applier.py +15 -6
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/schema_loader.py +11 -0
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/LICENSE +0 -0
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/__init__.py +0 -0
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/errors.py +0 -0
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/py.typed +0 -0
- {logging_objects_with_schema-1.0.2 → logging_objects_with_schema-1.0.4}/src/logging_objects_with_schema/schema_logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: logging-objects-with-schema
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Schema-aware Python logging with strict extra validation and schema-driven field projection.
|
|
5
5
|
Keywords: logging,schema,validation,structured-logging,structured-logs
|
|
6
6
|
Author: Dmitrii Safronov
|
|
@@ -23,6 +23,13 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
|
|
24
24
|
# python-logging-objects-with-schema
|
|
25
25
|
|
|
26
|
+
Arbitrary `extra` fields let log producers use different names, structures, and
|
|
27
|
+
types for the same information, making downstream searches, alerts, and
|
|
28
|
+
dashboards harder to maintain. A shared schema makes these structured fields a
|
|
29
|
+
contract between producers and consumers. `SchemaLogger` emits the valid fields
|
|
30
|
+
and reports data-validation violations separately, so a malformed field does
|
|
31
|
+
not discard the valid part of the record.
|
|
32
|
+
|
|
26
33
|
`SchemaLogger` extends Python's standard `logging.Logger` with schema-driven
|
|
27
34
|
validation and projection of `extra` fields. It preserves the standard logging
|
|
28
35
|
API while invalid structured data is dropped and reported separately.
|
|
@@ -236,8 +243,10 @@ An example of a valid empty schema (no leaves, no problems):
|
|
|
236
243
|
- **`item_type`**: Optional field for list-typed leaves. Must be a string if
|
|
237
244
|
present. See "List-typed fields" section below.
|
|
238
245
|
- **Root key restrictions**: Root keys cannot conflict with standard `logging`
|
|
239
|
-
module fields (e.g., `name`, `levelno`, `pathname`).
|
|
240
|
-
|
|
246
|
+
module fields (e.g., `name`, `levelno`, `pathname`). This includes the
|
|
247
|
+
`message` and `asctime` fields, which are populated by formatters and are
|
|
248
|
+
rejected by `logging.Logger.makeRecord()`. Such conflicts cause schema
|
|
249
|
+
validation to fail.
|
|
241
250
|
|
|
242
251
|
**List-typed fields:**
|
|
243
252
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# python-logging-objects-with-schema
|
|
2
2
|
|
|
3
|
+
Arbitrary `extra` fields let log producers use different names, structures, and
|
|
4
|
+
types for the same information, making downstream searches, alerts, and
|
|
5
|
+
dashboards harder to maintain. A shared schema makes these structured fields a
|
|
6
|
+
contract between producers and consumers. `SchemaLogger` emits the valid fields
|
|
7
|
+
and reports data-validation violations separately, so a malformed field does
|
|
8
|
+
not discard the valid part of the record.
|
|
9
|
+
|
|
3
10
|
`SchemaLogger` extends Python's standard `logging.Logger` with schema-driven
|
|
4
11
|
validation and projection of `extra` fields. It preserves the standard logging
|
|
5
12
|
API while invalid structured data is dropped and reported separately.
|
|
@@ -213,8 +220,10 @@ An example of a valid empty schema (no leaves, no problems):
|
|
|
213
220
|
- **`item_type`**: Optional field for list-typed leaves. Must be a string if
|
|
214
221
|
present. See "List-typed fields" section below.
|
|
215
222
|
- **Root key restrictions**: Root keys cannot conflict with standard `logging`
|
|
216
|
-
module fields (e.g., `name`, `levelno`, `pathname`).
|
|
217
|
-
|
|
223
|
+
module fields (e.g., `name`, `levelno`, `pathname`). This includes the
|
|
224
|
+
`message` and `asctime` fields, which are populated by formatters and are
|
|
225
|
+
rejected by `logging.Logger.makeRecord()`. Such conflicts cause schema
|
|
226
|
+
validation to fail.
|
|
218
227
|
|
|
219
228
|
**List-typed fields:**
|
|
220
229
|
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "logging-objects-with-schema"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "Schema-aware Python logging with strict extra validation and schema-driven field projection."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "logging-objects-with-schema"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "Schema-aware Python logging with strict extra validation and schema-driven field projection."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -11,11 +11,20 @@ from .errors import _DataProblem
|
|
|
11
11
|
from .schema_loader import _CompiledSchema, _SchemaLeaf
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def _safe_repr(value: Any) -> str:
|
|
15
|
+
"""Represent diagnostic data without propagating user __repr__ failures."""
|
|
16
|
+
try:
|
|
17
|
+
return repr(value)
|
|
18
|
+
except Exception:
|
|
19
|
+
# Do not format the value or exception again: either may have a broken repr.
|
|
20
|
+
return "<unrepresentable value>"
|
|
21
|
+
|
|
22
|
+
|
|
14
23
|
def _create_validation_error_dict(field: str, error: str, value: Any) -> dict[str, Any]:
|
|
15
24
|
"""Create a dict for a single validation error.
|
|
16
25
|
|
|
17
|
-
All values
|
|
18
|
-
|
|
26
|
+
All values use safe repr() formatting. If user code raises during repr(),
|
|
27
|
+
a constant placeholder preserves the validation diagnostic.
|
|
19
28
|
|
|
20
29
|
Args:
|
|
21
30
|
field: Field name that caused the validation error.
|
|
@@ -23,12 +32,12 @@ def _create_validation_error_dict(field: str, error: str, value: Any) -> dict[st
|
|
|
23
32
|
value: Invalid value that caused the error.
|
|
24
33
|
|
|
25
34
|
Returns:
|
|
26
|
-
Dict with field, error, and value
|
|
35
|
+
Dict with field, error, and value as safely represented strings.
|
|
27
36
|
"""
|
|
28
37
|
return {
|
|
29
|
-
"field":
|
|
30
|
-
"error":
|
|
31
|
-
"value":
|
|
38
|
+
"field": _safe_repr(field),
|
|
39
|
+
"error": _safe_repr(error),
|
|
40
|
+
"value": _safe_repr(value),
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
|
|
@@ -645,11 +645,16 @@ def _get_builtin_logrecord_attributes() -> set[str]:
|
|
|
645
645
|
Returns:
|
|
646
646
|
Set of attribute names that are reserved by the logging system.
|
|
647
647
|
Examples include: 'name', 'levelno', 'pathname', 'lineno', 'msg', etc.
|
|
648
|
+
Also includes 'message' and 'asctime', which are not set on a fresh
|
|
649
|
+
LogRecord instance but are rejected by Logger.makeRecord() and
|
|
650
|
+
populated by formatters.
|
|
648
651
|
|
|
649
652
|
Example:
|
|
650
653
|
>>> forbidden = _get_builtin_logrecord_attributes()
|
|
651
654
|
>>> "name" in forbidden
|
|
652
655
|
True
|
|
656
|
+
>>> "message" in forbidden
|
|
657
|
+
True
|
|
653
658
|
>>> "ServicePayload" in forbidden
|
|
654
659
|
False
|
|
655
660
|
"""
|
|
@@ -672,6 +677,12 @@ def _get_builtin_logrecord_attributes() -> set[str]:
|
|
|
672
677
|
if not callable(attr_value):
|
|
673
678
|
forbidden.add(attr_name)
|
|
674
679
|
|
|
680
|
+
# makeRecord() rejects these names even though dir(record) does not list
|
|
681
|
+
# them: both "message" and "asctime" are set by Formatter.format() before
|
|
682
|
+
# formatting. Without this, such root keys would pass schema validation
|
|
683
|
+
# and later raise KeyError when a log record is created.
|
|
684
|
+
forbidden.update({"message", "asctime"})
|
|
685
|
+
|
|
675
686
|
return forbidden
|
|
676
687
|
|
|
677
688
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|