3535import org .apache .logging .log4j .core .config .plugins .PluginElement ;
3636import org .apache .logging .log4j .core .config .plugins .PluginFactory ;
3737import org .apache .logging .log4j .core .impl .Log4jLogEvent ;
38+ import org .apache .logging .log4j .message .SimpleMessage ;
3839
3940import software .amazon .lambda .powertools .common .internal .LambdaHandlerProcessor ;
4041
@@ -51,7 +52,7 @@ public class BufferingAppender extends AbstractAppender {
5152 private final int maxBytes ;
5253 private final boolean flushOnErrorLog ;
5354 private final Map <String , Deque <LogEvent >> bufferCache = new ConcurrentHashMap <>();
54- private final ThreadLocal <Boolean > bufferOverflowWarned = new ThreadLocal <>();
55+ private final ThreadLocal <Boolean > bufferOverflowTriggered = new ThreadLocal <>();
5556
5657 protected BufferingAppender (String name , Filter filter , Layout <? extends Serializable > layout ,
5758 AppenderRef [] appenderRefs , Configuration configuration , Level bufferAtVerbosity , int maxBytes ,
@@ -107,8 +108,8 @@ private void bufferEvent(String traceId, LogEvent event) {
107108 // Check if single event is larger than buffer - discard if so
108109 int eventSize = immutableEvent .getMessage ().getFormattedMessage ().length ();
109110 if (eventSize > maxBytes ) {
110- if (Boolean .TRUE != bufferOverflowWarned .get ()) {
111- bufferOverflowWarned .set (true );
111+ if (Boolean .TRUE != bufferOverflowTriggered .get ()) {
112+ bufferOverflowTriggered .set (true );
112113 }
113114 return ;
114115 }
@@ -118,8 +119,8 @@ private void bufferEvent(String traceId, LogEvent event) {
118119 // Simple size check - remove oldest if over limit
119120 Deque <LogEvent > buffer = bufferCache .get (traceId );
120121 while (getBufferSize (buffer ) > maxBytes && !buffer .isEmpty ()) {
121- if (Boolean .TRUE != bufferOverflowWarned .get ()) {
122- bufferOverflowWarned .set (true );
122+ if (Boolean .TRUE != bufferOverflowTriggered .get ()) {
123+ bufferOverflowTriggered .set (true );
123124 }
124125 buffer .removeFirst ();
125126 }
@@ -140,13 +141,22 @@ public void flushBuffer() {
140141 }
141142
142143 private void flushBuffer (String traceId ) {
144+ // Emit buffer overflow warning if it occurred
145+ if (Boolean .TRUE == bufferOverflowTriggered .get ()) {
146+ // Create LogEvent directly since Log4j status logger may not reach target appenders
147+ LogEvent warningEvent = Log4jLogEvent .newBuilder ()
148+ .setLoggerName ("BufferingAppender" )
149+ .setLevel (Level .WARN )
150+ .setMessage (new SimpleMessage (
151+ "Some logs are not displayed because they were evicted from the buffer. Increase buffer size to store more logs in the buffer." ))
152+ .setTimeMillis (System .currentTimeMillis ())
153+ .build ();
154+ callAppenders (warningEvent );
155+ bufferOverflowTriggered .remove ();
156+ }
157+
143158 Deque <LogEvent > buffer = bufferCache .remove (traceId );
144159 if (buffer != null ) {
145- // Emit buffer overflow warning if it occurred
146- if (Boolean .TRUE == bufferOverflowWarned .get ()) {
147- LOGGER .warn ("Buffer size exceeded for trace ID: {}. Some log events were discarded." , traceId );
148- bufferOverflowWarned .remove ();
149- }
150160 buffer .forEach (this ::callAppenders );
151161 }
152162 }
0 commit comments