diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java
index dca76120..3e5ca93d 100644
--- a/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java
+++ b/src/main/java/com/splunk/logging/HttpEventCollectorLog4jAppender.java
@@ -157,6 +157,7 @@ public static HttpEventCollectorLog4jAppender createAppender(
@PluginAttribute(value = "call_timeout", defaultLong = HttpEventCollectorSender.TimeoutSettings.DEFAULT_CALL_TIMEOUT) final long callTimeout,
@PluginAttribute(value = "read_timeout", defaultLong = HttpEventCollectorSender.TimeoutSettings.DEFAULT_READ_TIMEOUT) final long readTimeout,
@PluginAttribute(value = "write_timeout", defaultLong = HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT) final long writeTimeout,
+ @PluginAttribute(value = "termination_timeout", defaultLong = HttpEventCollectorSender.TimeoutSettings.DEFAULT_TERMINATION_TIMEOUT) final long terminationTimeout,
@PluginElement("Layout") Layout extends Serializable> layout,
@PluginElement("Filter") final Filter filter
)
@@ -219,7 +220,7 @@ public static HttpEventCollectorLog4jAppender createAppender(
disableCertificateValidation,
eventBodySerializer,
eventHeaderSerializer,
- new HttpEventCollectorSender.TimeoutSettings(connectTimeout, callTimeout, readTimeout, writeTimeout)
+ new HttpEventCollectorSender.TimeoutSettings(connectTimeout, callTimeout, readTimeout, writeTimeout, terminationTimeout)
);
}
diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java
index fe786299..45d62f5b 100644
--- a/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java
+++ b/src/main/java/com/splunk/logging/HttpEventCollectorLogbackAppender.java
@@ -383,6 +383,14 @@ public long getWriteTimeout(long milliseconds) {
return this.timeoutSettings.writeTimeout = milliseconds;
}
+ public void setTerminationTimeout(long milliseconds) {
+ this.timeoutSettings.terminationTimeout = milliseconds;
+ }
+
+ public long getTerminationTimeout(long milliseconds) {
+ return this.timeoutSettings.terminationTimeout = milliseconds;
+ }
+
private static long parseLong(String string, int defaultValue) {
try {
return Long.parseLong(string);
diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java
index 34826ded..88821771 100644
--- a/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java
+++ b/src/main/java/com/splunk/logging/HttpEventCollectorLoggingHandler.java
@@ -114,6 +114,7 @@ public final class HttpEventCollectorLoggingHandler extends Handler {
private final String CallTimeoutConfTag = "call_timeout";
private final String ReadTimeoutConfTag = "read_timeout";
private final String WriteTimeoutConfTag = "write_timeout";
+ private final String TerminationTimeoutConfTag = "termination_timeout";
/** HttpEventCollectorLoggingHandler c-or */
public HttpEventCollectorLoggingHandler() {
@@ -165,7 +166,8 @@ public HttpEventCollectorLoggingHandler() {
getConfigurationNumericProperty(ConnectTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CONNECT_TIMEOUT),
getConfigurationNumericProperty(CallTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_CALL_TIMEOUT),
getConfigurationNumericProperty(ReadTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_READ_TIMEOUT),
- getConfigurationNumericProperty(WriteTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT)
+ getConfigurationNumericProperty(WriteTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_WRITE_TIMEOUT),
+ getConfigurationNumericProperty(TerminationTimeoutConfTag, HttpEventCollectorSender.TimeoutSettings.DEFAULT_TERMINATION_TIMEOUT)
);
if ("raw".equalsIgnoreCase(type)) {
diff --git a/src/main/java/com/splunk/logging/HttpEventCollectorSender.java b/src/main/java/com/splunk/logging/HttpEventCollectorSender.java
index 36fbcbd9..e65202d1 100644
--- a/src/main/java/com/splunk/logging/HttpEventCollectorSender.java
+++ b/src/main/java/com/splunk/logging/HttpEventCollectorSender.java
@@ -29,6 +29,7 @@
import java.io.Serializable;
import java.security.cert.CertificateException;
import java.util.*;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -262,8 +263,36 @@ public static void putIfPresent(JsonObject collection, String tag, Object value)
private void stopHttpClient() {
if (httpClient != null) {
- httpClient.dispatcher().executorService().shutdown();
+ Dispatcher dispatcher = httpClient.dispatcher();
httpClient = null;
+
+ if (timeoutSettings.terminationTimeout > 0) {
+ // wait for queued messages in the dispatcher to be promoted to the executor service
+ long start = System.currentTimeMillis();
+ while (dispatcher.queuedCallsCount() > 0 && start + timeoutSettings.terminationTimeout > System.currentTimeMillis()) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(10);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+
+ // initialize the shutdown of the executor service
+ dispatcher.executorService().shutdown();
+
+ // wait for the messages in the dispatcher's executor service to be sent out
+ long awaitTerminationTimeout = timeoutSettings.terminationTimeout - (System.currentTimeMillis() - start);
+ if (awaitTerminationTimeout > 0) {
+ try {
+ dispatcher.executorService().awaitTermination(awaitTerminationTimeout, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ } else {
+ dispatcher.executorService().shutdown();
+ }
}
}
@@ -392,19 +421,22 @@ public static class TimeoutSettings {
public static final long DEFAULT_WRITE_TIMEOUT = 0; // 0 means no timeout
public static final long DEFAULT_CALL_TIMEOUT = 0;
public static final long DEFAULT_READ_TIMEOUT = 0;
+ public static final long DEFAULT_TERMINATION_TIMEOUT = 0;
public long connectTimeout = DEFAULT_CONNECT_TIMEOUT;
public long callTimeout = DEFAULT_CALL_TIMEOUT;
public long readTimeout = DEFAULT_READ_TIMEOUT;
public long writeTimeout = DEFAULT_WRITE_TIMEOUT;
+ public long terminationTimeout = DEFAULT_TERMINATION_TIMEOUT;
public TimeoutSettings() {}
- public TimeoutSettings(long connectTimeout, long callTimeout, long readTimeout, long writeTimeout) {
+ public TimeoutSettings(long connectTimeout, long callTimeout, long readTimeout, long writeTimeout, long terminationTimeout) {
this.connectTimeout = connectTimeout;
this.callTimeout = callTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
+ this.terminationTimeout = terminationTimeout;
}
}
}
diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml
index 18fb5b87..6ca9f362 100644
--- a/src/test/resources/log4j2.xml
+++ b/src/test/resources/log4j2.xml
@@ -45,6 +45,7 @@ under the License.
batch_size_count="0"
batch_interval="0"
connect_timeout="5000"
+ termination_timeout="1000"
disableCertificateValidation="true">
diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml
index 960372a5..00637f13 100644
--- a/src/test/resources/logback.xml
+++ b/src/test/resources/logback.xml
@@ -60,6 +60,7 @@ under the License.
text
HttpEventCollectorUnitTestMiddleware
5000
+ 2000
%msg