Skip to content

Log stack traces only in debug mode #12989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 14, 2025
Merged

Conversation

sannya-singal
Copy link
Contributor

@sannya-singal sannya-singal commented Aug 11, 2025

Motivation

As a part of the initiative for improving Localstack error messages and stack traces, this PR aims to ensure that stack traces are logged when debug mode is enabled. Currently, in some use cases stack traces are logged without checking if debug mode is enabled or not. This causes excessive log noise even when DEBUG=0.

Changes

This PR cleans up logging across different use cases to ensure that stack traces are only logged when debug mode is enabled.

@sannya-singal sannya-singal self-assigned this Aug 11, 2025
@sannya-singal sannya-singal added the semver: patch Non-breaking changes which can be included in patch releases label Aug 11, 2025
@sannya-singal sannya-singal added this to the 4.8 milestone Aug 11, 2025
Copy link

github-actions bot commented Aug 11, 2025

S3 Image Test Results (AMD64 / ARM64)

    2 files    2 suites   8m 22s ⏱️
  515 tests 465 ✅  50 💤 0 ❌
1 030 runs  930 ✅ 100 💤 0 ❌

Results for commit ea8c0eb.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Aug 11, 2025

Test Results - Preflight, Unit

22 107 tests  ±0   20 372 ✅ ±0   6m 16s ⏱️ -18s
     1 suites ±0    1 735 💤 ±0 
     1 files   ±0        0 ❌ ±0 

Results for commit ea8c0eb. ± Comparison against base commit 5a920cb.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Aug 11, 2025

Test Results (amd64) - Acceptance

7 tests  ±0   5 ✅ ±0   3m 7s ⏱️ -7s
1 suites ±0   2 💤 ±0 
1 files   ±0   0 ❌ ±0 

Results for commit ea8c0eb. ± Comparison against base commit 5a920cb.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Aug 11, 2025

Test Results (amd64) - Integration, Bootstrap

    5 files  ±0      5 suites  ±0   2h 21m 30s ⏱️ -22s
4 987 tests ±0  4 395 ✅ ±0  592 💤 ±0  0 ❌ ±0 
4 993 runs  ±0  4 395 ✅ ±0  598 💤 ±0  0 ❌ ±0 

Results for commit ea8c0eb. ± Comparison against base commit 5a920cb.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Aug 11, 2025

LocalStack Community integration with Pro

    2 files  ±0      2 suites  ±0   1h 42m 8s ⏱️ -46s
4 628 tests ±0  4 188 ✅ ±0  440 💤 ±0  0 ❌ ±0 
4 630 runs  ±0  4 188 ✅ ±0  442 💤 ±0  0 ❌ ±0 

Results for commit ea8c0eb. ± Comparison against base commit 5a920cb.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@simonrw simonrw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for CFn

@@ -1479,10 +1479,11 @@ def delete_stack(self):
# correct order yet.
continue
case OperationStatus.FAILED:
LOG.exception(
LOG.error(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: it might be nice to extract a helper method to our LOG class that we can use so we don't forget to set this behaviour in the future. E.g.

from localstack.logging import get_logger

LOG = get_logger(__name__)

LOG.error("message")

which in turn is implemented like

class LocalStackLogger(logging.Logger):
    def _log(self, level, *args, **kwargs):
        kwargs.pop("exc_info", None)
        super()._log(level, *args, **kwargs, exc_info=self.isEnabledFor(logging.DEBUG))

    def exception(self, *args, **kwargs):
        """
        Protect against using this method which logs the exception by default
        """
        return self.error(*args, **kwargs)

WDYT? Or we could write a linting rule that operates over our AST and catches usages of the LOG.error(...) without handling the exc_info field properly, or protects us against usages of LOG.exception?

Copy link
Contributor

@bentsku bentsku Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely agree about the linting rule to protect about the exception usage, this is the main issue we have currently.

For the logger above, I'm not sure, or we'd instead need to override exception with a conditional exc_info instead of the default keyword exc_info=True that it has currently, so we'd be protected without changing behavior for the rest.
Also, not sure what happens when adding exc_info outside of an exception handler (except), but not anything good I suppose.

I think we'd still need to be deliberate about when we want to log stack traces or not, and always printing stack traces might be too much, it might be an exception we're actually expecting so we would not need it.

edit: it seems Ruff does not support custom linting rules though: https://docs.astral.sh/ruff/faq/#how-does-ruffs-linter-compare-to-flake8, so we might need to look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, the lint rule for exception seems like a nice way here, but as Ben mentioned Ruff seems not to support custom linting rules.
On the LocalStackLogger idea, I see the point there but adding exc_info outside of an except block might not be the best option here.

@sannya-singal sannya-singal force-pushed the stack-traces-debug-only branch from 9f0d066 to c487fbf Compare August 13, 2025 04:10
@sannya-singal sannya-singal marked this pull request as ready for review August 13, 2025 04:48
@sannya-singal sannya-singal requested a review from bentsku August 13, 2025 04:48
@dfangl dfangl removed their request for review August 13, 2025 09:54
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, nice work! 🚀

This is quite a lot of logging statements that got updated! This is good to go, I only have 2 small nits, but this can go as is. Kudos for churning through all of them!

The pipeline failure are fixed with #13004, so you can rebase and we should be good to go 👍

Comment on lines +72 to +75
if LOG.isEnabledFor(logging.DEBUG):
LOG.exception("Error executing scheduled alarm", exc_info=e)
else:
LOG.error("Error executing scheduled alarm")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think the previous implementation was wrong, e is an Exception here and exc_info takes a boolean.

This can be replaced by the regular one we've been using, no need for the if check.

LOG.error("Error executing scheduled alarm", exc_info=LOG.isEnabledFor(logging.DEBUG))

It's not blocking, but it sends the wrong message that the Exception object needs to be based to exc_info

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per my understanding from the official docs which mention that exc_info can accept exception instances, here, I thought we were doing that intentionally. But if it seems incorrect, I am happy to update this to the simpler version 🙂

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good catch! Let's leave it like that then 😄 this is good!

@@ -166,7 +166,7 @@ def handle_request(request: Request, region: str) -> Response:
op = service.operation_model(service.operation_names[0])
return serializer.serialize_error_to_response(e, op, request.headers, request_id)
except Exception as e:
LOG.exception("exception")
LOG.error("exception", exc_info=LOG.isEnabledFor(logging.DEBUG))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: a bit out of scope of this PR so no need to address this, but this logging message is not going to be very useful is debug is not activated, it will just log "exception". It seems we're properly handling the exception anyway and returning a proper serialized error, so it could maybe be a debug logging statement somehow or contain more info, like LOG.error("Internal Server exception while executing SQS Query operation: '%s'", e, exc_info=LOG.isEnabledFor(logging.DEBUG)) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed 💯 Adding more info would definitely make it more useful 👍 As you mentioned, I will keep it as is for this PR since it is a bit out of scope for this one, but I will create a follow up PR for this 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow PR: #13007

@sannya-singal sannya-singal force-pushed the stack-traces-debug-only branch from c487fbf to 4aea6c0 Compare August 14, 2025 05:34
@sannya-singal sannya-singal merged commit cfbfe5a into main Aug 14, 2025
46 checks passed
@sannya-singal sannya-singal deleted the stack-traces-debug-only branch August 14, 2025 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver: patch Non-breaking changes which can be included in patch releases
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants