Skip to content

Commit e97b839

Browse files
authored
native loggers: add is_enabled_for & get_effective_level (hynek#689)
* native loggers: add is_enabled_for & get_effective_level fixes hynek#685 * add PR#
1 parent 8688c32 commit e97b839

File tree

5 files changed

+45
-9
lines changed

5 files changed

+45
-9
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/
2222
With it, you do not need to add `structlog.stdlib.PositionalArgumentsFormatter` processor to format positional arguments from *structlog* loggers.
2323
[#668](https://github.com/hynek/structlog/pull/668)
2424

25+
- Native loggers now have `is_enabled_for()` and `get_effective_level()` methods that mirror the behavior of the standard library's `logging.Logger.isEnabledFor()` and `logging.Logger.getEffectiveLevel()`.
26+
[#689](https://github.com/hynek/structlog/pull/689)
27+
2528

2629
## Changed
2730

src/structlog/_native.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ async def alog(
219219
meths["msg"] = meths["info"]
220220
meths["amsg"] = meths["ainfo"]
221221

222+
# Introspection
223+
meths["is_enabled_for"] = lambda self, level: level >= min_level
224+
meths["get_effective_level"] = lambda self: min_level
225+
222226
return type(
223227
f"BoundLoggerFilteringAt{LEVEL_TO_NAME.get(min_level, 'Notset').capitalize()}",
224228
(BoundLoggerBase,),

src/structlog/typing.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,20 @@ def new(self, **new_values: Any) -> FilteringBoundLogger:
190190
.. versionadded:: 22.1.0
191191
"""
192192

193+
def is_enabled_for(self, level: int) -> bool:
194+
"""
195+
Check whether the logger is enabled for *level*.
196+
197+
.. versionadded:: 25.1.0
198+
"""
199+
200+
def get_effective_level(self) -> int:
201+
"""
202+
Return the effective level of the logger.
203+
204+
.. versionadded:: 25.1.0
205+
"""
206+
193207
def debug(self, event: str, *args: Any, **kw: Any) -> Any:
194208
"""
195209
Log ``event % args`` with **kw** at **debug** level.
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,23 @@ def _bl(cl):
2323
return make_filtering_bound_logger(logging.INFO)(cl, [], {})
2424

2525

26-
class TestFilteringLogger:
26+
class TestNativeFilteringLogger:
27+
def test_is_enabled_for(self, bl):
28+
"""
29+
is_enabled_for returns True if the log level is enabled.
30+
"""
31+
assert bl.is_enabled_for(20)
32+
assert bl.is_enabled_for(logging.INFO)
33+
34+
assert not bl.is_enabled_for(19)
35+
assert not bl.is_enabled_for(logging.DEBUG)
36+
37+
def test_get_effective_level(self, bl):
38+
"""
39+
get_effective_level returns the log level.
40+
"""
41+
assert 20 == logging.INFO == bl.get_effective_level()
42+
2743
def test_exact_level(self, bl, cl):
2844
"""
2945
if log level is exactly the min_level, log.

tests/typing/api.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,10 @@ def bytes_dumps(
4444
processors=[structlog.processors.JSONRenderer(serializer=bytes_dumps)]
4545
)
4646

47-
structlog.configure(
48-
processors=[
49-
structlog.stdlib.render_to_log_args_and_kwargs,
50-
],
51-
logger_factory=structlog.stdlib.LoggerFactory(),
52-
wrapper_class=structlog.stdlib.BoundLogger,
53-
cache_logger_on_first_use=True,
54-
)
5547

5648
structlog.configure(
5749
processors=[
50+
structlog.stdlib.render_to_log_args_and_kwargs,
5851
structlog.stdlib.filter_by_level,
5952
structlog.stdlib.add_logger_name,
6053
structlog.stdlib.add_log_level,
@@ -359,3 +352,9 @@ def typecheck_bound_logger_return() -> None:
359352

360353
fbl: FilteringBoundLogger = structlog.get_logger()
361354
fbl.info("Hello %s! The answer is %d.", "World", 42, x=1)
355+
356+
357+
# Introspection
358+
level: int = fbl.get_effective_level()
359+
is_active: bool = fbl.is_enabled_for(logging.INFO)
360+
is_active = fbl.is_enabled_for(20)

0 commit comments

Comments
 (0)