Skip to content

Conversation

phipag
Copy link
Contributor

@phipag phipag commented Sep 1, 2025

Summary

Docs preview: https://dealn7fl31ram.cloudfront.net/core/logging/#buffering-logs

This PR introduces a log buffering feature to Powertools for AWS Lambda (Java). Log buffering is the mechanism of buffering lower level logs and only flush them (to STDOUT on Lambda) in case of error or manually if needed. It is a good way to reduce the noise caused by e.g. DEBUG logs and can be seen as a more elaborate way of "log sampling".

While the other Powertools runtimes (Python, TypeScript, .NET) follow a programmatic approach to configuring log buffering, this PR uses the concept of "Appenders" in the corresponding logging backend (log4j2, logback). This means that log buffering is configured using the configuration files of the respective logging framework which is compatible with the way how structured JSON logging is already implemented. This also means that log buffering can be used independent of the @Logging annotation (except for automatic flushing on exceptions) and it is also compatible with any other Appender. The idea is to wrap an arbitrary existing Appender (e.g. a STDOUT JSON structured appender) with the BufferingAppender which will enable log buffering with zero code changes. Here is an example for log4j2:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="JsonAppender" target="SYSTEM_OUT">
            <JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
        </Console>
        <!-- New BufferingAppender wrapping existing JsonAppender emitting Lambda structured JSON logs -->
        <BufferingAppender name="BufferedAppender" bufferAtVerbosity="DEBUG" maxBytes="20480">
            <AppenderRef ref="JsonAppender" />
        </BufferingAppender>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <!-- Reference the BufferedAppender wrapping the JsonAppender instead of the JsonAppender directly -->
            <AppenderRef ref="BufferedAppender" />
        </Root>
    </Loggers>
</Configuration>

Note: This XML based configuration supersedes the original design proposal of @BufferingConfig made in the feature request issue (see below).

Changes

  • Implement log buffering feature
  • Extend E2E tests to test for both log4j2 and logback implementations (we only had log4j2 before)
  • Update examples to use log buffering feature
  • Add section in documentation about log buffering
  • Make buffering compatible with GraalVM

Issue number: #2095


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@phipag phipag self-assigned this Sep 1, 2025
@phipag phipag added feature-request New feature or request feature-parity Feature parity with python version logger labels Sep 1, 2025
phipag and others added 2 commits September 3, 2025 15:49
Co-authored-by: Stefano Vozza <[email protected]>
Co-authored-by: Stefano Vozza <[email protected]>
Copy link

sonarqubecloud bot commented Sep 3, 2025

@dreamorosi
Copy link
Contributor

Hi @svozza, did you by chance also review the implementation or just the docs?

@svozza
Copy link
Contributor

svozza commented Sep 4, 2025

Yes, it's a big diff so I only really focused on the implementation's Java classes. The only thing I noticed was that logback/BufferingAppender.java and log4j/BufferingAppender.java seem to share quite a bit of common logic but I decided it probably isn't worth try to extract it.

@dreamorosi
Copy link
Contributor

@phipag comments on @svozza's feedback above?

If you think it's not necessary to extract I'm ok to merge as is.

@phipag
Copy link
Contributor Author

phipag commented Sep 4, 2025

Thanks @svozza and @dreamorosi for the feedback. It is a good point and I thought about this as well. Some of the code flow is shared but there are notable differences in the typing and behavior of the log events / Appenders in these frameworks.

The main candidate for abstraction would be the append() method. However, you can see that log4j2 requires to create a immutable copy of the log event first while logback doesn't. Also the log level comparison for the buffering decision is different due to the Level type being different.

Another argument I fought in my mind was whether the LambdaHandlerProcessor.getXrayTraceId() calls should be abstracted. I decided against this as well because this logic already comes from the powertools-common module. If we change the way how individual requests are identified in a Lambda execution we will change it in powertools-common anyway so that it propagates to all consumers of this logic.

Historically, this is also the reason why the JSON structured logging was implemented independently for both log4j2 and logback. The tradeoff between abstraction to remove code redundancy and flexibility in embedding the logic in the framework-specific plugin system is not big enough here IMO.

Copy link
Contributor

@dreamorosi dreamorosi left a comment

Choose a reason for hiding this comment

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

Thanks for the super quick turnaround on this 🚀

@phipag
Copy link
Contributor Author

phipag commented Sep 4, 2025

Thanks folks for your feedback. Let's bring this feature live in the next release 🚀 💚

@phipag phipag merged commit 53b29bd into main Sep 4, 2025
15 checks passed
@phipag phipag deleted the phipag/issue2095 branch September 4, 2025 13:50
@phipag phipag linked an issue Sep 4, 2025 that may be closed by this pull request
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-parity Feature parity with python version feature-request New feature or request logger size/XXL
Projects
Status: Coming soon
Development

Successfully merging this pull request may close these issues.

Feature request: Log buffering support for Logger utility
3 participants