Skip to content

Comments

fix(logging): emit log without stack trace when exception is in disable_stack_trace#4588

Open
skylarkoo7 wants to merge 4 commits intolitestar-org:mainfrom
skylarkoo7:fix-4510-disable-stack-trace-logging
Open

fix(logging): emit log without stack trace when exception is in disable_stack_trace#4588
skylarkoo7 wants to merge 4 commits intolitestar-org:mainfrom
skylarkoo7:fix-4510-disable-stack-trace-logging

Conversation

@skylarkoo7
Copy link

Summary

disable_stack_trace suppresses exception logging entirely instead of only suppressing the stack trace. When an exception's status code or class matches an entry in disable_stack_trace, the handle_exception_logging method short-circuits completely — no log line is emitted at all, not even a one-line error message.

The fix separates the "should we log?" decision from the "should we include the stack trace?" decision:

  • The handler is now always invoked when logging is enabled, regardless of disable_stack_trace
  • When the exception matches disable_stack_trace, the handler receives an empty traceback list ([]) instead of the formatted exception
  • When it doesn't match, the handler receives the full traceback as before

Changes

  • litestar/middleware/_internal/exceptions/middleware.py — split the handle_exception_logging conditional into a "should log" check and a separate "include stack trace" check; pass [] when stack trace is suppressed
  • litestar/logging/config.py — default exception logging handlers (both standard-lib and structlog) now check tb: use logger.exception() when traceback is present, logger.error() when it is empty
  • tests/unit/test_logging/test_logging_config.py — updated test_disable_stack_trace to assert the handler IS always called, and that tb is empty when stack trace is suppressed
  • tests/unit/test_logging/test_structlog_config.py — same update for test_structlog_disable_stack_trace

Test plan

  • All 10 parametrized cases in both test files updated to verify: handler is always called, tb is non-empty when stack trace is expected, tb is [] when stack trace is suppressed
  • Custom handlers that inspect the tb argument will see [] for suppressed exceptions and can decide their own behavior
  • Backward compatible: no change in behavior when disable_stack_trace is empty (the default)

Fixes #4510

…le_stack_trace

When an exception's status code or class matched an entry in
`disable_stack_trace`, the entire `handle_exception_logging` call was
short-circuited — neither the stack trace nor a one-line error log was
emitted.  The option's documented intent is to suppress the stack trace
while still logging that the exception occurred.

Separate the "should log" decision from the "include stack trace"
decision:

- When the exception matches `disable_stack_trace`, the handler is
  still invoked but receives an empty traceback list (`[]`).
- The default exception logging handlers now check whether `tb` is
  non-empty: `logger.exception()` (with traceback) when it is,
  `logger.error()` (without traceback) when it is not.

Updated both standard-lib and structlog handler factories, plus their
corresponding tests.

Fixes litestar-org#4510
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.85%. Comparing base (f16b520) to head (725ef88).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4588   +/-   ##
=======================================
  Coverage   97.85%   97.85%           
=======================================
  Files         297      297           
  Lines       15339    15347    +8     
  Branches     1721     1723    +2     
=======================================
+ Hits        15010    15018    +8     
  Misses        188      188           
  Partials      141      141           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Extract exception_logging_handler into a local variable before the
  compound should_log condition so mypy/pyright can narrow the type
  from Optional to non-None inside the if-block.
- Add test_default_handler_uses_error_when_stack_trace_suppressed for
  both standard logging and structlog to exercise the logger.error
  branch in _default_exception_logging_handler_factory.
- Restructure handle_exception_logging so `handler is not None` is an
  inline condition in the if-statement, allowing mypy/pyright to narrow
  the type correctly (stored bool variables don't propagate narrowing).
- Replace integration-style default handler tests with direct unit tests
  of _default_exception_logging_handler_factory using a MagicMock logger.
  This avoids the AttributeError from picologging.Logger whose attributes
  are read-only and cannot be patched.
- Fix import ordering in test_structlog_config.py (ruff I001).
The handler factory returns a callable expecting Scope (Union[HTTPScope,
WebSocketScope]).  Passing a plain dict literal triggers arg-type errors.
Using Any silences the checkers while keeping the test readable.
@cofin
Copy link
Member

cofin commented Feb 18, 2026

#4593 is probably a better place for this update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

disable_stack_trace suppresses exception logging entirely instead of only stack traces

2 participants