Skip to content

Commit 426eb39

Browse files
authored
Changeset targeting version 1.0.0-beta3 (#13)
1 parent 3d896a4 commit 426eb39

5 files changed

Lines changed: 72 additions & 49 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ All notable changes to this project will be documented in this file. The
44
format is based (to a large extent) on [Keep a Changelog](https://keepachangelog.com/).
55

66
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7-
The entire *public API* is documented in the [API Reference](https://certlib-log.readthedocs.io/page/reference/)
8-
(with the proviso that *neither* any exception messages *nor* any source
9-
code available there via the `<> Source code...` elements are part of the
10-
*public API*).
7+
The *public API* is documented in the [API Reference](https://certlib-log.readthedocs.io/page/reference/).
118

129

1310
## [Unreleased] (2026-XX-XX)

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# certlib.log
22

3-
...is a library that extends the standard [`logging`](https://docs.python.org/3/library/logging.html)
3+
...is a library that extends the standard **[`logging`](https://docs.python.org/3/library/logging.html)**
44
toolset. Among other things, it makes it possible to introduce
5-
*structured logging* with minimal fuss, and/or to start using the
6-
modern `{}`-based style of log message formatting (gradually if
5+
_**structured logging**_ with minimal fuss, and/or to start using the
6+
modern _**`{}`-based style of log message formatting**_ (gradually if
77
required).
88

99

1010
## Basic Info
1111

1212
- **Documentation:** [certlib-log.readthedocs.io](https://certlib-log.readthedocs.io)
13-
- **Home page:** [github.com/CERT-Polska/certlib-log](https://github.com/CERT-Polska/certlib-log)
14-
- **Contributing:** [github.com/CERT-Polska/certlib-log/pulls](https://github.com/CERT-Polska/certlib-log/pulls)
13+
- **Repository:** [github.com/CERT-Polska/certlib-log](https://github.com/CERT-Polska/certlib-log)
14+
- **Package:** [pypi.org/project/certlib-log](https://pypi.org/project/certlib-log/)
1515

1616
You can install the `certlib.log` library by running (typically, in a
1717
[*virtual environment*](https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments))

docs/doc-src/reference.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,43 @@
11
# API Reference
22

3-
!!! info
3+
!!! danger "Warning"
4+
5+
The `certlib.log` library is currently in the _**beta**_ stage
6+
of development. This means, in particular, that _**backward
7+
incompatible**_ changes to the public API are still possible
8+
(even if unlikely) in *non-major* versions -- _**until**_ the
9+
final _**1.0.0**_ version is released.
10+
11+
***
12+
13+
!!! exclusion "Interface exclusion"
14+
15+
In general, the following elements are _**not**_ part of the public
16+
API (so, in particular, they may change in *minor* or *patch* versions
17+
of the `certlib.log` library):
18+
19+
* any elements *not* documented in this *API reference*;
20+
21+
* specific *runtime types* of any objects bound to a documented
22+
element of the API (variable, attribute, parameter or call
23+
result) -- *provided that* they remain correct with respect to
24+
the element's type annotation, according to the [static typing
25+
rules](https://typing.python.org/en/latest/spec/index.html);
26+
27+
* specific behaviors in cases where -- according to the
28+
documentation -- *undefined behavior* is expected;
29+
30+
* any elements that appear in this document *only* in source code
31+
excerpts (available via `<> Source code...` drop-down widgets),
32+
e.g., specific exception messages.
33+
34+
!!! warning "Important"
435

536
Whenever this document refers to *undefined behavior*, this should
637
be understood to mean: *the API makes no guarantees about what will
738
happen -- an exception or a malfunction is likely.*
839

40+
***
941

1042
::: certlib.log.StructuredLogsFormatter
1143
handler: python

src/certlib/log.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ class method would return an instance of [`dt.date`][datetime.date]
662662
representing a *February 2026* date, e.g., one equal to `dt.date(2026,
663663
2, 21)`).
664664
665-
What it means when the logging system is configured to employ a
665+
What that means if the logging system is configured to employ a
666666
[`StructuredLogsFormatter`][], is that:
667667
668668
* the formatted message will appear in the JSON-serialized *output
@@ -672,9 +672,9 @@ class method would return an instance of [`dt.date`][datetime.date]
672672
673673
!!! info
674674
675-
Please note that when you use **[`xm`][]**, you still benefit from
676-
the standard mechanism of deferring message formatting until the log
677-
entry really needs to be emitted (regardless of what formatter is in
675+
When you use **[`xm`][]**, you still benefit from the standard
676+
mechanism of deferring message formatting until the log entry
677+
really needs to be emitted (regardless of what formatter is in
678678
use).
679679
680680
The code in the next example does the same as above; the only difference
@@ -932,11 +932,6 @@ class method would return an instance of [`dt.date`][datetime.date]
932932

933933

934934
COMMONLY_EXPECTED_NON_STANDARD_OUTPUT_KEYS: Final[Set[str]] = frozenset({
935-
# These items are to be provided automatically (at least by default)
936-
# by the `StructuredLogsFormatter`'s machinery.
937-
'py_ver',
938-
'script_args',
939-
940935
# These items *need* to be provided individually per system/component
941936
# (in `StructuredLogsFormatter` configuration, or by subclassing...).
942937
'system',
@@ -1023,8 +1018,7 @@ class StructuredLogsFormatter(logging.Formatter):
10231018
even though you may decide to use some other serialization format,
10241019
if this is OK for you/your organization). Alternatively, a string
10251020
being a *dotted path* (*importable dotted name*) that points to
1026-
such a function (callable) can be given as the **`serializer`**
1027-
argument.
1021+
such a callable can be given as the **`serializer`** argument.
10281022
10291023
!!! note
10301024
@@ -1065,6 +1059,11 @@ class StructuredLogsFormatter(logging.Formatter):
10651059
10661060
If any of them does not comply, [`TypeError`][] is raised.
10671061
1062+
!!! info
1063+
1064+
Obviously, passing any unexpected (surplus) arguments also
1065+
causes [`TypeError`][].
1066+
10681067
!!! note
10691068
10701069
Thanks to the interface extensions described above, you can
@@ -1250,11 +1249,11 @@ def __init__(self, /, *args: Any, **kwargs: Any):
12501249

12511250
def unregister_auto_makers(self) -> None:
12521251
"""
1253-
A rarely useful method: you should invoke it on an instance
1254-
of `StructuredLogsFormatter` *only when* you need to stop
1255-
using that instance but continue using any `logging` stuff
1256-
during further program execution (this does not seem to be
1257-
a common case).
1252+
A rarely useful method: you may want to invoke it on an instance
1253+
of `StructuredLogsFormatter` *only when* you need to stop using
1254+
that instance but continue using any `logging` stuff during
1255+
further program execution (this does not seem to be a common
1256+
case).
12581257
"""
12591258
for rec_attr in self.auto_makers.keys():
12601259
unregister_log_record_attr_auto_maker(rec_attr)
@@ -1428,12 +1427,10 @@ def get_output_keys_required_in_defaults_or_auto_makers(self) -> Set[str]:
14281427
14291428
The default implementation of this method just uses the set of
14301429
keys defined as [`COMMONLY_EXPECTED_NON_STANDARD_OUTPUT_KEYS`][]
1431-
(here it is worth noting that, because the default implementation
1432-
of [`make_base_auto_makers`][] already provides *auto-makers*
1433-
for certain keys, the *only* keys for which it is *required*
1434-
to specify *default values* or *auto-makers* when invoking the
1435-
[`StructuredLogsFormatter`][] constructor -- are: `"system"`,
1436-
`"component"` and `"component_type"`).
1430+
(which means that, when invoking the [`StructuredLogsFormatter`][]
1431+
constructor, it is *required* to specify *default values* and/or
1432+
*auto-makers* for the keys: `"system"`, `"component"` and
1433+
`"component_type"`).
14371434
14381435
!!! info
14391436
@@ -1450,7 +1447,7 @@ def get_output_keys_required_in_defaults_or_auto_makers(self) -> Set[str]:
14501447
14511448
```python
14521449
my_formatter = StructuredLogsFormatter(
1453-
# This satisfies the requirement:
1450+
# This is OK (the requirement is satisfied):
14541451
defaults={
14551452
"system": None,
14561453
"component": None,
@@ -1650,7 +1647,7 @@ def format_timestamp(
16501647
representation is a *UTC* one (with `Z`, rather than `+00:00`,
16511648
as its suffix), e.g.: `"2026-03-15 13:48:56.726403Z"`.
16521649
1653-
!!! info
1650+
!!! note
16541651
16551652
The [`logging.Formatter`][]-specific attributes related to
16561653
timestamp formatting (`converter`, `default_time_format` and
@@ -1807,7 +1804,8 @@ def get_prepared_output_data(self, record: logging.LogRecord) -> dict[str, Outpu
18071804
described above; and *even* if some *default value* is defined
18081805
for that key!); note that *nested* values, even if *void*, are
18091806
*never* subject to such an *exclusion* (at least if the default
1810-
implementation of `prepare_value` is used);
1807+
implementations of `prepare_value` and `prepare_submapping_key`
1808+
are used);
18111809
18121810
* potential *item collisions* (which might occur, for example,
18131811
when some **key** is present *both* in the `ExtendedMessage`'s
@@ -2620,17 +2618,17 @@ class ExtendedMessage:
26202618
26212619
When it comes to the arguments **`exc_info`**, **`stack_info`**
26222620
and **`stacklevel`**, they should *not* be included in that
2623-
mapping; each of them, if to be specified, should *only* be
2624-
specified as a real keyword argument (putting any of them in
2625-
that mapping will result in undefined behavior).
2621+
mapping. Each of them, if to be specified, should *only* be
2622+
specified as a real keyword argument. Putting any of them in
2623+
that mapping will result in undefined behavior.
26262624
26272625
!!! warning "Interface restriction"
26282626
26292627
If you pass a **`stack_info`** and/or **`stacklevel`** argument
26302628
to the **[`ExtendedMessage`][]** (**[`xm`][]**) constructor, you
26312629
should *not* pass **`stack_info`** or **`stacklevel`** to the
2632-
related [logger method call](https://docs.python.org/3/library/logging.html#logging.Logger.debug)
2633-
(doing so will result in undefined behavior).
2630+
related [logger method call](https://docs.python.org/3/library/logging.html#logging.Logger.debug);
2631+
doing so will result in undefined behavior.
26342632
26352633
```python
26362634
# All WRONG (!!!):
@@ -2670,7 +2668,7 @@ class ExtendedMessage:
26702668
as the first positional argument to a [logger method
26712669
call](https://docs.python.org/3/library/logging.html#logging.Logger.debug),
26722670
you should *not* pass to that call any other *positional*
2673-
arguments (doing so will result in undefined behavior).
2671+
arguments; doing so will result in undefined behavior.
26742672
26752673
```python
26762674
# WRONG (!!!):
@@ -3454,7 +3452,7 @@ def __call__(self, output_data: dict[str, OutputValue], /) -> str: ...
34543452
34553453
The [`json.dumps`][] function, which is the default
34563454
**[`serializer`][StructuredLogsFormatter.serializer]**, satisfies
3457-
this requirement in respect to the default implementation of
3455+
this requirement with respect to the default implementation of
34583456
**[`prepare_value`][StructuredLogsFormatter.prepare_value]**.
34593457
34603458
!!! info "Typing details"

tests/test_certlib_log.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,7 @@ def typical_log_case(
13031303
'component': None, # ("void" value)
13041304
'component_type': None, # ("void" value)
13051305
}),
1306+
base_auto_makers={},
13061307
),
13071308
dict(
13081309
defaults={},
@@ -1312,15 +1313,10 @@ def typical_log_case(
13121313
# Expected public attributes
13131314
dict(
13141315
defaults={},
1315-
auto_makers={
1316-
'<PREFIX>py_ver': AnyOfType(Function),
1317-
'<PREFIX>script_args': AnyOfType(Function),
1318-
},
1316+
auto_makers={},
13191317
auto_made_record_attr_prefix=AnyOfType(str),
13201318
record_attr_to_output_key={
13211319
**STANDARD_RECORD_ATTR_TO_OUTPUT_KEY,
1322-
'<PREFIX>py_ver': 'py_ver',
1323-
'<PREFIX>script_args': 'script_args',
13241320
},
13251321
serializer=json.dumps,
13261322
),
@@ -5575,7 +5571,7 @@ def test_formatter_get_output_keys_required_in_defaults_or_auto_makers_snippet(
55755571
self,
55765572
snippet_finder,
55775573
):
5578-
snippet = snippet_finder.lookup(substring='This satisfies the requirement')
5574+
snippet = snippet_finder.lookup(substring='requirement is satisfied')
55795575
variables = {'StructuredLogsFormatter': StructuredLogsFormatter}
55805576

55815577
exec(snippet, variables)

0 commit comments

Comments
 (0)