### Eclipse Workspace Patch 1.0 #P log4j2 Index: core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java (revision 1444667) +++ core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java (working copy) @@ -49,6 +49,7 @@ private final ThreadContext.ContextStack ndc; private String threadName = null; private StackTraceElement location; + private boolean endOfBatch = false; /** * Constructor. @@ -249,6 +250,16 @@ return location; } + @Override + public boolean isEndOfBatch() { + return endOfBatch; + } + + @Override + public void setEndOfBatch(boolean endOfBatch) { + this.endOfBatch = endOfBatch; + } + /** * Creates a LogEventProxy that can be serialized. * @return a LogEventProxy. @@ -267,8 +278,12 @@ } if (event instanceof LogEventProxy) { final LogEventProxy proxy = (LogEventProxy) event; - return new Log4jLogEvent(proxy.name, proxy.marker, proxy.fqcnOfLogger, proxy.level, proxy.message, - proxy.throwable, proxy.mdc, proxy.ndc, proxy.threadName, proxy.location, proxy.timestamp); + Log4jLogEvent result = new Log4jLogEvent(proxy.name, proxy.marker, + proxy.fqcnOfLogger, proxy.level, proxy.message, + proxy.throwable, proxy.mdc, proxy.ndc, proxy.threadName, + proxy.location, proxy.timestamp); + result.setEndOfBatch(proxy.isEndOfBatch); + return result; } throw new IllegalArgumentException("Event is not a serialized LogEvent: " + event.toString()); } @@ -304,6 +319,7 @@ private final ThreadContext.ContextStack ndc; private final String threadName; private final StackTraceElement location; + private final boolean isEndOfBatch; public LogEventProxy(final Log4jLogEvent event) { this.fqcnOfLogger = event.fqcnOfLogger; @@ -317,6 +333,7 @@ this.ndc = event.ndc; this.location = event.getSource(); this.threadName = event.getThreadName(); + this.isEndOfBatch = event.endOfBatch; } /** @@ -324,10 +341,11 @@ * @return Log4jLogEvent. */ protected Object readResolve() { - return new Log4jLogEvent(name, marker, fqcnOfLogger, level, message, throwable, mdc, ndc, threadName, - location, timestamp); + Log4jLogEvent result = new Log4jLogEvent(name, marker, fqcnOfLogger, + level, message, throwable, mdc, ndc, threadName, location, + timestamp); + result.setEndOfBatch(isEndOfBatch); + return result; } - } - } Index: core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java (revision 1444667) +++ core/src/main/java/org/apache/logging/log4j/core/appender/AsynchAppender.java (working copy) @@ -206,6 +206,9 @@ continue; } final Log4jLogEvent event = Log4jLogEvent.deserialize(s); + if (queue.isEmpty()) { + event.setEndOfBatch(true); + } boolean success = false; for (final AppenderControl control : appenders) { try { Index: core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java (revision 1442969) +++ core/src/test/java/org/apache/logging/log4j/core/lookup/DateLookupTest.java (working copy) @@ -94,5 +94,12 @@ public String getFQCN() { return null; } + + public boolean isEndOfBatch() { + return false; + } + + public void setEndOfBatch(boolean endOfBatch) { + } } } Index: core/src/main/java/org/apache/logging/log4j/core/LogEvent.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/LogEvent.java (revision 1444667) +++ core/src/main/java/org/apache/logging/log4j/core/LogEvent.java (working copy) @@ -30,78 +30,109 @@ */ public interface LogEvent extends Serializable { - /** + /** * Get level. + * * @return level. */ Level getLevel(); /** * Get logger name. + * * @return logger name, may be null. */ String getLoggerName(); /** * Get source of logging request. + * * @return source of logging request, may be null. */ StackTraceElement getSource(); /** * Get the message associated with the event. - * + * * @return message. */ Message getMessage(); /** * Get the Marker associated with the event. + * * @return Marker */ Marker getMarker(); /** * Get thread name. + * * @return thread name, may be null. - * @doubt guess this could go into a thread context object too. - * (RG) Why? + * @doubt guess this could go into a thread context object too. (RG) Why? */ String getThreadName(); - /** * Get event time in milliseconds since 1970. + * * @return milliseconds since 1970. */ long getMillis(); - /** * Get throwable associated with logging request. + * * @return throwable, may be null. */ Throwable getThrown(); - /** * Get the MDC data. - * + * * @return A copy of the Mapped Diagnostic Context or null. */ Map getContextMap(); /** * Get the NDC data. - * + * * @return A copy of the Nested Diagnostic Context or null; */ ThreadContext.ContextStack getContextStack(); /** * Returns the fully qualified class name of the caller of the logging api. + * * @return The fully qualified class name of the caller. */ String getFQCN(); + /** + * Returns whether this event is the last event in a batch of queued events, + * {@code false} by default. Loggers with queues should set this to + * {@code true} for the last event in the queue. + *

+ * Buffered appenders may make use of this information by flushing their + * buffer only after writing the last event to the buffer, producing the + * same result as "immediateFlush", with less I/O overhead. + * + * @return {@code true} if this event is the last event in a batch, + * {@code false} otherwise + */ + boolean isEndOfBatch(); + + /** + * Sets whether this event is the last event in a batch of queued events. + * Loggers with queues should set this to {@code true} for the last event in + * the queue. + *

+ * Buffered appenders may make use of this information by flushing their + * buffer only after writing the last event to the buffer, producing the + * same result as "immediateFlush", with less I/O overhead. + * + * @param endOfBatch {@code true} if this event is the last event in a + * batch, {@code false} otherwise + */ + void setEndOfBatch(boolean endOfBatch); } Index: core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java (revision 1444667) +++ core/src/main/java/org/apache/logging/log4j/core/appender/AbstractOutputStreamAppender.java (working copy) @@ -113,7 +113,7 @@ final byte[] bytes = getLayout().toByteArray(event); if (bytes.length > 0) { manager.write(bytes); - if (this.immediateFlush) { + if (this.immediateFlush || event.isEndOfBatch()) { manager.flush(); } }