Skip to content

Commit

Permalink
Add additional_ignores to StackInfoRenderer
Browse files Browse the repository at this point in the history
Fixes #396
  • Loading branch information
hynek committed Jan 29, 2022
1 parent a77d938 commit 60792bc
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Changes:
- Overloaded the ``bind``, ``unbind``, ``try_unbind`` and ``new`` methods in the ``FilteringBoundLogger`` `Protocol <https://docs.python.org/3/library/typing.html#typing.Protocol>`_.
This makes it easier to use objects of type ``FilteringBoundLogger`` in a typed context.
`#392 <https://github.com/hynek/structlog/pull/392>`_
- ``structlog.processors.StackInfoRenderer`` now has an *additional_ignores* parameter that allows you to filter out your own logging layer.
`#396 <https://github.com/hynek/structlog/issues/396>`_


----
Expand Down
20 changes: 16 additions & 4 deletions src/structlog/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,20 +526,32 @@ class StackInfoRenderer:
Add stack information with key ``stack`` if ``stack_info`` is `True`.
Useful when you want to attach a stack dump to a log entry without
involving an exception.
involving an exception and works analogously to the *stack_info* argument
of the Python standard library logging.
It works analogously to the *stack_info* argument of the Python 3 standard
library logging.
:param additional_ignores: By default, stack frames coming from
``structlog`` are ignored. With this argument you can add additional
names that are ignored, before the stack starts being rendered. They
are matched using ``startswith()``, so they don't have to match
exactly. The names are used to find the first relevant name, therefore
once a frame is found that doesn't start with ``structlog`` or one of
*additional_ignores*, **no filtering** is applied to subsequent frames.
.. versionadded:: 0.4.0
.. versionadded:: 22.1.0 *additional_ignores*
"""

__slots__ = ["_additional_ignores"]

def __init__(self, additional_ignores: Optional[List[str]] = None) -> None:
self._additional_ignores = additional_ignores

def __call__(
self, logger: WrappedLogger, name: str, event_dict: EventDict
) -> EventDict:
if event_dict.pop("stack_info", None):
event_dict["stack"] = _format_stack(
_find_first_app_frame_and_name()[0]
_find_first_app_frame_and_name(self._additional_ignores)[0]
)

return event_dict
Expand Down
4 changes: 1 addition & 3 deletions tests/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ def test_proxies_anything(self):
assert "log", "foo" == b.log("foo")
assert "gol", "bar" == b.gol("bar")

@pytest.mark.parametrize("proto", range(pickle.HIGHEST_PROTOCOL + 1))
@pytest.mark.parametrize("proto", range(3, pickle.HIGHEST_PROTOCOL + 1))
def test_pickle(self, proto):
"""
Can be pickled and unpickled.
Works only on Python 3: TypeError: can't pickle instancemethod objects
"""
b = BoundLogger(
ReturnLogger(),
Expand Down
12 changes: 12 additions & 0 deletions tests/test_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,18 @@ def test_renders_correct_stack(self, sir):

assert 'ed = sir(None, None, {"stack_info": True})' in ed["stack"]

def test_additional_ignores(self):
"""
Filtering of names works.
"""
sir = StackInfoRenderer(["tests.additional_frame"])

ed = additional_frame(
functools.partial(sir, None, None, {"stack_info": True})
)

assert "additional_frame.py" not in ed["stack"]


class TestFigureOutExcInfo:
@pytest.mark.parametrize("true_value", [True, 1, 1.1])
Expand Down

0 comments on commit 60792bc

Please sign in to comment.